Support removal of individual next hops - new logic implemented
Refs: #3442
Change-Id: I56f72c9df01fb91c2acb7e037fdff1007def458f
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 f6e0b4f..162f80b 100644
--- a/app/src/main/java/net/named_data/nfd/RouteInfoFragment.java
+++ b/app/src/main/java/net/named_data/nfd/RouteInfoFragment.java
@@ -5,14 +5,21 @@
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.annotation.Nullable;
+import android.support.v4.app.Fragment;
import android.support.v4.app.ListFragment;
import android.util.Pair;
+import android.view.ActionMode;
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.BaseAdapter;
import android.widget.HeaderViewListAdapter;
import android.widget.ListView;
+import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
@@ -21,12 +28,15 @@
import com.intel.jndn.management.types.RibEntry;
import com.intel.jndn.management.types.Route;
+import net.named_data.jndn.Name;
import net.named_data.jndn.encoding.EncodingException;
import net.named_data.jndn.util.Blob;
+import net.named_data.jndn_xx.util.FaceUri;
import net.named_data.nfd.utils.G;
import net.named_data.nfd.utils.NfdcHelper;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
@@ -78,6 +88,60 @@
TextView prefix = (TextView)v.findViewById(R.id.route_detail_prefix);
prefix.setText(m_ribEntry.getName().toUri());
+
+ // Get progress bar spinner view
+ m_reloadingListProgressBar = (ProgressBar)v.findViewById(R.id.route_detail_list_reloading_list_progress_bar);
+
+ ListView listView = getListView();
+ listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
+ listView.setMultiChoiceModeListener(new AbsListView.MultiChoiceModeListener() {
+ @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_routeFacesToDelete));
+ removeRouteFace(m_ribEntry.getName(), m_routeFacesToDelete);
+ m_routeFacesToDelete = new HashSet<>();
+ mode.finish();
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ @Override
+ public void onDestroyActionMode(ActionMode mode) {
+
+ }
+
+ @Override
+ public void
+ onItemCheckedStateChanged(ActionMode mode, int position, long id, boolean checked) {
+ if (checked && id < 256) {
+ getListView().setItemChecked(position, false);
+ return;
+ }
+ if (checked)
+ m_routeFacesToDelete.add((int)id);
+ else
+ m_routeFacesToDelete.remove((int)id);
+ }
+
+ private HashSet<Integer> m_routeFacesToDelete = new HashSet<>();
+
+ });
}
@Override
@@ -103,17 +167,18 @@
public void onResume()
{
super.onResume();
- m_faceListAsyncTask = new FaceListAsyncTask();
- m_faceListAsyncTask.execute();
+ startRouteFaceListRetrievalTask();
}
@Override
public void onPause()
{
super.onPause();
- if (m_faceListAsyncTask != null) {
- m_faceListAsyncTask.cancel(false);
- m_faceListAsyncTask = null;
+ stopRouteFaceListRetrievalTask();
+
+ if (m_routeFaceRemoveAsyncTask != null) {
+ m_routeFaceRemoveAsyncTask.cancel(false);
+ m_routeFaceRemoveAsyncTask = null;
}
}
@@ -134,6 +199,43 @@
/////////////////////////////////////////////////////////////////////////////
+ private void removeRouteFace(Name prefix, HashSet<Integer> faceIds)
+ {
+ m_routeFaceRemoveAsyncTask = new RouteFaceRemoveAsyncTask(prefix, faceIds);
+ m_routeFaceRemoveAsyncTask.execute();
+ }
+
+ private void retrieveRouteFaceList() {
+ // Stop if running; before starting the new Task
+ if (m_routeListAsyncTask != null) {
+ m_routeListAsyncTask.cancel(false);
+ m_routeListAsyncTask = null;
+ }
+ m_routeListAsyncTask = new RouteListAsyncTask();
+ m_routeListAsyncTask.execute();
+
+ stopRouteFaceListRetrievalTask();
+ startRouteFaceListRetrievalTask();
+ }
+
+ /**
+ * Create a new AsyncTask for face list information retrieval.
+ */
+ private void startRouteFaceListRetrievalTask() {
+ m_faceListAsyncTask = new FaceListAsyncTask();
+ m_faceListAsyncTask.execute();
+ }
+
+ /**
+ * Stops a previously started face retrieval AsyncTask.
+ */
+ private void stopRouteFaceListRetrievalTask() {
+ if (m_faceListAsyncTask != null) {
+ m_faceListAsyncTask.cancel(false);
+ m_faceListAsyncTask = null;
+ }
+ }
+
/**
* Updates the underlying adapter with the given list of FaceStatus.
*
@@ -182,7 +284,7 @@
public long
getItemId(int position)
{
- return position;
+ return m_ribEntry.getRoutes().get(position).getFaceId();
}
@Override
@@ -238,6 +340,8 @@
@Override
protected void
onPreExecute() {
+ // Display progress bar
+ m_reloadingListProgressBar.setVisibility(View.VISIBLE);
}
@Override
@@ -258,22 +362,162 @@
@Override
protected void
onCancelled() {
- // Nothing to do here; No change in UI.
+ // Remove progress bar
+ m_reloadingListProgressBar.setVisibility(View.GONE);
}
@Override
protected void
onPostExecute(Pair<List<FaceStatus>, Exception> result) {
+ // Remove progress bar
+ m_reloadingListProgressBar.setVisibility(View.GONE);
+
if (result.second != null) {
Toast.makeText(getActivity(),
"Error communicating with NFD (" + result.second.getMessage() + ")",
Toast.LENGTH_LONG).show();
+ return;
}
updateFaceList(result.first);
}
}
+ private class RouteListAsyncTask extends AsyncTask<Void, Void, Pair<List<RibEntry>, Exception>> {
+ @Override
+ protected void
+ onPreExecute() {
+ // Display progress bar
+ m_reloadingListProgressBar.setVisibility(View.VISIBLE);
+ }
+
+ @Override
+ protected Pair<List<RibEntry>, Exception>
+ doInBackground(Void... params) {
+ NfdcHelper nfdcHelper = new NfdcHelper();
+ Exception returnException = null;
+ List<RibEntry> routes = null;
+ try {
+ routes = nfdcHelper.ribList();
+ }
+ catch (Exception e) {
+ returnException = e;
+ }
+ nfdcHelper.shutdown();
+ return new Pair<>(routes, returnException);
+ }
+
+ @Override
+ protected void onCancelled() {
+ // Remove progress bar
+ m_reloadingListProgressBar.setVisibility(View.GONE);
+ }
+
+ @Override
+ protected void onPostExecute(Pair<List<RibEntry>, Exception> result) {
+ // Remove progress bar
+ m_reloadingListProgressBar.setVisibility(View.GONE);
+
+ if (result.second != null) {
+ Toast.makeText(getActivity(),
+ "Error communicating with NFD (" + result.second.getMessage() + ")",
+ Toast.LENGTH_LONG).show();
+ return;
+ }
+
+ updateRoute(result.first);
+ }
+ }
+
+ private void updateRoute(List<RibEntry> ribList) {
+ for (RibEntry rib : ribList) {
+ if ((rib.getName().toUri()).equals(m_ribEntry.getName().toUri())) {
+ m_ribEntry = rib;
+ m_routeFaceListAdapter = new RouteFaceListAdapter(getActivity(), m_ribEntry);
+ setListAdapter(m_routeFaceListAdapter);
+ return;
+ }
+ }
+
+ // After removal of the last next hops, jump back to the route list fragment
+ Fragment fragment = RouteListFragment.newInstance();
+ getActivity().getSupportFragmentManager()
+ .beginTransaction()
+ .replace(R.id.main_fragment_container, fragment)
+ .commit();
+ }
+
+ /**
+ * AsyncTask that removes next hops that are passed in as a list of NextHopInfo.
+ */
+ private class RouteFaceRemoveAsyncTask extends AsyncTask<Void, Void, String> {
+ public
+ RouteFaceRemoveAsyncTask(Name prefix, HashSet<Integer> routeFaceIds)
+ {
+ m_prefix = prefix;
+ m_routeFaceList = routeFaceIds;
+ }
+
+ @Override
+ protected String
+ doInBackground(Void... params)
+ {
+ NfdcHelper nfdcHelper = new NfdcHelper();
+ try {
+ for (int routeFaceId : m_routeFaceList) {
+ nfdcHelper.ribUnregisterPrefix(m_prefix, routeFaceId);
+ }
+
+ nfdcHelper.shutdown();
+ return "OK";
+ }
+ catch (FaceUri.CanonizeError e) {
+ return "Error Destroying dace (" + e.getMessage() + ")";
+ }
+ catch (FaceUri.Error e) {
+ return "Error destroying 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();
+
+ retrieveRouteFaceList();
+ }
+
+ @Override
+ protected void
+ onCancelled()
+ {
+ // Remove progress bar
+ m_reloadingListProgressBar.setVisibility(View.GONE);
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ private Name m_prefix;
+ private HashSet<Integer> m_routeFaceList;
+ }
+
/////////////////////////////////////////////////////////////////////////////
@@ -282,11 +526,19 @@
private RibEntry m_ribEntry;
+ /** Progress bar spinner to display to user when destroying faces */
+ private ProgressBar m_reloadingListProgressBar;
+
/** Callback handler of the hosting activity */
private FaceListFragment.Callbacks m_callbacks;
+ /** Reference to the most recent AsyncTask that was created for removing a next hop for a route */
+ private RouteFaceRemoveAsyncTask m_routeFaceRemoveAsyncTask;
+
/** Reference to the most recent AsyncTask that was created for listing faces */
private FaceListAsyncTask m_faceListAsyncTask;
+ private RouteListAsyncTask m_routeListAsyncTask;
+
private RouteFaceListAdapter m_routeFaceListAdapter;
}
diff --git a/app/src/main/res/layout/fragment_route_detail_list_header.xml b/app/src/main/res/layout/fragment_route_detail_list_header.xml
index 539e84a..2244c1a 100644
--- a/app/src/main/res/layout/fragment_route_detail_list_header.xml
+++ b/app/src/main/res/layout/fragment_route_detail_list_header.xml
@@ -29,4 +29,10 @@
style="?android:listSeparatorTextViewStyle"
/>
+ <ProgressBar
+ android:id="@+id/route_detail_list_reloading_list_progress_bar"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:visibility="gone" />
+
</LinearLayout>
\ No newline at end of file