gui: support creation of a route using FaceId

refs: #3997
Change-Id: If28b0cb335cabdf1f073f6a27bb27d1bd07e56f2
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 a8faa90..607b5c1 100644
--- a/app/src/main/java/net/named_data/nfd/FaceListFragment.java
+++ b/app/src/main/java/net/named_data/nfd/FaceListFragment.java
@@ -1,6 +1,6 @@
 /* -*- Mode:jde; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2015-2017 Regents of the University of California
+ * Copyright (c) 2015-2019 Regents of the University of California
  * <p/>
  * This file is part of NFD (Named Data Networking Forwarding Daemon) Android.
  * See AUTHORS.md for complete list of NFD Android authors and contributors.
@@ -21,7 +21,9 @@
 
 import android.annotation.SuppressLint;
 import android.app.Activity;
+import android.app.AlertDialog;
 import android.content.Context;
+import android.content.DialogInterface;
 import android.os.AsyncTask;
 import android.os.Bundle;
 import android.os.Handler;
@@ -30,14 +32,14 @@
 import android.support.v4.content.ContextCompat;
 import android.util.Pair;
 import android.util.SparseArray;
-import android.view.ActionMode;
+import android.view.ContextMenu;
 import android.view.LayoutInflater;
 import android.view.Menu;
 import android.view.MenuInflater;
 import android.view.MenuItem;
 import android.view.View;
 import android.view.ViewGroup;
-import android.widget.AbsListView;
+import android.widget.AdapterView;
 import android.widget.BaseAdapter;
 import android.widget.ListView;
 import android.widget.ProgressBar;
@@ -57,7 +59,9 @@
 import java.util.List;
 import java.util.Set;
 
-public class FaceListFragment extends ListFragment implements FaceCreateDialogFragment.OnFaceCreateRequested {
+public class FaceListFragment extends ListFragment implements
+    FaceCreateDialogFragment.OnFaceCreateRequested,
+    FaceListRouteCreateDialogFragment.OnFaceListRouteCreateRequestd {
 
   public static FaceListFragment
   newInstance() {
@@ -72,6 +76,66 @@
   }
 
   @Override
+  public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
+    super.onCreateContextMenu(menu, v, menuInfo);
+    MenuInflater inflater = getActivity().getMenuInflater();
+    inflater.inflate(R.menu.menu_face_list_floating, menu);
+  }
+
+  @Override
+  public boolean onContextItemSelected(MenuItem item) {
+    HashSet<Integer> m_facesToDelete = new HashSet<>();
+    AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
+    if (info.id < 256) {
+      return super.onContextItemSelected(item);
+    }
+
+    FaceStatus faceStatus = m_faceListAdapter.getItem(info.position - 1);
+    switch (item.getItemId()) {
+
+      case R.id.menu_item_add_route_face_item_floating:
+        G.Log("Requesting to add route using face: " + faceStatus.getRemoteUri());
+
+        FaceListRouteCreateDialogFragment dialog =
+            FaceListRouteCreateDialogFragment.newInstance((int) info.id);
+        dialog.setTargetFragment(FaceListFragment.this, 0);
+        dialog.show(getFragmentManager(), "FaceListRouteCreateFragment");
+        return true;
+
+      case R.id.menu_item_delete_face_item_floating:
+        G.Log("Requesting to delete face: " + faceStatus.getRemoteUri());
+
+        new AlertDialog.Builder(getContext())
+            .setIcon(android.R.drawable.ic_dialog_alert)
+            .setTitle(R.string.face_list_delete_face_dialog_title)
+            .setMessage(getString(R.string.face_list_delete_face_dialog_warning) + "\n" +
+                        faceStatus.getRemoteUri() + " ?")
+            .setPositiveButton(R.string.menu_item_delete_face_item, new DialogInterface.OnClickListener() {
+              @Override
+              public void onClick(DialogInterface dialogInterface, int i) {
+                m_facesToDelete.add((int) info.id);
+                m_faceDestroyAsyncTask = new FaceDestroyAsyncTask();
+                m_faceDestroyAsyncTask.execute(m_facesToDelete);
+              }
+            })
+            .setNegativeButton(android.R.string.cancel, null)
+            .show();
+        return true;
+
+      case R.id.menu_item_details_face_item_floating:
+        G.Log("Requesting to check details of face: " + faceStatus.getRemoteUri());
+
+        if (m_callbacks != null) {
+          m_callbacks.onFaceItemSelected(faceStatus);
+        }
+        return true;
+
+      default:
+        return super.onContextItemSelected(item);
+    }
+  }
+
+  @Override
   public void onViewCreated(View view, Bundle savedInstanceState)
   {
     super.onViewCreated(view, savedInstanceState);
@@ -88,59 +152,7 @@
 
     // Setup list view for deletion
     ListView listView = getListView();
-    listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
-    listView.setMultiChoiceModeListener(new AbsListView.MultiChoiceModeListener() {
-      @Override
-      public void
-      onItemCheckedStateChanged(ActionMode mode, int position, long id, boolean checked) {
-        if (checked && id < 256) {
-          getListView().setItemChecked(position, false);
-          return;
-        }
-        if (checked)
-          m_facesToDelete.add((int)id);
-        else
-          m_facesToDelete.remove((int)id);
-      }
-
-      @Override
-      public boolean
-      onCreateActionMode(ActionMode mode, Menu menu) {
-        MenuInflater menuInflater = mode.getMenuInflater();
-        menuInflater.inflate(R.menu.menu_face_list_multiple_modal_menu, menu);
-        return true;
-      }
-
-      @Override
-      public boolean
-      onPrepareActionMode(ActionMode mode, Menu menu) {
-        return false;
-      }
-
-      @Override
-      public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
-        switch (item.getItemId()) {
-          case R.id.menu_item_delete_face_item:
-            G.Log("Requesting to delete " + String.valueOf(m_facesToDelete));
-
-            // Delete selected faceIds
-            m_faceDestroyAsyncTask = new FaceDestroyAsyncTask();
-            m_faceDestroyAsyncTask.execute(m_facesToDelete);
-
-            m_facesToDelete = new HashSet<>();
-            mode.finish();
-            return true;
-          default:
-            return false;
-        }
-      }
-
-      @Override
-      public void onDestroyActionMode(ActionMode mode) {
-      }
-
-      private HashSet<Integer> m_facesToDelete = new HashSet<>();
-    });
+    registerForContextMenu(listView);
   }
 
   @Override
@@ -242,6 +254,12 @@
     m_faceCreateAsyncTask.execute();
   }
 
+  @Override
+  public void createRoute(Name prefix, int faceId, boolean isPermanent) {
+    m_routeCreateAsyncTask = new RouteCreateAsyncTask(prefix, faceId, "", isPermanent, false);
+    m_routeCreateAsyncTask.execute();
+  }
+
   /////////////////////////////////////////////////////////////////////////
 
   /**
@@ -555,6 +573,99 @@
     private String m_faceUri;
     private boolean m_isPermanent;
   }
+
+  private class RouteCreateAsyncTask extends AsyncTask<Void, Void, String> {
+    RouteCreateAsyncTask(Name prefix, int faceId, String faceUri, boolean isPermanent, boolean isFaceUri) {
+      m_prefix = prefix;
+      m_faceId = faceId;
+      m_faceUri = faceUri;
+      m_isPermanent = isPermanent;
+      m_isFaceUri = isFaceUri;
+    }
+
+    @Override
+    protected String
+    doInBackground(Void... params) {
+      NfdcHelper nfdcHelper = new NfdcHelper();
+      try {
+        if (m_isFaceUri) {
+          int faceId = nfdcHelper.faceCreate(m_faceUri);
+          nfdcHelper.ribRegisterPrefix(new Name(m_prefix), faceId, 10, true, false);
+          if (m_isPermanent) {
+            Context context = getActivity().getApplicationContext();
+            SharedPreferencesManager
+                .addPermanentRoute(
+                    context,
+                    m_prefix.toUri(),
+                    NfdcHelper.formatFaceUri(m_faceUri)
+                );
+          }
+        } else {
+          nfdcHelper.ribRegisterPrefix(new Name(m_prefix), m_faceId, 10, true, false);
+          if (m_isPermanent) {
+            String uri = null;
+            for (FaceStatus faceStatus : nfdcHelper.faceList()) {
+              if (faceStatus.getFaceId() == m_faceId) {
+                uri = faceStatus.getRemoteUri();
+                System.out.println(">>>>>>>>> " + uri);
+                break;
+              }
+            }
+            if (uri == null) {
+              throw new ManagementException("Face not found: " + uri);
+            }
+            Context context = getActivity().getApplicationContext();
+            SharedPreferencesManager
+                .addPermanentRoute(
+                    context,
+                    m_prefix.toUri(),
+                    NfdcHelper.formatFaceUri(uri)
+                );
+          }
+        }
+        nfdcHelper.shutdown();
+        return "OK";
+      } catch (FaceUri.CanonizeError|FaceUri.Error e) {
+        return "Error creating face (" + e.getMessage() + ")";
+      } catch (Exception e) {
+        return "Error communicating with NFD (" + e.getMessage() + ")";
+      } finally {
+        nfdcHelper.shutdown();
+      }
+    }
+
+    @Override
+    protected void
+    onPreExecute() {
+      // Display progress bar
+      m_reloadingListProgressBar.setVisibility(View.VISIBLE);
+    }
+
+    @Override
+    protected void
+    onPostExecute(String status) {
+      // Display progress bar
+      m_reloadingListProgressBar.setVisibility(View.VISIBLE);
+      Toast.makeText(getActivity(), status, Toast.LENGTH_LONG).show();
+
+      retrieveFaceList();
+    }
+
+    @Override
+    protected void
+    onCancelled() {
+      // Remove progress bar
+      m_reloadingListProgressBar.setVisibility(View.GONE);
+    }
+
+    ///////////////////////////////////////////////////////////////////////////
+
+    private Name m_prefix;
+    private String m_faceUri;
+    private int m_faceId;
+    private boolean m_isPermanent;
+    private boolean m_isFaceUri;
+  }
   /////////////////////////////////////////////////////////////////////////
 
   public interface Callbacks {
@@ -591,4 +702,6 @@
 
   private Handler m_timeoutHandler = new Handler();
 
+  private RouteCreateAsyncTask m_routeCreateAsyncTask;
+
 }
diff --git a/app/src/main/java/net/named_data/nfd/FaceListRouteCreateDialogFragment.java b/app/src/main/java/net/named_data/nfd/FaceListRouteCreateDialogFragment.java
new file mode 100644
index 0000000..c358077
--- /dev/null
+++ b/app/src/main/java/net/named_data/nfd/FaceListRouteCreateDialogFragment.java
@@ -0,0 +1,87 @@
+/* -*- Mode:jde; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2015-2019 Regents of the University of California
+ * <p/>
+ * This file is part of NFD (Named Data Networking Forwarding Daemon) Android.
+ * See AUTHORS.md for complete list of NFD Android authors and contributors.
+ * <p/>
+ * NFD Android is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ * <p/>
+ * NFD Android is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ * <p/>
+ * You should have received a copy of the GNU General Public License along with
+ * NFD Android, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.named_data.nfd;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v4.app.DialogFragment;
+import android.view.LayoutInflater;
+import android.view.WindowManager;
+import android.widget.CheckBox;
+import android.widget.EditText;
+
+import net.named_data.jndn.Name;
+
+public class FaceListRouteCreateDialogFragment extends DialogFragment {
+
+  public static interface OnFaceListRouteCreateRequestd {
+    public void
+    createRoute(Name prefix, int faceId, boolean isPermanent);
+  }
+
+  public static FaceListRouteCreateDialogFragment
+  newInstance(int faceId) {
+    FaceListRouteCreateDialogFragment faceListRouteCreateDialogFragment =
+        new FaceListRouteCreateDialogFragment();
+    Bundle args = new Bundle();
+    args.putInt("faceId", faceId);
+    faceListRouteCreateDialogFragment.setArguments(args);
+    return faceListRouteCreateDialogFragment;
+  }
+
+  @NonNull
+  @Override
+  public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
+    super.onCreateDialog(savedInstanceState);
+    int faceId = getArguments().getInt("faceId");
+    AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+    LayoutInflater inflater = getActivity().getLayoutInflater();
+    builder
+        .setView(inflater.inflate(R.layout.dialog_create_face_list_add_route, null))
+        .setPositiveButton(R.string.route_add_dialog_create_route, new DialogInterface.OnClickListener() {
+          @Override
+          public void onClick(DialogInterface dialogInterface, int i) {
+            EditText prefixBox = getDialog().findViewById(R.id.face_list_add_route_prefix);
+            CheckBox permanent = getDialog().findViewById(R.id.face_list_add_route_permanent);
+            final String prefix = prefixBox.getText().toString();
+
+            ((OnFaceListRouteCreateRequestd) getTargetFragment()).createRoute(new Name(prefix),
+                                                                              faceId,
+                                                                              permanent.isChecked());
+          }
+        })
+        .setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
+          @Override
+          public void onClick(DialogInterface dialogInterface, int i) {
+            FaceListRouteCreateDialogFragment.this.getDialog().cancel();
+          }
+        });
+
+    Dialog faceListRouteCreateDialog = builder.create();
+    faceListRouteCreateDialog
+        .getWindow()
+        .setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
+    return faceListRouteCreateDialog;
+  }
+}
diff --git a/app/src/main/java/net/named_data/nfd/RouteCreateDialogFragment.java b/app/src/main/java/net/named_data/nfd/RouteCreateDialogFragment.java
index 8e09e55..a77d810 100644
--- a/app/src/main/java/net/named_data/nfd/RouteCreateDialogFragment.java
+++ b/app/src/main/java/net/named_data/nfd/RouteCreateDialogFragment.java
@@ -1,23 +1,24 @@
 /* -*- Mode:jde; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (c) 2015 Regents of the University of California
- *
+/*
+ * Copyright (c) 2015-2019 Regents of the University of California
+ * <p/>
  * This file is part of NFD (Named Data Networking Forwarding Daemon) Android.
  * See AUTHORS.md for complete list of NFD Android authors and contributors.
- *
+ * <p/>
  * NFD Android is free software: you can redistribute it and/or modify it under the terms
  * of the GNU General Public License as published by the Free Software Foundation,
  * either version 3 of the License, or (at your option) any later version.
- *
+ * <p/>
  * NFD Android is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
  * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  * PURPOSE.  See the GNU General Public License for more details.
- *
+ * <p/>
  * You should have received a copy of the GNU General Public License along with
  * NFD Android, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
  */
 
 package net.named_data.nfd;
+import net.named_data.nfd.utils.G;
 
 import android.app.AlertDialog;
 import android.app.Dialog;
@@ -32,11 +33,16 @@
 
 import net.named_data.jndn.Name;
 
+import java.util.regex.Pattern;
+
 public class RouteCreateDialogFragment extends DialogFragment
 {
   public static interface OnRouteCreateRequested {
     public void
-    createRoute(Name prefix, String faceUri, boolean isPermanent);
+    createRouteByFaceUri(Name prefix, String faceUri, boolean isPermanent);
+
+    public void
+    createRouteByFaceId(Name prefix, int faceId, boolean isPermanent);
   }
 
   public static RouteCreateDialogFragment
@@ -49,6 +55,7 @@
   onCreateDialog(Bundle savedInstanceState) {
     AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
     LayoutInflater inflater = getActivity().getLayoutInflater();
+
     builder
       .setView(inflater.inflate(R.layout.dialog_create_route, null))
       .setPositiveButton(R.string.route_add_dialog_create_route, new DialogInterface.OnClickListener() {
@@ -58,10 +65,27 @@
           EditText prefixBox = (EditText) getDialog().findViewById(R.id.prefix);
           EditText uriBox = (EditText) getDialog().findViewById(R.id.faceUri);
           final String prefix = prefixBox.getText().toString();
-          final String uri = uriBox.getText().toString();
 
           CheckBox permanent = (CheckBox) getDialog().findViewById(R.id.permanent);
-          ((OnRouteCreateRequested)getTargetFragment()).createRoute(new Name(prefix), uri, permanent.isChecked());
+
+          if (Pattern.matches("[0-9]{1,18}", uriBox.getText().toString())) {
+            // Assume FaceID entered
+            try {
+              final int faceId = Integer.valueOf(uriBox.getText().toString());
+              ((OnRouteCreateRequested)getTargetFragment()).createRouteByFaceId(new Name(prefix),
+                                                                                faceId,
+                                                                                permanent.isChecked());
+            } catch (Exception e) {
+              G.Log("Failed to convert string " + uriBox.getText().toString() + " to number: " + e.toString());
+            }
+          }
+          else {
+            // Assume FaceURI entered
+            final String uri = uriBox.getText().toString();
+            ((OnRouteCreateRequested)getTargetFragment()).createRouteByFaceUri(new Name(prefix),
+                                                                               uri,
+                                                                               permanent.isChecked());
+          }
         }
       })
       .setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
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 f461dce..b205d75 100644
--- a/app/src/main/java/net/named_data/nfd/RouteListFragment.java
+++ b/app/src/main/java/net/named_data/nfd/RouteListFragment.java
@@ -1,6 +1,6 @@
 /* -*- Mode:jde; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2015-2017 Regents of the University of California
+ * Copyright (c) 2015-2019 Regents of the University of California
  * <p/>
  * This file is part of NFD (Named Data Networking Forwarding Daemon) Android.
  * See AUTHORS.md for complete list of NFD Android authors and contributors.
@@ -111,9 +111,9 @@
         final RibEntry entry = (RibEntry) parent.getItemAtPosition(position);
         new AlertDialog.Builder(v.getContext())
           .setIcon(android.R.drawable.ic_dialog_alert)
-          .setTitle("Deleting route")
-          .setMessage("Are you sure you want to delete " + entry.getName().toUri() + "?")
-          .setPositiveButton("Yes", new DialogInterface.OnClickListener() {
+          .setTitle(R.string.route_list_delete_route_dialog_titile)
+          .setMessage(getString(R.string.route_list_delete_route_dialog_warning) + " " + entry.getName().toUri() + "?")
+          .setPositiveButton(R.string.route_list_delete_route_item, new DialogInterface.OnClickListener() {
             @Override
             public void onClick(DialogInterface dialog, int which) {
               List<Integer> faceList = new ArrayList<>();
@@ -123,7 +123,7 @@
               removeRoute(entry.getName(), faceList);
             }
           })
-          .setNegativeButton("No", null)
+          .setNegativeButton(android.R.string.cancel, null)
           .show();
 
         return true;
@@ -198,8 +198,15 @@
 
   @Override
   public void
-  createRoute(Name prefix, String faceUri, boolean isPermanent) {
-    m_routeCreateAsyncTask = new RouteCreateAsyncTask(prefix, faceUri, isPermanent);
+  createRouteByFaceUri(Name prefix, String faceUri, boolean isPermanent) {
+    m_routeCreateAsyncTask = new RouteCreateAsyncTask(prefix, 0, faceUri, isPermanent, true);
+    m_routeCreateAsyncTask.execute();
+  }
+
+  @Override
+  public void
+  createRouteByFaceId(Name prefix, int faceId, boolean isPermanent) {
+    m_routeCreateAsyncTask = new RouteCreateAsyncTask(prefix, faceId, "", isPermanent, false);
     m_routeCreateAsyncTask.execute();
   }
 
@@ -434,10 +441,12 @@
   }
 
   private class RouteCreateAsyncTask extends AsyncTask<Void, Void, String> {
-    RouteCreateAsyncTask(Name prefix, String faceUri, boolean isPermanent) {
+    RouteCreateAsyncTask(Name prefix, int faceId, String faceUri, boolean isPermanent, boolean isFaceUri) {
       m_prefix = prefix;
+      m_faceId = faceId;
       m_faceUri = faceUri;
       m_isPermanent = isPermanent;
+      m_isFaceUri = isFaceUri;
     }
 
     @Override
@@ -445,16 +454,39 @@
     doInBackground(Void... params) {
       NfdcHelper nfdcHelper = new NfdcHelper();
       try {
-        int faceId = nfdcHelper.faceCreate(m_faceUri);
-        nfdcHelper.ribRegisterPrefix(new Name(m_prefix), faceId, 10, true, false);
-        if (m_isPermanent) {
-          Context context = getActivity().getApplicationContext();
-          SharedPreferencesManager
-            .addPermanentRoute(
-              context,
-              m_prefix.toUri(),
-              NfdcHelper.formatFaceUri(m_faceUri)
-            );
+        if (m_isFaceUri) {
+          int faceId = nfdcHelper.faceCreate(m_faceUri);
+          nfdcHelper.ribRegisterPrefix(new Name(m_prefix), faceId, 10, true, false);
+          if (m_isPermanent) {
+            Context context = getActivity().getApplicationContext();
+            SharedPreferencesManager
+                .addPermanentRoute(
+                    context,
+                    m_prefix.toUri(),
+                    NfdcHelper.formatFaceUri(m_faceUri)
+                );
+          }
+        } else {
+          nfdcHelper.ribRegisterPrefix(new Name(m_prefix), m_faceId, 10, true, false);
+          if (m_isPermanent) {
+            String uri = null;
+            for (FaceStatus faceStatus : nfdcHelper.faceList()) {
+              if (faceStatus.getFaceId() == m_faceId) {
+                uri = faceStatus.getRemoteUri();
+                break;
+              }
+            }
+            if (uri == null) {
+              throw new ManagementException("Face not found: " + uri);
+            }
+            Context context = getActivity().getApplicationContext();
+            SharedPreferencesManager
+                .addPermanentRoute(
+                    context,
+                    m_prefix.toUri(),
+                    NfdcHelper.formatFaceUri(uri)
+                );
+          }
         }
         nfdcHelper.shutdown();
         return "OK";
@@ -495,7 +527,9 @@
 
     private Name m_prefix;
     private String m_faceUri;
+    private int m_faceId;
     private boolean m_isPermanent;
+    private boolean m_isFaceUri;
   }
 
 
diff --git a/app/src/main/java/net/named_data/nfd/service/NfdService.java b/app/src/main/java/net/named_data/nfd/service/NfdService.java
index 92196f6..184799e 100644
--- a/app/src/main/java/net/named_data/nfd/service/NfdService.java
+++ b/app/src/main/java/net/named_data/nfd/service/NfdService.java
@@ -1,18 +1,18 @@
 /* -*- Mode:jde; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
+/*
  * Copyright (c) 2015-2019 Regents of the University of California
- * <p>
+ * <p/>
  * This file is part of NFD (Named Data Networking Forwarding Daemon) Android.
  * See AUTHORS.md for complete list of NFD Android authors and contributors.
- * <p>
+ * <p/>
  * NFD Android is free software: you can redistribute it and/or modify it under the terms
  * of the GNU General Public License as published by the Free Software Foundation,
  * either version 3 of the License, or (at your option) any later version.
- * <p>
+ * <p/>
  * NFD Android is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
  * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  * PURPOSE.  See the GNU General Public License for more details.
- * <p>
+ * <p/>
  * You should have received a copy of the GNU General Public License along with
  * NFD Android, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
  */
@@ -26,7 +26,6 @@
 import android.app.Service;
 import android.content.Context;
 import android.content.Intent;
-import android.graphics.Color;
 import android.os.AsyncTask;
 import android.os.Build;
 import android.os.Handler;
@@ -42,6 +41,7 @@
 import com.android.volley.toolbox.StringRequest;
 import com.android.volley.toolbox.Volley;
 import com.intel.jndn.management.ManagementException;
+import com.intel.jndn.management.types.FaceStatus;
 import com.intel.jndn.management.types.RibEntry;
 
 import net.named_data.jndn.Name;
@@ -328,7 +328,17 @@
         Set<String[]> prefixAndFacePairs = SharedPreferencesManager.getPermanentRoutes(this.context);
         G.Log(TAG, "Permanent face list has " + prefixAndFacePairs.size() + " item(s)");
         for (String[] prefixAndFaceUri : prefixAndFacePairs) {
-          int faceId = nfdcHelper.faceCreate(prefixAndFaceUri[1]);
+          List<FaceStatus> faceStatuses = nfdcHelper.faceList();
+          int faceId = -1;
+          for (int i = 0; i < faceStatuses.size(); i++) {
+            if (prefixAndFaceUri[1].equals(faceStatuses.get(i).getRemoteUri())) {
+              faceId = faceStatuses.get(i).getFaceId();
+              break;
+            }
+          }
+          if (faceId == -1) {
+            faceId = nfdcHelper.faceCreate(prefixAndFaceUri[1]);
+          }
           nfdcHelper.ribRegisterPrefix(new Name(prefixAndFaceUri[0]), faceId, 10, true, false);
           G.Log(TAG, "Create permanent route" + prefixAndFaceUri[0] + " - " + prefixAndFaceUri[1]);
         }
diff --git a/app/src/main/res/drawable-hdpi/ic_action_add_route.png b/app/src/main/res/drawable-hdpi/ic_action_add_route.png
new file mode 100644
index 0000000..e055e9f
--- /dev/null
+++ b/app/src/main/res/drawable-hdpi/ic_action_add_route.png
Binary files differ
diff --git a/app/src/main/res/drawable-mdpi/ic_action_add_route.png b/app/src/main/res/drawable-mdpi/ic_action_add_route.png
new file mode 100644
index 0000000..186e6b9
--- /dev/null
+++ b/app/src/main/res/drawable-mdpi/ic_action_add_route.png
Binary files differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_action_add_route.png b/app/src/main/res/drawable-xhdpi/ic_action_add_route.png
new file mode 100644
index 0000000..63aab39
--- /dev/null
+++ b/app/src/main/res/drawable-xhdpi/ic_action_add_route.png
Binary files differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_action_add_route.png b/app/src/main/res/drawable-xxhdpi/ic_action_add_route.png
new file mode 100644
index 0000000..644d8d1
--- /dev/null
+++ b/app/src/main/res/drawable-xxhdpi/ic_action_add_route.png
Binary files differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_action_add_route.png b/app/src/main/res/drawable-xxxhdpi/ic_action_add_route.png
new file mode 100644
index 0000000..44c1005
--- /dev/null
+++ b/app/src/main/res/drawable-xxxhdpi/ic_action_add_route.png
Binary files differ
diff --git a/app/src/main/res/layout/dialog_create_face_list_add_route.xml b/app/src/main/res/layout/dialog_create_face_list_add_route.xml
new file mode 100644
index 0000000..708a455
--- /dev/null
+++ b/app/src/main/res/layout/dialog_create_face_list_add_route.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content">
+
+    <TextView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        style="@style/default_dialog_margin"
+        android:textAppearance="?android:attr/textAppearanceMedium"
+        android:text="@string/dialog_face_list_add_route_edit_title"
+        android:layout_gravity="center_horizontal"/>
+
+    <EditText
+        android:id="@+id/face_list_add_route_prefix"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        style="@style/default_dialog_margin"
+        android:hint="@string/dialog_add_route_edit_prefix_hint"
+        android:inputType="text"
+        android:focusable="true"
+        android:focusableInTouchMode="true"
+        android:selectAllOnFocus="true">
+        <requestFocus />
+    </EditText>
+
+    <CheckBox
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/dialog_add_route_or_face_as_permanent"
+        android:id="@+id/face_list_add_route_permanent"
+        android:layout_gravity="center_horizontal"
+        android:checked="false" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/dialog_create_route.xml b/app/src/main/res/layout/dialog_create_route.xml
index 5d8630d..993688b 100644
--- a/app/src/main/res/layout/dialog_create_route.xml
+++ b/app/src/main/res/layout/dialog_create_route.xml
@@ -30,7 +30,7 @@
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         style="@style/default_dialog_margin"
-        android:hint="@string/dialog_add_route_edit_face_uri_hint"
+        android:hint="@string/route_list_add_route_edit_face_hint"
         android:inputType="text"
         android:focusable="true"
         android:focusableInTouchMode="true"
diff --git a/app/src/main/res/menu/menu_face_list_floating.xml b/app/src/main/res/menu/menu_face_list_floating.xml
new file mode 100644
index 0000000..83af90f
--- /dev/null
+++ b/app/src/main/res/menu/menu_face_list_floating.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto">
+
+    <item
+        android:id="@+id/menu_item_details_face_item_floating"
+        android:title="@string/menu_item_face_details"
+        app:showAsAction="never"
+        />
+
+    <item
+        android:id="@+id/menu_item_add_route_face_item_floating"
+        android:icon="@drawable/ic_action_add_route"
+        android:title="@string/menu_item_add_route"
+        app:showAsAction="never"
+        />
+
+    <item
+        android:id="@+id/menu_item_delete_face_item_floating"
+        android:icon="@drawable/ic_action_discard"
+        android:title="@string/menu_item_delete_face_item"
+        app:showAsAction="never"
+        />
+
+</menu>
\ No newline at end of file
diff --git a/app/src/main/res/menu/menu_face_list_multiple_modal_menu.xml b/app/src/main/res/menu/menu_face_list_multiple_modal_menu.xml
index a6b91be..b4dcb9c 100644
--- a/app/src/main/res/menu/menu_face_list_multiple_modal_menu.xml
+++ b/app/src/main/res/menu/menu_face_list_multiple_modal_menu.xml
@@ -9,4 +9,12 @@
         app:showAsAction="always"
         />
 
+    <item
+        android:id="@+id/menu_item_add_route"
+        android:icon="@drawable/ic_action_add_route"
+        android:title="@string/menu_item_delete_face_item"
+        app:showAsAction="always"
+        />
+
+
 </menu>
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index eb7b812..96c2b50 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -61,7 +61,11 @@
     <string name="route_list_list_of_routes_title">List of Routes</string>
     <string name="route_list_refresh_route_list">Refresh Route List</string>
     <string name="route_list_add_route">Add Route</string>
-    <string name="dialog_add_route_edit_title">Enter prefix and FaceUri to register with NDN daemon</string>
+    <string name="route_list_add_route_edit_face_hint">Face URI or Face ID</string>
+    <string name="route_list_delete_route_dialog_titile">Deleting Route</string>
+    <string name="route_list_delete_route_dialog_warning">Are you sure you want to delete</string>
+    <string name="route_list_delete_route_item">Delete</string>
+    <string name="dialog_add_route_edit_title">Enter prefix and FaceUri or FaceID to register with NFD</string>
     <string name="dialog_add_route_edit_prefix_hint">Prefix</string>
     <string name="dialog_add_route_edit_face_uri_hint">Face URI</string>
     <string name="dialog_add_route_or_face_as_permanent">Keep it permanent</string>
@@ -69,11 +73,17 @@
     <string name="face_list_refresh_face_list">Refresh Face List</string>
     <string name="face_list_list_of_faces_title">List of Faces</string>
     <string name="face_list_add_face">Add Face</string>
-    <string name="dialog_add_face_edit_title">Enter FaceUri for the remote NDN daemon</string>
+    <string name="face_list_delete_face_dialog_title">Deleting face</string>
+    <string name="face_list_delete_face_dialog_warning">Are you sure you want to delete face:</string>
+    <string name="dialog_add_face_edit_title">Enter FaceUri for the remote NFD</string>
+    <string name="dialog_face_list_add_route_edit_title">Enter prefix to register with NDN NFD</string>
     <string name="fragment_face_details_title">Face Details</string>
     <string name="menu_item_delete_face_item">Delete</string>
+    <string name="menu_item_add_route">Add Route</string>
+    <string name="menu_item_face_details">Face Details</string>
     <string name="expire_never">Never</string>
     <string name="face_id">Face ID</string>
+    <string name="face_uri">Face URI</string>
     <string name="local_face_uri">Local FaceURI</string>
     <string name="remote_face_uri">Remote FaceURI</string>
     <string name="expires_in">Expires in</string>