gui: Convert UI to use Fragments
Change-Id: I7269604a1da72e6b22f4bbac31c1f5561660ccf5
Refs: #2646, #2667
diff --git a/app/build.gradle b/app/build.gradle
index 674060e..86267a6 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -3,7 +3,7 @@
apply plugin: 'com.android.application'
android {
- compileSdkVersion 19
+ compileSdkVersion 21
buildToolsVersion "21.1.2"
defaultConfig {
@@ -130,7 +130,7 @@
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
- compile 'com.android.support:appcompat-v7:20.0.0'
+ compile 'com.android.support:appcompat-v7:21.0.3'
compile 'com.android.support:support-v4:21.0.3'
compile 'net.named-data:jndn:0.4'
@@ -141,5 +141,4 @@
compile 'com.google.protobuf:protobuf-java:2.6.1'
compile 'joda-time:joda-time:2.7'
- compile 'commons-lang:commons-lang:2.6'
}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index e28c78b..8ce237c 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -20,22 +20,6 @@
</intent-filter>
</activity>
- <activity
- android:name=".LogcatSettingsActivity"
- android:label="@string/nfd_log_settings" />
-
- <activity
- android:name=".LogcatActivity"
- android:label="@string/nfd_logger" />
-
- <activity
- android:name=".FaceListActivity"
- android:label="Faces" />
-
- <activity
- android:name=".RouteListActivity"
- android:label="Routes" />
-
<service
android:name=".service.NfdService"
android:process="net.named_data.nfd.service.NfdService"
diff --git a/app/src/main/java/net/named_data/nfd/DrawerFragment.java b/app/src/main/java/net/named_data/nfd/DrawerFragment.java
new file mode 100644
index 0000000..8190941
--- /dev/null
+++ b/app/src/main/java/net/named_data/nfd/DrawerFragment.java
@@ -0,0 +1,527 @@
+/* -*- Mode:jde; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2015 Regents of the University of California
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon) Android.
+ * See AUTHORS.md for complete list of NFD Android authors and contributors.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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.Activity;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.preference.PreferenceManager;
+import android.support.annotation.Nullable;
+import android.support.v4.app.Fragment;
+import android.support.v4.widget.DrawerLayout;
+import android.support.v4.widget.ViewDragHelper;
+import android.support.v7.app.ActionBar;
+import android.support.v7.app.ActionBarActivity;
+import android.support.v7.app.ActionBarDrawerToggle;
+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.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.ImageView;
+import android.widget.ListView;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+
+/**
+ * DrawerFragment that provides navigation for MainActivity.
+ */
+public class DrawerFragment extends Fragment {
+
+ public static DrawerFragment
+ newInstance(ArrayList<DrawerFragment.DrawerItem> items) {
+ Bundle drawerParams = new Bundle();
+ drawerParams.putParcelableArrayList(DrawerFragment.BUNDLE_PARAMETERS, items);
+
+ DrawerFragment fragment = new DrawerFragment();
+ fragment.setArguments(drawerParams);
+ return fragment;
+ }
+
+ @Override
+ public void onAttach(Activity activity) {
+ super.onAttach(activity);
+ try {
+ // Register callback
+ m_callbacks = (DrawerCallbacks)activity;
+ } catch (ClassCastException e) {
+ throw new ClassCastException("Host activity must implement DrawerFragment.DrawerCallbacks.");
+ }
+ }
+
+ @Override
+ public void onDetach() {
+ super.onDetach();
+ m_callbacks = null;
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // Read in the flag indicating whether or not the user has demonstrated awareness of the
+ // drawer. See PREF_DRAWER_SHOWN_TO_USER_FOR_THE_FIRST_TIME for details.
+ SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getActivity());
+ m_hasUserSeenDrawer = sp.getBoolean(PREF_DRAWER_SHOWN_TO_USER_FOR_THE_FIRST_TIME, false);
+
+ if (savedInstanceState != null) {
+ m_drawerSelectedPosition = savedInstanceState.getInt(DRAWER_SELECTED_POSITION_BUNDLE_KEY);
+ m_restoredFromSavedInstanceState = true;
+ }
+
+ m_drawerItems = getArguments().getParcelableArrayList(BUNDLE_PARAMETERS);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater,
+ ViewGroup container,
+ Bundle savedInstanceState)
+ {
+ m_drawerListView = (ListView)inflater.inflate(
+ R.layout.activity_main_drawer_listview, container, false);
+
+ m_drawerListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
+ @Override
+ public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+ // Update UI
+ updateSelection(position);
+ }
+ });
+
+ m_drawerListView.setAdapter(new DrawerListAdapter(getActionBar().getThemedContext(), m_drawerItems));
+ m_drawerListView.setItemChecked(m_drawerSelectedPosition, true);
+
+ return m_drawerListView;
+ }
+
+ @Override
+ public void onActivityCreated(@Nullable Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+ // Fragment influences action bar
+ setHasOptionsMenu(true);
+
+ // Initialize and set up the navigation drawer UI
+ initializeDrawerFragment(getActivity().findViewById(R.id.navigation_drawer),
+ (DrawerLayout)getActivity().findViewById(R.id.drawer_layout));
+
+ if (savedInstanceState == null) {
+ // when restoring (e.g., after rotation), rely on system to restore previous state of
+ // fragments
+ updateSelection(m_drawerSelectedPosition);
+ }
+ }
+
+ /**
+ * Initialize drawer fragment after being attached to the host activity.
+ *
+ * @param drawerFragmentViewContainer View container that holds the navigation drawer
+ * @param drawerLayout DrawerLayout of the drawer in the host Activity
+ */
+ private void initializeDrawerFragment(View drawerFragmentViewContainer,
+ DrawerLayout drawerLayout)
+ {
+ m_drawerFragmentViewContainer = drawerFragmentViewContainer;
+ m_drawerLayout = drawerLayout;
+
+ // Setup drawer and action bar
+ ActionBar actionBar = getActionBar();
+ actionBar.setDisplayHomeAsUpEnabled(true);
+ actionBar.setHomeButtonEnabled(true);
+
+ m_drawerToggle = new ActionBarDrawerToggle(
+ getActivity(),
+ m_drawerLayout,
+ R.string.accessibility_open_drawer,
+ R.string.accessibility_close_drawer)
+ {
+ @Override
+ public void onDrawerClosed(View drawerView) {
+ super.onDrawerClosed(drawerView);
+ if (!isAdded()) {
+ return;
+ }
+
+ // Allow update calls to onCreateOptionsMenu() and
+ // onPrepareOptionsMenu() to update Menu UI.
+ getActivity().supportInvalidateOptionsMenu();
+ }
+
+ @Override
+ public void onDrawerOpened(View drawerView) {
+ super.onDrawerOpened(drawerView);
+ if (!isAdded()) {
+ // Drawer has not been added; Nothing to de here
+ return;
+ }
+
+ // Flag that user has seen drawer for the first time
+ if (!m_hasUserSeenDrawer) {
+ m_hasUserSeenDrawer = true;
+ SharedPreferences sp = PreferenceManager
+ .getDefaultSharedPreferences(getActivity());
+
+ sp.edit()
+ .putBoolean(PREF_DRAWER_SHOWN_TO_USER_FOR_THE_FIRST_TIME, true)
+ .apply();
+ }
+
+ // Allow update calls to onCreateOptionsMenu() and
+ // onPrepareOptionsMenu() to update Menu UI
+ getActivity().supportInvalidateOptionsMenu();
+ }
+
+ @Override
+ public void onDrawerStateChanged(int newState) {
+ super.onDrawerStateChanged(newState);
+ switch (newState) {
+ case ViewDragHelper.STATE_DRAGGING:
+ // Fall through; Same condition.
+ case ViewDragHelper.STATE_SETTLING:
+ if (m_drawerCurrentState == DRAWER_CLOSED) {
+ m_shouldHideOptionsMenu = true;
+ m_drawerCurrentState = DRAWER_SLIDING;
+ getActivity().supportInvalidateOptionsMenu();
+ }
+ break;
+ case ViewDragHelper.STATE_IDLE:
+ if (m_drawerCurrentState == DRAWER_SLIDING) {
+ m_drawerCurrentState = DRAWER_OPENED;
+ m_shouldHideOptionsMenu = false;
+ getActivity().supportInvalidateOptionsMenu();
+ } else if (m_drawerCurrentState == DRAWER_OPENED) {
+ m_drawerCurrentState = DRAWER_CLOSED;
+ }
+ break;
+ }
+ }
+ };
+
+ // Open drawer for the first time
+ if (!m_hasUserSeenDrawer && !m_restoredFromSavedInstanceState) {
+ m_shouldHideOptionsMenu = true;
+ m_drawerCurrentState = DRAWER_OPENED;
+ m_drawerLayout.openDrawer(m_drawerFragmentViewContainer);
+ }
+
+ // Post to drawer's handler to update UI State
+ m_drawerLayout.post(new Runnable() {
+ @Override
+ public void run() {
+ m_drawerToggle.syncState();
+ }
+ });
+
+ m_drawerLayout.setDrawerListener(m_drawerToggle);
+ }
+
+ @Override
+ public void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ outState.putInt(DRAWER_SELECTED_POSITION_BUNDLE_KEY, m_drawerSelectedPosition);
+ }
+
+ @Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ // Forward the new configuration the drawer toggle component.
+ m_drawerToggle.onConfigurationChanged(newConfig);
+ }
+
+ @Override
+ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ super.onCreateOptionsMenu(menu, inflater);
+ // Update menu UI when the drawer is open. This gives the user a better
+ // contextual perception of the application.
+ if (m_drawerLayout != null && isDrawerOpen()) {
+ // Inflate drawer specific menu here (if any)
+ showGlobalContextActionBar();
+ }
+
+ }
+
+ @Override
+ public void onPrepareOptionsMenu(Menu menu) {
+ super.onPrepareOptionsMenu(menu);
+ // Remove option menu items when drawer is sliding out
+ if (m_shouldHideOptionsMenu) {
+ for (int i = 0; i < menu.size(); i++) {
+ menu.getItem(i).setVisible(false);
+ }
+ }
+
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ // Handle drawer selection events
+ if (m_drawerToggle.onOptionsItemSelected(item)) {
+ return true;
+ }
+
+ // Handle other menu items
+ switch (item.getItemId()) {
+ // Handle activity menu item here (if any)
+ default:
+ return super.onOptionsItemSelected(item);
+ }
+ }
+
+ /**
+ * Convenience method that updates the UI and callbacks the host activity.
+ *
+ * @param position Position of the selected item within the Drawer's ListView.
+ */
+ private void updateSelection(int position) {
+ // Update Position
+ m_drawerSelectedPosition = position;
+
+ // Update UI of selected position
+ if (m_drawerListView != null) {
+ m_drawerListView.setItemChecked(position, true);
+ }
+
+ // Close drawer
+ if (m_drawerLayout != null) {
+ m_drawerLayout.closeDrawer(m_drawerFragmentViewContainer);
+ }
+
+ // Invoke host activity callback
+ if (m_callbacks != null) {
+ DrawerItem item = m_drawerItems.get(position);
+ m_callbacks.onDrawerItemSelected(item.getItemCode(), item.getItemName());
+ }
+ }
+
+ /**
+ * Safe convenience method to determine if drawer is open.
+ *
+ * @return True if drawer is present and in an open state; false otherwise
+ */
+ public boolean isDrawerOpen() {
+ return m_drawerLayout != null && m_drawerLayout.isDrawerOpen(m_drawerFragmentViewContainer);
+ }
+
+ /**
+ * Convenience method to update host activity action bar so that the user is informed of
+ * the app's "current context" of the fragment.
+ */
+ private void showGlobalContextActionBar() {
+ ActionBar actionBar = getActionBar();
+ actionBar.setDisplayShowTitleEnabled(true);
+ actionBar.setTitle(R.string.app_name);
+ }
+
+ /**
+ * Convenience method to get host activity's ActionBar. This makes for easy updates
+ * in a single location when upgrading to use >= HONEYCOMB (API 11) ActionBar.
+ *
+ * @return Host activity's ActionBar.
+ */
+ private ActionBar getActionBar() {
+ return ((ActionBarActivity)getActivity()).getSupportActionBar();
+ }
+
+ //////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * DrawerItem represents a single selection option in the Drawer, complete
+ * with the ability to set a Drawable resource icon for display along
+ * with the drawer item name.
+ */
+ public static class DrawerItem implements Parcelable {
+ @Override
+ public int describeContents()
+ {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel parcel, int i)
+ {
+ parcel.writeInt(m_itemNameId);
+ parcel.writeInt(m_iconResId);
+ parcel.writeInt(m_itemCode);
+ }
+
+ public static final Parcelable.Creator<DrawerItem> CREATOR = new Parcelable.Creator<DrawerItem>() {
+ public DrawerItem
+ createFromParcel(Parcel in) {
+ return new DrawerItem(in.readInt(), in.readInt(), in.readInt());
+ }
+
+ public DrawerItem[] newArray(int size) {
+ return new DrawerItem[size];
+ }
+ };
+
+ public
+ DrawerItem(int itemNameId, int resIconId, int itemCode) {
+ m_itemNameId = itemNameId;
+ m_iconResId = resIconId;
+ m_itemCode = itemCode;
+ }
+
+ public int
+ getItemName() {
+ return m_itemNameId;
+ }
+
+ public int
+ getIconResId() {
+ return m_iconResId;
+ }
+
+ public int
+ getItemCode() {
+ return m_itemCode;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ /** Drawer item name */
+ private final int m_itemNameId;
+
+ /** Resource ID of a drawable to be shown as the item's icon */
+ private final int m_iconResId;
+
+ /** Item code for feedback to the host activity's implemented callback. */
+ private final int m_itemCode;
+
+ }
+
+ /**
+ * Customized DrawerListAdapter to furnishes the Drawer with DrawerItem
+ * information.
+ */
+ private static class DrawerListAdapter extends ArrayAdapter<DrawerItem> {
+
+ public DrawerListAdapter(Context context, ArrayList<DrawerItem> drawerItems) {
+ super(context, 0, drawerItems);
+ m_layoutInflater =
+ (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ m_resources = context.getResources();
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ DrawerItemHolder holder;
+
+ if (convertView == null) {
+ holder = new DrawerItemHolder();
+
+ convertView = m_layoutInflater.inflate(R.layout.list_item_drawer_item, null);
+ convertView.setTag(holder);
+
+ holder.m_icon = (ImageView) convertView.findViewById(R.id.drawer_item_icon);
+ holder.m_text = (TextView) convertView.findViewById(R.id.drawer_item_text);
+ } else {
+ holder = (DrawerItemHolder)convertView.getTag();
+ }
+
+ // Update items in holder
+ DrawerItem item = getItem(position);
+ if (item.getIconResId() != 0) {
+ holder.m_icon.setImageDrawable(m_resources.getDrawable(item.getIconResId()));
+ }
+ holder.m_text.setText(item.getItemName());
+
+ return convertView;
+ }
+
+ private static class DrawerItemHolder {
+ private ImageView m_icon;
+ private TextView m_text;
+ }
+
+ /** Layout inflater for use */
+ private final LayoutInflater m_layoutInflater;
+
+ /** Reference to get context's resources */
+ private final Resources m_resources;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////
+
+ /** Callback that host activity must implement */
+ public static interface DrawerCallbacks {
+ /** Callback to host activity when a drawer item is selected */
+ void onDrawerItemSelected(int itemCode, int itemNameId);
+ }
+
+ //////////////////////////////////////////////////////////////////////////////
+
+ /** SharedPreference: Display drawer when drawer loads for the very first time */
+ private static final String PREF_DRAWER_SHOWN_TO_USER_FOR_THE_FIRST_TIME
+ = "DRAWER_PRESENTED_TO_USER_ON_FIRST_LOAD";
+
+ /** Bundle key used to (re)store position of selected drawer item */
+ private static final String DRAWER_SELECTED_POSITION_BUNDLE_KEY
+ = "DRAWER_SELECTED_POSITION";
+
+ /** Bundle argument key for bundle parameters */
+ private static final String BUNDLE_PARAMETERS = "net.named_data.nfd.drawer_fragment_parameters";
+
+ /** Callback to parent activity */
+ private DrawerCallbacks m_callbacks;
+
+ /** DrawerToggle for interacting with drawer and action bar app icon */
+ private ActionBarDrawerToggle m_drawerToggle;
+
+ /** Reference to DrawerLayout fragment in host activity */
+ private DrawerLayout m_drawerLayout;
+
+ /** Reference to drawer's ListView */
+ private ListView m_drawerListView;
+
+ /** Drawer's fragment container in the host activity */
+ private View m_drawerFragmentViewContainer;
+
+ /** Current position of the Drawer's selection */
+ private int m_drawerSelectedPosition = 0;
+
+ /** Flag that denotes if the fragment is restored from an instance state */
+ private boolean m_restoredFromSavedInstanceState;
+
+ /** Flag that denotes if the user has seen the Drawer when the app loads for the first time */
+ private boolean m_hasUserSeenDrawer;
+
+ /** ArrayList of DrawerItems to be displayed in the Drawer */
+ private ArrayList<DrawerItem> m_drawerItems;
+
+ /** Flag that marks if drawer is sliding outwards and being displayed */
+ private boolean m_shouldHideOptionsMenu;
+
+ /** Keeping track of the drawer state */
+ private int m_drawerCurrentState = DRAWER_CLOSED;
+
+ /** Drawer State Values that are used by m_drawerCurrentState */
+ private static final int DRAWER_SLIDING = 1;
+ private static final int DRAWER_CLOSED = 2;
+ private static final int DRAWER_OPENED = 3;
+}
diff --git a/app/src/main/java/net/named_data/nfd/FaceCreateDialog.java b/app/src/main/java/net/named_data/nfd/FaceCreateDialog.java
deleted file mode 100644
index 0020f59..0000000
--- a/app/src/main/java/net/named_data/nfd/FaceCreateDialog.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/* -*- Mode:jde; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (c) 2015 Regents of the University of California
- *
- * This file is part of NFD (Named Data Networking Forwarding Daemon) Android.
- * See AUTHORS.md for complete list of NFD Android authors and contributors.
- *
- * 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.
- *
- * 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.
- *
- * 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.app.DialogFragment;
-import android.content.DialogInterface;
-import android.os.Bundle;
-import android.view.LayoutInflater;
-import android.view.WindowManager;
-import android.widget.EditText;
-
-import net.named_data.jndn_xx.util.FaceUri;
-import net.named_data.nfd.utils.Nfdc;
-import net.named_data.nfd.utils.NfdcAsyncTask;
-
-public class FaceCreateDialog extends DialogFragment
-{
- @Override
- public Dialog
- onCreateDialog(Bundle savedInstanceState) {
- AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
- LayoutInflater inflater = getActivity().getLayoutInflater();
- builder
- .setView(inflater.inflate(R.layout.create_face, null))
- .setPositiveButton("Create face", new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int id)
- {
- EditText uriBox = (EditText) getDialog().findViewById(R.id.faceUri);
- final String uri = uriBox.getText().toString();
- new NfdcAsyncTask(getActivity(),
- new NfdcAsyncTask.Task() {
- public String
- runTask() throws Exception
- {
- try {
- Nfdc nfdc = new Nfdc();
- int faceId = nfdc.faceCreate(m_uri);
- nfdc.shutdown();
- return "OK. Face id: " + String.valueOf(faceId);
- } catch (FaceUri.CanonizeError e) {
- return "Error creating face (" + e.getMessage() + ")";
- } catch (FaceUri.Error e) {
- return "Error creating face (" + e.getMessage() + ")";
- }
- }
-
- ///////////////////////////
- private String m_uri = uri;
- }).execute();
- }
- })
- .setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int id)
- {
- FaceCreateDialog.this.getDialog().cancel();
- }
- })
- ;
-
- Dialog faceCreateDialog = builder.create();
- faceCreateDialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
- return faceCreateDialog;
- }
-}
diff --git a/app/src/main/java/net/named_data/nfd/FaceCreateDialogFragment.java b/app/src/main/java/net/named_data/nfd/FaceCreateDialogFragment.java
new file mode 100644
index 0000000..2013129
--- /dev/null
+++ b/app/src/main/java/net/named_data/nfd/FaceCreateDialogFragment.java
@@ -0,0 +1,72 @@
+/* -*- Mode:jde; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2015 Regents of the University of California
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon) Android.
+ * See AUTHORS.md for complete list of NFD Android authors and contributors.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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.EditText;
+
+public class FaceCreateDialogFragment extends DialogFragment {
+ public static interface OnFaceCreateRequested {
+ public void
+ createFace(String faceUri);
+ }
+
+ public static FaceCreateDialogFragment
+ newInstance() {
+ return new FaceCreateDialogFragment();
+ }
+
+ @NonNull @Override
+ public Dialog
+ onCreateDialog(@Nullable Bundle savedInstanceState) {
+ AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+ LayoutInflater inflater = getActivity().getLayoutInflater();
+ builder
+ .setView(inflater.inflate(R.layout.create_face, null))
+ .setPositiveButton(R.string.face_add_dialog_create_face, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int id)
+ {
+ EditText uriBox = (EditText) getDialog().findViewById(R.id.faceUri);
+ String uri = uriBox.getText().toString();
+ ((OnFaceCreateRequested)getTargetFragment()).createFace(uri);
+ }
+ })
+ .setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id)
+ {
+ FaceCreateDialogFragment.this.getDialog().cancel();
+ }
+ })
+ ;
+
+ Dialog faceCreateDialog = builder.create();
+ faceCreateDialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
+ return faceCreateDialog;
+ }
+}
diff --git a/app/src/main/java/net/named_data/nfd/FaceListActivity.java b/app/src/main/java/net/named_data/nfd/FaceListActivity.java
deleted file mode 100644
index 3ca5042..0000000
--- a/app/src/main/java/net/named_data/nfd/FaceListActivity.java
+++ /dev/null
@@ -1,390 +0,0 @@
-/* -*- Mode:jde; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (c) 2015 Regents of the University of California
- *
- * This file is part of NFD (Named Data Networking Forwarding Daemon) Android.
- * See AUTHORS.md for complete list of NFD Android authors and contributors.
- *
- * 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.
- *
- * 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.
- *
- * 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.Activity;
-import android.app.AlertDialog;
-import android.app.FragmentManager;
-import android.app.FragmentTransaction;
-import android.app.ListFragment;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.os.Bundle;
-import android.preference.PreferenceFragment;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.AdapterView;
-import android.widget.BaseAdapter;
-import android.widget.TextView;
-
-import com.intel.jndn.management.types.FacePersistency;
-import com.intel.jndn.management.types.FaceScope;
-import com.intel.jndn.management.types.FaceStatus;
-import com.intel.jndn.management.types.LinkType;
-
-import net.named_data.jndn.encoding.EncodingException;
-import net.named_data.jndn.util.Blob;
-import net.named_data.nfd.utils.NfdcAsyncTask;
-import net.named_data.nfd.utils.Nfdc;
-
-import org.joda.time.Period;
-import org.joda.time.format.PeriodFormat;
-import org.w3c.dom.Text;
-
-import java.nio.ByteBuffer;
-import java.util.LinkedList;
-import java.util.List;
-
-public class FaceListActivity extends Activity {
- @Override
- public void
- onCreate(Bundle savedInstanceState)
- {
- super.onCreate(savedInstanceState);
-
- FragmentManager fm = getFragmentManager();
- FragmentTransaction ft = fm.beginTransaction();
- if (fm.findFragmentById(android.R.id.content) == null) {
- ft.add(android.R.id.content, m_faceListFragment);
- } else {
- ft.replace(android.R.id.content, m_faceListFragment);
- }
- ft.commit();
- }
-
- public static class FaceListFragment extends ListFragment
- implements AdapterView.OnItemLongClickListener,
- AdapterView.OnItemClickListener {
- @Override
- public void onActivityCreated(Bundle savedInstanceState)
- {
- super.onActivityCreated(savedInstanceState);
-
- setListAdapter(new FaceListAdapter(getActivity()));
- getListView().setLongClickable(true);
-
- getListView().setOnItemLongClickListener(this);
- getListView().setOnItemClickListener(this);
-
- }
-
- @Override
- public boolean
- onItemLongClick(final AdapterView<?> parent, View view, final int position, long id)
- {
- final int faceId = (int)id;
- if (faceId < 256) {
- return false;
- }
-
- AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(getActivity());
- alertDialogBuilder
- .setMessage("Delete face " + String.valueOf(faceId) + "?")
- .setCancelable(false)
- .setPositiveButton("Yes", new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int id)
- {
- new NfdcAsyncTask(getActivity(),
- new NfdcAsyncTask.Task() {
- public String
- runTask() throws Exception
- {
- Nfdc nfdc = new Nfdc();
- nfdc.faceDestroy(faceId);
- nfdc.shutdown();
-
- getActivity().runOnUiThread(new Runnable() {
- @Override
- public void run()
- {
- ((FaceListAdapter) parent.getAdapter()).updateFaceList();
- }
- });
- return null;
- }
- }).execute();
- }
- })
- .setNegativeButton("No", new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int id)
- {
- dialog.cancel();
- }
- });
-
- AlertDialog alertDialog = alertDialogBuilder.create();
- alertDialog.show();
-
- return true;
- }
-
- @Override
- public void onItemClick(AdapterView<?> parent, View view, int position, long id)
- {
- FaceStatus s = (FaceStatus)getListAdapter().getItem(position);
- FaceStatusFragment fragment = new FaceStatusFragment();
- Bundle bundle = new Bundle();
- bundle.putByteArray("faceStatus", s.wireEncode().getImmutableArray());
- fragment.setArguments(bundle);
-
- getFragmentManager()
- .beginTransaction()
- .addToBackStack("FaceStatus")
- .replace(android.R.id.content, fragment)
- .commit();
- }
-
- private class FaceListAdapter extends BaseAdapter {
- public FaceListAdapter(Context context)
- {
- this.m_inflater = LayoutInflater.from(context);
- this.m_context = context;
-
- updateFaceList();
- }
-
- public void
- updateFaceList()
- {
- new NfdcAsyncTask(m_context,
- new NfdcAsyncTask.Task() {
- public String
- runTask() throws Exception
- {
- synchronized (m_facesLock) {
- Nfdc nfdc = new Nfdc();
- m_faces = nfdc.faceList();
- nfdc.shutdown();
- }
-
- getActivity().runOnUiThread(new Runnable() {
- @Override
- public void run()
- {
- notifyDataSetChanged();
- }
- });
- return null;
- }
- }).execute();
- }
-
- @Override
- public int
- getCount()
- {
- synchronized (m_facesLock) {
- if (m_faces == null)
- return 0;
- else
- return m_faces.size();
- }
- }
-
- @Override
- public Object
- getItem(int position)
- {
- synchronized (m_facesLock) {
- assert m_faces != null && position < m_faces.size();
- return m_faces.get(position);
- }
- }
-
- @Override
- public long
- getItemId(int position)
- {
- synchronized (m_facesLock) {
- assert m_faces != null && position < m_faces.size();
- return m_faces.get(position).getFaceId();
- }
- }
-
- @Override
- public View
- getView(int position, View convertView, ViewGroup parent)
- {
- if (convertView == null) {
- convertView = this.m_inflater.inflate(android.R.layout.simple_list_item_2, parent, false);
- }
-
- FaceStatus s;
- synchronized(m_facesLock) {
- s = m_faces.get(position);
- }
-
- ((TextView)convertView.findViewById(android.R.id.text2)).setText(String.valueOf(s.getFaceId()));
- ((TextView)convertView.findViewById(android.R.id.text1)).setText(s.getUri());
-
- return convertView;
- }
-
- /////////////////////////////////////////////////////////////////////////
- private LayoutInflater m_inflater;
- private Context m_context;
- private List<FaceStatus> m_faces;
- private final Object m_facesLock = new Object();
- }
- }
-
- ////////////////////////////////////////////////////////////////////////////////////////////////
-
- public static class FaceStatusFragment extends ListFragment {
-
- @Override
- public void onActivityCreated(Bundle savedInstanceState)
- {
- super.onActivityCreated(savedInstanceState);
-
- FaceStatus s = null;
- try {
- s = new FaceStatus();
- s.wireDecode(new Blob(getArguments().getByteArray("faceStatus")).buf());
- }
- catch (EncodingException e) {
- assert false;
- }
-
- m_faceStatus.add(new Item("Face ID", String.valueOf(s.getFaceId())));
- m_faceStatus.add(new Item("Local FaceUri", s.getLocalUri()));
- m_faceStatus.add(new Item("Remote FaceUri", s.getUri()));
- m_faceStatus.add(new Item("Expires in", s.getExpirationPeriod() < 0 ?
- "never" :
- PeriodFormat.getDefault().print(new Period(s.getExpirationPeriod()))));
- m_faceStatus.add(new Item("Face scope", getScope(s.getFaceScope())));
- m_faceStatus.add(new Item("Face persistency", getPersistency(s.getFacePersistency())));
- m_faceStatus.add(new Item("Link type", getLinkType(s.getLinkType())));
- m_faceStatus.add(new Item("In interests", String.valueOf(s.getInInterests())));
- m_faceStatus.add(new Item("In data", String.valueOf(s.getInDatas())));
- m_faceStatus.add(new Item("Out interests", String.valueOf(s.getOutInterests())));
- m_faceStatus.add(new Item("Out data", String.valueOf(s.getOutDatas())));
- m_faceStatus.add(new Item("In bytes", String.valueOf(s.getInBytes())));
- m_faceStatus.add(new Item("Out bytes", String.valueOf(s.getOutBytes())));
-
- setListAdapter(new FaceStatusAdapter(getActivity()));
- }
-
- private class FaceStatusAdapter extends BaseAdapter {
- public FaceStatusAdapter(Context context)
- {
- this.m_inflater = LayoutInflater.from(context);
- }
-
- @Override
- public int getCount()
- {
- return m_faceStatus.size();
- }
-
- @Override
- public Object getItem(int position)
- {
- return m_faceStatus.get(position);
- }
-
- @Override
- public long getItemId(int position)
- {
- return position;
- }
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent)
- {
- if (convertView == null) {
- convertView = m_inflater.inflate(R.layout.face_status_item, parent, false);
- }
-
- Item i = (Item)getItem(position);
- ((TextView)convertView.findViewById(R.id.title)).setText(i.getTitle());
- ((TextView)convertView.findViewById(R.id.value)).setText(i.getValue());
-
- return convertView;
- }
-
- /////////////////////////////////////////////////////////////////////////
- private LayoutInflater m_inflater;
- }
-
- private static class Item {
- public Item(String title, String value)
- {
- m_title = title;
- m_value = value;
- }
-
- public String getValue()
- {
- return m_value;
- }
-
- public void setValue(String value)
- {
- m_value = value;
- }
-
- public String getTitle()
- {
- return m_title;
- }
-
- public void setTitle(String title)
- {
- m_title = title;
- }
-
- /////////////////////////////////////////////////////////////////////////
- private String m_title;
- private String m_value;
- }
- private List<Item> m_faceStatus = new LinkedList<Item>();
- }
-
- /////////////////////////////////////////////////////////////////////////////
-
- private static String
- getScope(FaceScope scope)
- {
- assert scope.getNumericValue() < s_scopes.length;
- return s_scopes[scope.getNumericValue()];
- }
-
- private static String
- getPersistency(FacePersistency persistency)
- {
- assert persistency.getNumericValue() < s_persistencies.length;
- return s_persistencies[persistency.getNumericValue()];
- }
-
- private static String
- getLinkType(LinkType linkType)
- {
- assert linkType.getNumericValue() < s_linkTypes.length;
- return s_linkTypes[linkType.getNumericValue()];
- }
-
- private static final String[] s_scopes = {"Local", "Non-local"};
- private static final String[] s_persistencies = {"Persistent", "On-demand", "Permanent"};
- private static final String[] s_linkTypes = {"Point-to-point", "Multi-access"};
-
- private FaceListFragment m_faceListFragment = new FaceListFragment();
-}
diff --git a/app/src/main/java/net/named_data/nfd/FaceListFragment.java b/app/src/main/java/net/named_data/nfd/FaceListFragment.java
new file mode 100644
index 0000000..168fe85
--- /dev/null
+++ b/app/src/main/java/net/named_data/nfd/FaceListFragment.java
@@ -0,0 +1,528 @@
+/* -*- Mode:jde; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2015 Regents of the University of California
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon) Android.
+ * See AUTHORS.md for complete list of NFD Android authors and contributors.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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.annotation.SuppressLint;
+import android.app.Activity;
+import android.content.Context;
+import android.os.AsyncTask;
+import android.os.Bundle;
+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.Button;
+import android.widget.ListView;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.intel.jndn.management.types.FaceStatus;
+
+import net.named_data.jndn_xx.util.FaceUri;
+import net.named_data.nfd.utils.G;
+import net.named_data.nfd.utils.Nfdc;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class FaceListFragment extends ListFragment implements FaceCreateDialogFragment.OnFaceCreateRequested {
+
+ public static FaceListFragment
+ newInstance() {
+ return new FaceListFragment();
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ setListAdapter(new FaceListAdapter(getActivity()));
+ }
+
+ @Override
+ public View onCreateView(final LayoutInflater inflater,
+ ViewGroup container,
+ Bundle savedInstanceState)
+ {
+ @SuppressLint("InflateParams")
+ View v = inflater.inflate(R.layout.fragment_face_list, null);
+
+ // Get info unavailable view
+ m_faceListInfoUnavailableView = v.findViewById(R.id.face_list_info_unavailable);
+
+ // Get progress bar spinner view
+ m_reloadingListProgressBar
+ = (ProgressBar)v.findViewById(R.id.face_list_reloading_list_progress_bar);
+
+ // Set refresh button click listener
+ Button refreshFaceListButton = (Button)v.findViewById(R.id.face_list_refresh_button);
+ refreshFaceListButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ retrieveFaceList();
+ }
+ });
+
+ Button addFaceButton = (Button)v.findViewById(R.id.face_list_add_button);
+ addFaceButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view)
+ {
+ FaceCreateDialogFragment dialog = FaceCreateDialogFragment.newInstance();
+ dialog.setTargetFragment(FaceListFragment.this, 0);
+ dialog.show(getFragmentManager(), "FaceCreateFragment");
+ }
+ });
+
+ // Setup list view for deletion
+ ListView listView = (ListView)v.findViewById(android.R.id.list);
+ 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);
+ }
+ }
+
+ @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:
+ FaceListAdapter faceListAdapter = (FaceListAdapter)getListAdapter();
+ List<Integer> deleteFaceInfoList = new ArrayList<Integer>();
+
+ for (int i = faceListAdapter.getCount() - 1; i >= 0; i--) {
+ if (getListView().isItemChecked(i)) {
+ int faceId = faceListAdapter.getItem(i).getFaceId();
+ if (faceId < 256)
+ continue;
+ deleteFaceInfoList.add(faceListAdapter.getItem(i).getFaceId());
+ }
+ }
+
+ // Delete selected faceIds
+ m_faceDestroyAsyncTask = new FaceDestroyAsyncTask();
+ m_faceDestroyAsyncTask.execute(deleteFaceInfoList);
+
+ mode.finish();
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ @Override
+ public void onDestroyActionMode(ActionMode mode) {
+ }
+ });
+
+ return v;
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ startFaceListRetrievalTask();
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ stopFaceListRetrievalTask();
+
+ if (m_faceDestroyAsyncTask != null) {
+ m_faceDestroyAsyncTask.cancel(false);
+ m_faceDestroyAsyncTask = null;
+ }
+
+ if (m_faceCreateAsyncTask != null) {
+ m_faceCreateAsyncTask.cancel(false);
+ m_faceCreateAsyncTask = null;
+ }
+ }
+
+ @Override
+ public void onAttach(Activity activity) {
+ super.onAttach(activity);
+ try {
+ m_callbacks = (Callbacks)activity;
+ } catch (Exception e) {
+ G.Log("Hosting activity must implement this fragment's callbacks: " + e);
+ }
+ }
+
+ @Override
+ public void onDetach() {
+ super.onDetach();
+ m_callbacks = null;
+ }
+
+ @Override
+ public void
+ onListItemClick(ListView l, View v, int position, long id) {
+ if (m_callbacks != null) {
+ FaceStatus faceStatus = (FaceStatus)l.getAdapter().getItem(position);
+ m_callbacks.onFaceItemSelected(faceStatus);
+ }
+ }
+
+ @Override
+ public void
+ createFace(String faceUri)
+ {
+ m_faceCreateAsyncTask = new FaceCreateAsyncTask(faceUri);
+ m_faceCreateAsyncTask.execute();
+ }
+
+ /////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Updates the underlying adapter with the given list of FaceStatus.
+ *
+ * Note: This method should only be called from the UI thread.
+ *
+ * @param list Update ListView with the given List<FaceStatus>
+ */
+ private void updateFaceList(List<FaceStatus> list) {
+ if (list == null) {
+ m_faceListInfoUnavailableView.setVisibility(View.VISIBLE);
+ return;
+ }
+
+ ((FaceListAdapter)getListAdapter()).updateList(list);
+ }
+
+ /**
+ * Convenience method that starts the AsyncTask that retrieves the
+ * list of available faces.
+ */
+ private void retrieveFaceList() {
+ // Update UI
+ m_faceListInfoUnavailableView.setVisibility(View.GONE);
+
+ // Stop if running; before starting the new Task
+ stopFaceListRetrievalTask();
+ startFaceListRetrievalTask();
+ }
+
+ /**
+ * Create a new AsyncTask for face list information retrieval.
+ */
+ private void startFaceListRetrievalTask() {
+ m_faceListAsyncTask = new FaceListAsyncTask();
+ m_faceListAsyncTask.execute();
+ }
+
+ /**
+ * Stops a previously started face retrieval AsyncTask.
+ */
+ private void stopFaceListRetrievalTask() {
+ if (m_faceListAsyncTask != null) {
+ m_faceListAsyncTask.cancel(false);
+ m_faceListAsyncTask = null;
+ }
+ }
+
+ /**
+ * Custom adapter for displaying face information in a ListView.
+ */
+ private static class FaceListAdapter extends BaseAdapter {
+ private FaceListAdapter(Context context) {
+ m_layoutInflater = LayoutInflater.from(context);
+ }
+
+ private void
+ updateList(List<FaceStatus> faces)
+ {
+ m_faces = faces;
+ notifyDataSetChanged();
+ }
+
+ @Override
+ public FaceStatus
+ getItem(int i)
+ {
+ assert m_faces != null;
+ return m_faces.get(i);
+ }
+
+ @Override
+ public long getItemId(int i)
+ {
+ assert m_faces != null;
+ return m_faces.get(i).getFaceId();
+ }
+
+ @Override
+ public int getCount()
+ {
+ return (m_faces != null) ? m_faces.size() : 0;
+ }
+
+ @SuppressLint("InflateParams")
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ FaceInfoHolder holder;
+
+ if (convertView == null) {
+ holder = new FaceInfoHolder();
+
+ convertView = m_layoutInflater.inflate(R.layout.list_item_face_status_item, null);
+ convertView.setTag(holder);
+
+ holder.m_faceUri = (TextView)convertView.findViewById(R.id.list_item_face_uri);
+ holder.m_faceId = (TextView)convertView.findViewById(R.id.list_item_face_id);
+ } else {
+ holder = (FaceInfoHolder)convertView.getTag();
+ }
+
+ FaceStatus info = getItem(position);
+ holder.m_faceUri.setText(info.getUri());
+ holder.m_faceId.setText(String.valueOf(info.getFaceId()));
+
+ return convertView;
+ }
+
+ private static class FaceInfoHolder {
+ private TextView m_faceUri;
+ private TextView m_faceId;
+ }
+
+ private final LayoutInflater m_layoutInflater;
+ private List<FaceStatus> m_faces;
+ }
+
+ /**
+ * AsyncTask that gets the list of faces from the running NFD.
+ */
+ private class FaceListAsyncTask extends AsyncTask<Void, Void, Pair<List<FaceStatus>, Exception>> {
+ @Override
+ protected void
+ onPreExecute() {
+ // Display progress bar
+ m_reloadingListProgressBar.setVisibility(View.VISIBLE);
+ }
+
+ @Override
+ protected Pair<List<FaceStatus>, Exception>
+ doInBackground(Void... params) {
+ Exception returnException = null;
+ Nfdc nfdc = new Nfdc();
+ List<FaceStatus> faceStatusList = null;
+ try {
+ faceStatusList = nfdc.faceList();
+ } catch (Exception e) {
+ returnException = e;
+ }
+ nfdc.shutdown();
+ return new Pair<>(faceStatusList, returnException);
+ }
+
+ @Override
+ protected void
+ onCancelled() {
+ // Remove progress bar
+ m_reloadingListProgressBar.setVisibility(View.GONE);
+
+ // Nothing to do here; No change in UI.
+ }
+
+ @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();
+ }
+
+ updateFaceList(result.first);
+ }
+ }
+
+ /**
+ * AsyncTask that destroys faces that are passed in as a list of FaceInfo.
+ */
+ private class FaceDestroyAsyncTask extends AsyncTask<List<Integer>, Void, Exception> {
+ @Override
+ protected void
+ onPreExecute() {
+ // Display progress bar
+ m_reloadingListProgressBar.setVisibility(View.VISIBLE);
+ }
+
+ @SafeVarargs
+ @Override
+ protected final Exception
+ doInBackground(List<Integer>... params) {
+ Exception retval = null;
+
+ Nfdc nfdc = new Nfdc();
+ try {
+ for (List<Integer> faces : params) {
+ for (int faceId : faces) {
+ nfdc.faceDestroy(faceId);
+ }
+ }
+ } catch (Exception e) {
+ retval = e;
+ }
+ nfdc.shutdown();
+
+ return retval;
+ }
+
+ @Override
+ protected void onCancelled() {
+ // Remove progress bar
+ m_reloadingListProgressBar.setVisibility(View.GONE);
+
+ // Nothing to do here; No change in UI.
+ }
+
+ @Override
+ protected void onPostExecute(Exception e) {
+ // Remove progress bar
+ m_reloadingListProgressBar.setVisibility(View.GONE);
+
+ if (e != null) {
+ Toast.makeText(getActivity(), "Error communicating with NFD (" + e.getMessage() + ")",
+ Toast.LENGTH_LONG).show();
+ }
+ else {
+ // Reload face list
+ retrieveFaceList();
+ }
+ }
+ }
+
+ private class FaceCreateAsyncTask extends AsyncTask<Void, Void, String> {
+ public FaceCreateAsyncTask(String faceUri)
+ {
+ m_faceUri = faceUri;
+ }
+
+ @Override
+ protected String
+ doInBackground(Void... params)
+ {
+ try {
+ Nfdc nfdc = new Nfdc();
+ int faceId = nfdc.faceCreate(m_faceUri);
+ nfdc.shutdown();
+ return "OK. Face id: " + String.valueOf(faceId);
+ }
+ catch (FaceUri.CanonizeError e) {
+ return "Error creating face (" + e.getMessage() + ")";
+ }
+ catch (FaceUri.Error e) {
+ return "Error creating face (" + e.getMessage() + ")";
+ }
+ catch (Exception e) {
+ return "Error communicating with NFD (" + e.getMessage() + ")";
+ }
+ }
+
+ @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 String m_faceUri;
+ }
+ /////////////////////////////////////////////////////////////////////////
+
+ public interface Callbacks {
+ /**
+ * This method is called when a face is selected and more
+ * information about the face should be presented to the user.
+ *
+ * @param faceStatus FaceStatus instance with information about the face
+ */
+ public void onFaceItemSelected(FaceStatus faceStatus);
+ }
+
+ /////////////////////////////////////////////////////////////////////////
+
+ /** Reference to the most recent AsyncTask that was created for listing faces */
+ private FaceListAsyncTask m_faceListAsyncTask;
+
+ /** Callback handler of the hosting activity */
+ private Callbacks m_callbacks;
+
+ /** Reference to the most recent AsyncTask that was created for destroying faces */
+ private FaceDestroyAsyncTask m_faceDestroyAsyncTask;
+
+ /** Reference to the most recent AsyncTask that was created for creating a face */
+ private FaceCreateAsyncTask m_faceCreateAsyncTask;
+
+ /** Reference to the view to be displayed when no information is available */
+ private View m_faceListInfoUnavailableView;
+
+ /** Progress bar spinner to display to user when destroying faces */
+ private ProgressBar m_reloadingListProgressBar;
+}
diff --git a/app/src/main/java/net/named_data/nfd/FaceStatusFragment.java b/app/src/main/java/net/named_data/nfd/FaceStatusFragment.java
new file mode 100644
index 0000000..13aa367
--- /dev/null
+++ b/app/src/main/java/net/named_data/nfd/FaceStatusFragment.java
@@ -0,0 +1,235 @@
+/* -*- Mode:jde; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2015 Regents of the University of California
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon) Android.
+ * See AUTHORS.md for complete list of NFD Android authors and contributors.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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.annotation.SuppressLint;
+import android.content.Context;
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.support.v4.app.ListFragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.TextView;
+
+import com.intel.jndn.management.types.FacePersistency;
+import com.intel.jndn.management.types.FaceScope;
+import com.intel.jndn.management.types.FaceStatus;
+import com.intel.jndn.management.types.LinkType;
+
+import net.named_data.jndn.encoding.EncodingException;
+import net.named_data.jndn.util.Blob;
+import net.named_data.nfd.utils.G;
+
+import org.joda.time.Period;
+import org.joda.time.format.PeriodFormat;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class FaceStatusFragment extends ListFragment {
+
+ /**
+ * Create a new instance of {@link net.named_data.nfd.FaceStatusFragment} with
+ * the given detail face information as a byte array object.
+ *
+ * Note:
+ * faceStatus.wireEncode().getImmutableArray()
+ * This byte array should be retrieved via a call to:
+ * {@link com.intel.jndn.management.types.FaceStatus#wireEncode()} for a
+ * {@link net.named_data.jndn.util.Blob} object. Subsequently, an
+ * immutable byte array can be retrieved via
+ * {@link net.named_data.jndn.util.Blob#getImmutableArray()}.
+ *
+ * @param faceStatus FaceStatus instance with information about the face
+ * @return Fragment instance of {@link net.named_data.nfd.FaceStatusFragment}
+ * that is ready for use by the hosting activity
+ */
+ public static FaceStatusFragment
+ newInstance(FaceStatus faceStatus) {
+ Bundle args = new Bundle();
+ args.putByteArray(EXTRA_FACE_INFORMATION, faceStatus.wireEncode().getImmutableArray());
+
+ FaceStatusFragment fragment = new FaceStatusFragment();
+ fragment.setArguments(args);
+
+ return fragment;
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ m_listItems = new ArrayList<>();
+
+ Resources res = getResources();
+ m_scopes = res.getStringArray(R.array.face_scopes);
+ m_linkTypes = res.getStringArray(R.array.face_link_types);
+ m_persistencies = res.getStringArray(R.array.face_persistency);
+
+ // Get face status information
+ FaceStatus faceStatus = new FaceStatus();
+ try {
+ byte [] args = getArguments().getByteArray(EXTRA_FACE_INFORMATION);
+ faceStatus.wireDecode(new Blob(args).buf());
+ } catch (EncodingException e) {
+ G.Log("EXTRA_FACE_INFORMATION: EncodingException: " + e);
+ }
+
+ // Creating list of items to be displayed
+ m_listItems.add(new ListItem("Face ID", String.valueOf(faceStatus.getFaceId())));
+ m_listItems.add(new ListItem("Local FaceUri", faceStatus.getLocalUri()));
+ m_listItems.add(new ListItem("Remote FaceUri", faceStatus.getUri()));
+ m_listItems.add(new ListItem("Expires in", faceStatus.getExpirationPeriod() < 0 ?
+ getString(R.string.expire_never):
+ PeriodFormat.getDefault().print(new Period(faceStatus.getExpirationPeriod()))));
+ m_listItems.add(new ListItem("Face scope", getScope(faceStatus.getFaceScope())));
+ m_listItems.add(new ListItem("Face persistency", getPersistency(faceStatus.getFacePersistency())));
+ m_listItems.add(new ListItem("Link type", getLinkType(faceStatus.getLinkType())));
+ m_listItems.add(new ListItem("In interests", String.valueOf(faceStatus.getInInterests())));
+ m_listItems.add(new ListItem("In data", String.valueOf(faceStatus.getInDatas())));
+ m_listItems.add(new ListItem("Out interests", String.valueOf(faceStatus.getOutInterests())));
+ m_listItems.add(new ListItem("Out data", String.valueOf(faceStatus.getOutDatas())));
+ m_listItems.add(new ListItem("In bytes", String.valueOf(faceStatus.getInBytes())));
+ m_listItems.add(new ListItem("Out bytes", String.valueOf(faceStatus.getOutBytes())));
+
+ m_faceStatusAdapter = new FaceStatusAdapter(getActivity(), m_listItems);
+ setListAdapter(m_faceStatusAdapter);
+ }
+
+ @SuppressLint("InflateParams")
+ @Override
+ public View onCreateView(LayoutInflater inflater,
+ @Nullable ViewGroup container,
+ @Nullable Bundle savedInstanceState)
+ {
+ return inflater.inflate(R.layout.fragment_face_detail, null);
+ }
+
+ /////////////////////////////////////////////////////////////////////////
+
+ private String
+ getScope(FaceScope scope)
+ {
+ return m_scopes[scope.getNumericValue()];
+ }
+
+ private String
+ getPersistency(FacePersistency persistency)
+ {
+ return m_persistencies[persistency.getNumericValue()];
+ }
+
+ private String
+ getLinkType(LinkType linkType)
+ {
+ return m_linkTypes[linkType.getNumericValue()];
+ }
+
+ /**
+ * Generic list item model for use in
+ * {@link net.named_data.nfd.FaceStatusFragment.FaceStatusAdapter}.
+ */
+ private static class ListItem {
+ public ListItem(String title, String value) {
+ m_title = title;
+ m_value = value;
+ }
+
+ public String getValue() {
+ return m_value;
+ }
+
+ public void setValue(String value) {
+ m_value = value;
+ }
+
+ public String getTitle() {
+ return m_title;
+ }
+
+ public void setTitle(String title) {
+ m_title = title;
+ }
+
+ private String m_title;
+ private String m_value;
+ }
+
+ /**
+ * Custom ListView adapter that displays face status information.
+ */
+ private static class FaceStatusAdapter extends ArrayAdapter<ListItem> {
+ private FaceStatusAdapter(Context context, List<ListItem> objects) {
+ super(context, 0, objects);
+ m_layoutInflater = LayoutInflater.from(context);
+ }
+
+ @SuppressLint("InflateParams")
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ ListItemHolder holder;
+ if (convertView == null) {
+ holder = new ListItemHolder();
+
+ convertView = m_layoutInflater.inflate(R.layout.list_item_face_generic_item, null);
+ convertView.setTag(holder);
+
+ holder.m_title = (TextView)convertView.findViewById(R.id.list_item_generic_title);
+ holder.m_value = (TextView)convertView.findViewById(R.id.list_item_generic_value);
+ } else {
+ holder = (ListItemHolder)convertView.getTag();
+ }
+
+ ListItem info = getItem(position);
+ holder.m_title.setText(info.getTitle());
+ holder.m_value.setText(info.getValue());
+
+ return convertView;
+ }
+
+ private static class ListItemHolder {
+ private TextView m_title;
+ private TextView m_value;
+ }
+
+ private final LayoutInflater m_layoutInflater;
+ }
+
+ /////////////////////////////////////////////////////////////////////////
+
+ /** Bundle argument key for face information byte array */
+ private static final String EXTRA_FACE_INFORMATION
+ = "net.named_data.nfd.face_detail_fragment_face_id";
+
+ /**
+ * List items to be displayed; Used when creating
+ * {@link net.named_data.nfd.FaceStatusFragment.FaceStatusAdapter}
+ */
+ private ArrayList<ListItem> m_listItems;
+
+ /** Reference to custom {@link net.named_data.nfd.FaceStatusFragment.FaceStatusAdapter} */
+ private FaceStatusAdapter m_faceStatusAdapter;
+
+ private String[] m_scopes;
+ private String[] m_persistencies;
+ private String[] m_linkTypes;
+}
diff --git a/app/src/main/java/net/named_data/nfd/LogcatActivity.java b/app/src/main/java/net/named_data/nfd/LogcatFragment.java
similarity index 66%
rename from app/src/main/java/net/named_data/nfd/LogcatActivity.java
rename to app/src/main/java/net/named_data/nfd/LogcatFragment.java
index de5b039..ed4b1e8 100644
--- a/app/src/main/java/net/named_data/nfd/LogcatActivity.java
+++ b/app/src/main/java/net/named_data/nfd/LogcatFragment.java
@@ -19,11 +19,14 @@
package net.named_data.nfd;
-import android.content.Intent;
+import android.annotation.SuppressLint;
+import android.app.Activity;
import android.os.Bundle;
-import android.support.v7.app.ActionBarActivity;
+import android.support.annotation.Nullable;
+import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.Menu;
+import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
@@ -32,7 +35,6 @@
import android.widget.TextView;
import net.named_data.nfd.utils.G;
-import net.named_data.nfd.utils.LogcatTags;
import java.io.BufferedReader;
import java.io.IOException;
@@ -40,55 +42,91 @@
import java.util.ArrayList;
/**
- * Display of NfdService's logcat output for easy debugging
+ * Logcat fragment that houses the output of LogCat in a ListView for viewing.
+ *
+ * The ListView is backed by a {@link net.named_data.nfd.LogcatFragment.LogListAdapter}
+ * that that limits the number of logs that are being displayed to the user. This
+ * prevents the ListView from growing indeterminately. This maximum number of
+ * log lines that is allowed to be displayed is set by
+ * {@link net.named_data.nfd.LogcatFragment#s_logMaxLines}.
+ *
*/
-public class LogcatActivity extends ActionBarActivity {
+public class LogcatFragment extends Fragment {
+
+ public static Fragment newInstance() {
+ return new LogcatFragment();
+ }
@Override
- public boolean onCreateOptionsMenu(Menu menu) {
- getMenuInflater().inflate(R.menu.menu_log, menu);
- return true;
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setHasOptionsMenu(true);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater,
+ @Nullable ViewGroup container,
+ @Nullable Bundle savedInstanceState) {
+ @SuppressLint("InflateParams")
+ View v = inflater.inflate(R.layout.fragment_logcat_output, null);
+
+ // Get UI Elements
+ m_logListView = (ListView) v.findViewById(R.id.log_output);
+ m_logListAdapter = new LogListAdapter(inflater, s_logMaxLines);
+ m_logListView.setAdapter(m_logListAdapter);
+
+ return v;
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ startLogging();
+ G.Log("LogcatFragment(): onResume()");
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ stopLogging();
+ G.Log("LogcatFragment(): onPause()");
+ }
+
+ @Override
+ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ super.onCreateOptionsMenu(menu, inflater);
+ inflater.inflate(R.menu.menu_log, menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
- case R.id.action_log_settings:
- startActivity(new Intent(this, LogcatSettingsActivity.class));
- return true;
- default:
- return super.onOptionsItemSelected(item);
+ case R.id.action_log_settings:
+ m_callbacks.onDisplayLogcatSettings();
+ return true;
+ default:
+ return super.onOptionsItemSelected(item);
}
}
@Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_log);
-
- // Get UI Elements
- m_logListView = (ListView) findViewById(R.id.log_output);
- m_logListAdapter = new LogListAdapter(getLayoutInflater(), s_logMaxLines);
- m_logListView.setAdapter(m_logListAdapter);
+ public void onAttach(Activity activity) {
+ super.onAttach(activity);
+ try {
+ m_callbacks = (Callbacks) activity;
+ } catch (ClassCastException e) {
+ G.Log("Hosting activity must implement callback.");
+ throw e;
+ }
}
@Override
- protected void onResume() {
- super.onResume();
- startLogging();
+ public void onDetach() {
+ super.onDetach();
+ m_callbacks = null;
}
- @Override
- protected void onPause() {
- super.onPause();
- stopLogging();
- }
-
- @Override
- protected void onDestroy() {
- super.onDestroy();
- G.Log("LogActivity::onDestroy()");
- }
+ //////////////////////////////////////////////////////////////////////////////
/**
* Starts logging by spawning a new thread to capture logs.
@@ -97,7 +135,7 @@
// Clear output, update UI and get tag arguments
clearLogOutput();
appendLogText(getString(R.string.loading_logger));
- m_tagArguments = LogcatTags.getTags(this);
+ m_tagArguments = LogcatSettingsManager.get(getActivity()).getTags();
new Thread(){
@Override
@@ -149,19 +187,19 @@
*/
// Build command for execution
String cmd = String.format("%s -v time %s *:S",
- "logcat",
- m_tagArguments);
+ "logcat",
+ m_tagArguments);
G.Log("LogCat Command: " + cmd);
m_logProcess = Runtime.getRuntime().exec(cmd);
BufferedReader in = new BufferedReader(
- new InputStreamReader(m_logProcess.getInputStream()));
+ new InputStreamReader(m_logProcess.getInputStream()));
String line;
while ((line = in.readLine()) != null) {
final String message = line;
- runOnUiThread(new Runnable() {
+ getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
appendLogText(message);
@@ -171,13 +209,13 @@
// Wait for process to join this thread
m_logProcess.waitFor();
- } catch (IOException e) {
- G.Log("captureLog(): " + e);
- } catch (InterruptedException e) {
+ } catch (IOException | InterruptedException e) {
G.Log("captureLog(): " + e);
}
}
+ //////////////////////////////////////////////////////////////////////////////
+
/**
* Custom LogListAdapter to limit the number of log lines that
* is being stored and displayed.
@@ -193,7 +231,7 @@
* the ListView for this adapter.
*/
public LogListAdapter(LayoutInflater layoutInflater, int maxLines) {
- m_data = new ArrayList<String>();
+ m_data = new ArrayList<>();
m_layoutInflater = layoutInflater;
m_maxLines = maxLines;
}
@@ -237,6 +275,7 @@
return position;
}
+ @SuppressLint("InflateParams")
@Override
public View getView(int position, View convertView, ViewGroup parent) {
LogEntryViewHolder holder;
@@ -244,7 +283,7 @@
if (convertView == null) {
holder = new LogEntryViewHolder();
- convertView = m_layoutInflater.inflate(R.layout.log_item, null);
+ convertView = m_layoutInflater.inflate(R.layout.list_item_log, null);
convertView.setTag(holder);
holder.logLineTextView = (TextView) convertView.findViewById(R.id.log_line);
@@ -257,13 +296,13 @@
}
/** Underlying message data store for log messages*/
- private ArrayList<String> m_data;
+ private final ArrayList<String> m_data;
/** Layout inflater for inflating views */
- private LayoutInflater m_layoutInflater;
+ private final LayoutInflater m_layoutInflater;
/** Maximum number of log lines to display */
- private int m_maxLines;
+ private final int m_maxLines;
}
/**
@@ -273,7 +312,15 @@
public TextView logLineTextView;
}
- /** Maximum number of log lines to be displayed */
+ //////////////////////////////////////////////////////////////////////////////
+
+ public interface Callbacks {
+ void onDisplayLogcatSettings();
+ }
+
+ //////////////////////////////////////////////////////////////////////////////
+
+ /** Maximum number of log lines to be displayed by the backing adapter of the ListView */
private static final int s_logMaxLines = 380;
/** Process in which logcat is running in */
@@ -287,4 +334,7 @@
/** Tag argument to logcat */
private String m_tagArguments;
+
+ /** Callback reference to hosting activity */
+ private Callbacks m_callbacks;
}
diff --git a/app/src/main/java/net/named_data/nfd/LogcatSettingItem.java b/app/src/main/java/net/named_data/nfd/LogcatSettingItem.java
new file mode 100644
index 0000000..d5a3fff
--- /dev/null
+++ b/app/src/main/java/net/named_data/nfd/LogcatSettingItem.java
@@ -0,0 +1,61 @@
+/* -*- Mode:jde; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2015 Regents of the University of California
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon) Android.
+ * See AUTHORS.md for complete list of NFD Android authors and contributors.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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;
+
+/**
+ * Logcat setting item that contains information about the tag name
+ * in the m_logTag field and log level in the m_logLevel field.
+ */
+public class LogcatSettingItem {
+
+ public LogcatSettingItem(String logTag, String logLevel) {
+ m_logTag = logTag;
+ m_logLevel = logLevel;
+ }
+
+ public String getLogTag() {
+ return m_logTag;
+ }
+
+ public void setLogTag(String logTag) {
+ m_logTag = logTag;
+ }
+
+ public String getLogLevel() {
+ return m_logLevel;
+ }
+
+ public void setLogLevel(String logLevel) {
+ m_logLevel = logLevel;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("%s: %s", m_logTag, m_logLevel);
+ }
+
+ //////////////////////////////////////////////////////////////////////////////
+
+ /** Log tag that logcat should monitor */
+ private String m_logTag;
+
+ /** Log level (aka priority level) that logcat should use for this log tag */
+ private String m_logLevel;
+}
diff --git a/app/src/main/java/net/named_data/nfd/LogcatSettingsActivity.java b/app/src/main/java/net/named_data/nfd/LogcatSettingsActivity.java
deleted file mode 100644
index b8b0f13..0000000
--- a/app/src/main/java/net/named_data/nfd/LogcatSettingsActivity.java
+++ /dev/null
@@ -1,250 +0,0 @@
-/* -*- Mode:jde; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (c) 2015 Regents of the University of California
- *
- * This file is part of NFD (Named Data Networking Forwarding Daemon) Android.
- * See AUTHORS.md for complete list of NFD Android authors and contributors.
- *
- * 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.
- *
- * 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.
- *
- * 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.Activity;
-import android.os.Bundle;
-import android.preference.ListPreference;
-import android.preference.Preference;
-import android.preference.PreferenceFragment;
-import android.preference.PreferenceGroup;
-import android.preference.PreferenceManager;
-import android.preference.PreferenceScreen;
-
-import net.named_data.nfd.utils.LogcatTags;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class LogcatSettingsActivity extends Activity {
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- getFragmentManager().
- beginTransaction().
- replace(android.R.id.content, new NfdLogSettingsFragment()).
- commit();
- }
-
- public static class NfdLogSettingsFragment extends PreferenceFragment {
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- // Load the preferences from an XML resource
- addPreferencesFromResource(R.xml.pref_nfd_log);
-
- PreferenceScreen preferenceScreen = getPreferenceScreen();
-
- //// NOTE: This section of code demonstrates how a preference can
- //// be added programmatically.
- ////
- // Creating and inserting a preference programmatically
- // Preference customPreference = preferenceScreen.
- // findPreference(getString(R.string.pref_category_title_tags_key));
- // if (customPreference instanceof PreferenceCategory) {
- // ListPreference listPreference = new ListPreference(getActivity());
- // listPreference.setKey("NFDTest_Key");
- // listPreference.setTitle("NFDTest");
- // listPreference.setDefaultValue("I");
- // listPreference.setNegativeButtonText(null);
- // listPreference.setDialogTitle("NFDTest");
-
- // String [] keys = getResources().getStringArray(R.array.pref_log_levels);
- // String [] values = getResources().getStringArray(R.array.pref_log_level_values);
-
- // listPreference.setEntries(keys);
- // listPreference.setEntryValues(values);
-
- // ((PreferenceCategory) customPreference).addPreference(listPreference);
- // }
-
- // Collect all Preference in the hierarchy
- m_tagListPreferences = new ArrayList<ListPreference>();
- extractPreferences(m_tagListPreferences,
- (PreferenceGroup) preferenceScreen.
- findPreference(getString(R.string.pref_category_title_tags_key)));
-
- // Set all preference setting
- m_resetPreference = preferenceScreen.
- findPreference(getString(R.string.pref_tags_log_level_key));
- }
-
- @Override
- public void onResume() {
- super.onResume();
- registerListeners();
- }
-
- @Override
- public void onPause() {
- super.onPause();
- unregisterPreferenceListeners();
- saveTagArguments();
- }
-
- /**
- * Convenience method to register preference listeners.
- */
- private void registerListeners() {
- for (Preference p : m_tagListPreferences) {
- if (p instanceof ListPreference) {
- registerPreferenceListener(p);
- }
- }
-
- m_resetPreference.setOnPreferenceChangeListener(m_setAllPreferenceChangeListener);
- }
-
- /**
- * Convenience method to unregister preference listeners.
- */
- private void unregisterPreferenceListeners() {
- for (Preference p : m_tagListPreferences) {
- if (p instanceof ListPreference) {
- unregisterPreferenceListener(p);
- }
- }
-
- m_resetPreference.setOnPreferenceChangeListener(null);
- }
-
- /**
- * Register preference listener and fire an update.
- *
- * @param preference Preference to register listener.
- */
- private void registerPreferenceListener(Preference preference) {
- // Attach listener
- preference.setOnPreferenceChangeListener(m_tagPreferenceChangeListener);
-
- // Trigger update
- m_tagPreferenceChangeListener.onPreferenceChange(preference,
- PreferenceManager.
- getDefaultSharedPreferences(preference.getContext()).
- getString(preference.getKey(), ""));
- }
-
- /**
- * Unregister preference listener for the given preference.
- *
- * @param preference Preference to unregister listener.
- */
- private void unregisterPreferenceListener(Preference preference) {
- // Remove listener
- preference.setOnPreferenceChangeListener(null);
- }
-
- /**
- * Convenience method that extracts all list preferences within a hierarchy
- * recursively.
- *
- * @param list List to add preference to
- * @param preferenceGroup Root preference group to begin search from
- */
- private void extractPreferences(List<ListPreference> list, PreferenceGroup preferenceGroup) {
- for (int i = 0; i < preferenceGroup.getPreferenceCount(); i++) {
- final Preference preference = preferenceGroup.getPreference(i);
-
- if (preference instanceof ListPreference) {
- list.add((ListPreference) preference);
- } else if (preference instanceof PreferenceGroup) {
- extractPreferences(list, (PreferenceGroup) preference);
- }
- }
- }
-
- /**
- * Save tag arguments for quick retrieval.
- */
- private void saveTagArguments() {
- LogcatTags.TagBuilder tagBuilder = LogcatTags.TagBuilder.getTagBuilder();
-
- for (Preference p : m_tagListPreferences) {
- if (p instanceof ListPreference) {
- ListPreference listPreference = (ListPreference) p;
- tagBuilder.addTag(listPreference.getTitle(), listPreference.getValue());
- }
- }
-
- LogcatTags.saveTags(getActivity(), tagBuilder.generateTagString());
- }
-
- /**
- * Convenience method to change all tags' log level to the
- * given logLevel.
- *
- * @param logLevel Target log level to set to.
- */
- private void setAllTagPreferences(String logLevel) {
- for (ListPreference preference : m_tagListPreferences) {
- preference.setValue(logLevel);
- m_tagPreferenceChangeListener.onPreferenceChange(preference, logLevel);
- }
- }
-
- /** List of preferences for registering handlers */
- private List<ListPreference> m_tagListPreferences;
-
- /** Reset log level preference */
- private Preference m_resetPreference;
-
- /**
- * Change listener that updates the summary text of the tag preferences.
- */
- private Preference.OnPreferenceChangeListener m_tagPreferenceChangeListener
- = new Preference.OnPreferenceChangeListener() {
- @Override
- public boolean onPreferenceChange(Preference preference, Object value) {
- // Get value of preference setting as a String
- String displayString = value.toString();
-
- // Deal with ListPreference
- if (preference instanceof ListPreference) {
- // Get display value
- ListPreference listPreference = (ListPreference) preference;
- int offset = listPreference.findIndexOfValue(displayString);
- displayString = (offset != -1) ?
- (String) listPreference.getEntries()[offset] :
- null;
- }
-
- // Update UI
- preference.setSummary(displayString);
- return true;
- }
- };
-
- /**
- * Change listener that resets all preference tags' log levels.
- */
- private Preference.OnPreferenceChangeListener m_setAllPreferenceChangeListener
- = new Preference.OnPreferenceChangeListener() {
- @Override
- public boolean onPreferenceChange(Preference preference, Object value) {
- setAllTagPreferences(value.toString());
- return true;
- }
- };
- }
-}
diff --git a/app/src/main/java/net/named_data/nfd/LogcatSettingsFragment.java b/app/src/main/java/net/named_data/nfd/LogcatSettingsFragment.java
new file mode 100644
index 0000000..805a568
--- /dev/null
+++ b/app/src/main/java/net/named_data/nfd/LogcatSettingsFragment.java
@@ -0,0 +1,341 @@
+/* -*- Mode:jde; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2015 Regents of the University of California
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon) Android.
+ * See AUTHORS.md for complete list of NFD Android authors and contributors.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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.annotation.SuppressLint;
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.v4.app.DialogFragment;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.app.ListFragment;
+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.ArrayAdapter;
+import android.widget.Button;
+import android.widget.ListView;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+
+public class LogcatSettingsFragment extends ListFragment {
+
+ public static LogcatSettingsFragment newInstance() {
+ return new LogcatSettingsFragment();
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ m_logcatSettingsManager = LogcatSettingsManager.get(getActivity());
+ m_logcatSettingItems = m_logcatSettingsManager.getLogcatSettingItems();
+
+ ArrayAdapter<LogcatSettingItem> adapter
+ = new LogcatSettingsAdapter(getActivity(), m_logcatSettingItems);
+
+ setListAdapter(adapter);
+ setRetainInstance(true);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater,
+ ViewGroup container,
+ Bundle savedInstanceState) {
+ @SuppressLint("InflateParams")
+ View v = inflater.inflate(R.layout.fragment_logcat_tags_list, null);
+
+ // Set resetLogLevelButton listener
+ Button resetLogLevelButton = (Button) v.findViewById(R.id.logcat_reset_loglevel_defaults);
+ resetLogLevelButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ FragmentManager fm = getActivity().getSupportFragmentManager();
+ ResetLogLevelDialog dialog
+ = ResetLogLevelDialog.newInstance(getString(R.string.reset_log_level_dialog_title));
+ dialog.setTargetFragment(LogcatSettingsFragment.this, REQUEST_CODE_DIALOG_RESET_ALL_LOG_LEVELS);
+ dialog.show(fm, DIALOG_RESET_ALL_LOG_LEVELS_TAG);
+ }
+ });
+
+ // Register context listener
+ ListView listView = (ListView) v.findViewById(android.R.id.list);
+ listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
+ listView.setMultiChoiceModeListener(new AbsListView.MultiChoiceModeListener() {
+ @Override
+ public void onItemCheckedStateChanged(ActionMode mode,
+ int position,
+ long id,
+ boolean checked)
+ {
+ // Nothing to do here
+ }
+
+ @Override
+ public boolean onCreateActionMode(ActionMode mode, Menu menu) {
+ MenuInflater inflater = mode.getMenuInflater();
+ inflater.inflate(R.menu.menu_logcat_settings_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_setting_item:
+ // TODO: Delete log item tag
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ @Override
+ public void onDestroyActionMode(ActionMode mode) {
+ // Nothing to do here
+ }
+ });
+
+ return v;
+ }
+
+ @Override
+ public void onListItemClick(ListView l, View v, int position, long id) {
+ final String logTag = m_logcatSettingItems.get(position).getLogTag();
+
+ final FragmentManager fm = getActivity().getSupportFragmentManager();
+ final ResetLogLevelDialog dialog = ResetLogLevelDialog.newInstance(logTag, position);
+
+ dialog.setTargetFragment(LogcatSettingsFragment.this, REQUEST_CODE_DIALOG_SET_LOG_LEVEL);
+ dialog.show(fm, DIALOG_SET_LOG_LEVEL_TAG);
+ }
+
+ @Override
+ public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ if (resultCode != Activity.RESULT_OK) {
+ return;
+ }
+
+ String newLogLevel;
+ switch (requestCode) {
+ case REQUEST_CODE_DIALOG_RESET_ALL_LOG_LEVELS:
+ newLogLevel = data.getStringExtra(ResetLogLevelDialog.EXTRA_RESET_LOG_LEVEL_VALUE);
+
+ // Update settings
+ for (LogcatSettingItem item : m_logcatSettingItems) {
+ item.setLogLevel(newLogLevel);
+ }
+
+ // Update UI
+ updateListUI();
+
+ // Save setting items
+ m_logcatSettingsManager.saveSettingItems();
+ break;
+ case REQUEST_CODE_DIALOG_SET_LOG_LEVEL:
+ newLogLevel = data.getStringExtra(ResetLogLevelDialog.EXTRA_RESET_LOG_LEVEL_VALUE);
+ final int listPosition
+ = data.getIntExtra(ResetLogLevelDialog.EXTRA_LOG_ITEM_LIST_POSITION, -1);
+
+ if (listPosition != -1) {
+ m_logcatSettingItems.get(listPosition).setLogLevel(newLogLevel);
+
+ // Update UI
+ updateListUI();
+
+ // Save setting items
+ m_logcatSettingsManager.saveSettingItems();
+ }
+ break;
+ }
+ }
+
+ /**
+ * Convenience method that updates the UI by notifying the backing list adapter
+ * that changes has been made to the underlying data set.
+ */
+ private void updateListUI() {
+ ((LogcatSettingsAdapter) getListAdapter()).notifyDataSetChanged();
+ }
+
+ //////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Adapter for use by thi ListFragment that display a list of LogcatSettingItem.
+ */
+ private static class LogcatSettingsAdapter extends ArrayAdapter<LogcatSettingItem> {
+
+ public LogcatSettingsAdapter(Context context, ArrayList<LogcatSettingItem> objects) {
+ super(context, 0, objects);
+ m_layoutInflater = LayoutInflater.from(context);
+ }
+
+ @SuppressLint("InflateParams")
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ SettingItemHolder holder;
+
+ if (convertView == null) {
+ holder = new SettingItemHolder();
+
+ convertView = m_layoutInflater.inflate(R.layout.list_item_setting_item, null);
+ convertView.setTag(holder);
+
+ holder.m_logTag = (TextView) convertView.findViewById(R.id.list_item_log_tag);
+ holder.m_logLevel = (TextView) convertView.findViewById(R.id.list_item_setting_log_level);
+ } else {
+ holder = (SettingItemHolder) convertView.getTag();
+ }
+
+ LogcatSettingItem item = getItem(position);
+ holder.m_logTag.setText(item.getLogTag());
+ holder.m_logLevel.setText(item.getLogLevel());
+
+ return convertView;
+ }
+
+ private static class SettingItemHolder {
+ private TextView m_logTag;
+ private TextView m_logLevel;
+ }
+
+ private final LayoutInflater m_layoutInflater;
+ }
+
+ /**
+ * Convenient dialog fragment that prompts for the log level value
+ * to reset all tags to.
+ */
+ public static class ResetLogLevelDialog extends DialogFragment {
+
+ public static ResetLogLevelDialog newInstance(String dialogTitle) {
+ return newInstance(dialogTitle, -1);
+ }
+
+ public static ResetLogLevelDialog newInstance(String dialogTitle, int listPosition) {
+ final Bundle args = new Bundle();
+ args.putSerializable(BUNDLE_KEY_DIALOG_TITLE, dialogTitle);
+
+ if (listPosition != -1) {
+ args.putSerializable(BUNDLE_KEY_DIALOG_LIST_POSITION, listPosition);
+ }
+
+ final ResetLogLevelDialog fragment = new ResetLogLevelDialog();
+ fragment.setArguments(args);
+
+ return fragment;
+ }
+
+ @NonNull
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ final String [] logLevelValues
+ = getResources().getStringArray(R.array.reset_log_level_values);
+
+ final String dialogTitle = getArguments().getString(BUNDLE_KEY_DIALOG_TITLE);
+
+ return new AlertDialog.Builder(getActivity())
+ .setTitle(dialogTitle)
+ .setItems(
+ logLevelValues,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ sendResult(Activity.RESULT_OK, logLevelValues[which]);
+ }
+ })
+ .create();
+ }
+
+ /**
+ * Convenient method to send data back to the fragment that presents this
+ * dialog.
+ *
+ * @param resultCode Result code to be passed back
+ * @param logLevelValue Log level value to be passed back
+ */
+ private void sendResult(int resultCode, String logLevelValue) {
+ if (getTargetFragment() == null) {
+ return;
+ }
+
+ // Create intent
+ Intent intent = new Intent();
+ intent.putExtra(EXTRA_RESET_LOG_LEVEL_VALUE, logLevelValue);
+
+ // Fill item position if present
+ final int logItemPosition = getArguments().getInt(BUNDLE_KEY_DIALOG_LIST_POSITION, -1);
+ if (logItemPosition != -1) {
+ intent.putExtra(EXTRA_LOG_ITEM_LIST_POSITION, logItemPosition);
+ }
+
+ // Send results
+ getTargetFragment().onActivityResult(getTargetRequestCode(), resultCode, intent);
+ }
+
+ /** Unique extra name to be used */
+ public static final String EXTRA_RESET_LOG_LEVEL_VALUE
+ = "net.named_data.nfd.reset_log_level_value";
+
+ public static final String EXTRA_LOG_ITEM_LIST_POSITION
+ = "net.named_data.nfd.log_item_list_position";
+
+ private static final String BUNDLE_KEY_DIALOG_TITLE
+ = "BUNDLE_KEY_DIALOG_TITLE";
+
+ private static final String BUNDLE_KEY_DIALOG_LIST_POSITION
+ = "BUNDLE_KEY_DIALOG_LIST_POSITION";
+ }
+
+ //////////////////////////////////////////////////////////////////////////////
+
+ /** Array list that contains all the tags that are logged */
+ private ArrayList<LogcatSettingItem> m_logcatSettingItems;
+
+ /** Reference to the currently used LogcatSettingsManager */
+ private LogcatSettingsManager m_logcatSettingsManager;
+
+ /** Request code for dialog that gets the new log level for all tags */
+ private static final int REQUEST_CODE_DIALOG_RESET_ALL_LOG_LEVELS = 1;
+
+ /** Request code for dialog that gets the new log level for a single tag */
+ private static final int REQUEST_CODE_DIALOG_SET_LOG_LEVEL = 2;
+
+ /** Unique tag that identifies dialog fragment in the fragment manager */
+ private static final String DIALOG_RESET_ALL_LOG_LEVELS_TAG = "ResetAllLogLevelDialog";
+
+ /** Unique tag that identifies dialog fragment in the fragment manager */
+ private static final String DIALOG_SET_LOG_LEVEL_TAG = "SetLogLevelDialog";
+}
diff --git a/app/src/main/java/net/named_data/nfd/LogcatSettingsManager.java b/app/src/main/java/net/named_data/nfd/LogcatSettingsManager.java
new file mode 100644
index 0000000..e6bffcb
--- /dev/null
+++ b/app/src/main/java/net/named_data/nfd/LogcatSettingsManager.java
@@ -0,0 +1,391 @@
+/* -*- Mode:jde; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2015 Regents of the University of California
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon) Android.
+ * See AUTHORS.md for complete list of NFD Android authors and contributors.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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.content.Context;
+import android.text.TextUtils;
+
+import net.named_data.nfd.utils.G;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.json.JSONTokener;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * Manager that controls the loading and saving of tags that are being logged.
+ */
+public class LogcatSettingsManager {
+
+ private LogcatSettingsManager(Context context) {
+ m_context = context;
+ m_logcatSettingItems = new ArrayList<>();
+ m_logLevelMap = new HashMap<>();
+ m_logcatTagsJSONSerializer = new LogcatTagsJSONSerializer(context, NFD_LOGCAT_TAGS_FILENAME);
+
+ // Populate log level map
+ loadLogLevelMap();
+
+ // Check if previous tags setting exists; otherwise load defaults
+ if (m_logcatTagsJSONSerializer.logcatTagsFileExists()) {
+ loadSettingItems();
+ } else {
+ loadDefaultSettingItems();
+ }
+
+ // Save setting items to file
+ saveSettingItems();
+
+ // Sort log tag name lexicographically
+ Collections.sort(m_logcatSettingItems, new Comparator<LogcatSettingItem>() {
+ @Override
+ public int compare(LogcatSettingItem lhs, LogcatSettingItem rhs) {
+ return lhs.getLogTag().compareTo(rhs.getLogTag());
+ }
+ });
+ }
+
+ /**
+ * Gets the singleton logcat settings manager.
+ *
+ * @param context Current application context
+ * @return The singleton settings manager
+ */
+ public static LogcatSettingsManager get(Context context) {
+ if (s_logcatSettingsManager == null) {
+ s_logcatSettingsManager = new LogcatSettingsManager(context.getApplicationContext());
+ }
+ return s_logcatSettingsManager;
+ }
+
+ /**
+ * Return the current working copy of setting items that are managed by the
+ * settings manager.
+ *
+ * @return Current setting items that are loaded
+ */
+ public ArrayList<LogcatSettingItem> getLogcatSettingItems() {
+ return m_logcatSettingItems;
+ }
+
+ /**
+ * Generate a string representing all the tags to be filtered by logcat
+ * and the relevant log levels.
+ *
+ * An example of a string returned by this method is:
+ *
+ * <pre>
+ * NFDService:S Strategy:S TcpChannel:S TcpFactory:S TcpLocalFace:S UdpFactory:S *:S
+ * </pre>
+ *
+ * @return String representation of the tags and their relevant log levels to be
+ * filtered.
+ */
+ public String getTags() {
+ ArrayList<String> arr = new ArrayList<>();
+ for (LogcatSettingItem item : m_logcatSettingItems) {
+ arr.add(String.format("%s:%s", item.getLogTag(), getPriorityName(item.getLogLevel())));
+ }
+
+ // Sort and silence everything else by default
+ Collections.sort(arr);
+ arr.add("*:S");
+
+ return TextUtils.join(" ", arr);
+ }
+
+ /**
+ * Convenience method that saves all tags present in m_logcatSettingItems
+ * to the persistent JSON storage file.
+ */
+ public void saveSettingItems() {
+ // Create tags map
+ Map<CharSequence, CharSequence> map = new HashMap<>();
+ for (LogcatSettingItem item : m_logcatSettingItems) {
+ map.put(item.getLogTag(), getPriorityName(item.getLogLevel()));
+ }
+
+ // Save tags
+ try {
+ m_logcatTagsJSONSerializer.saveTags(map);
+ } catch (IOException e) {
+ G.Log("saveSettingItems(): Error: " + e);
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Convenience method that loads all possible log level priority values as
+ * specified by the string array: R.array.logcat_log_level_map.
+ */
+ private void loadLogLevelMap() {
+ for (String item : m_context.getResources().getStringArray(R.array.logcat_log_level_map)) {
+ String [] arr = item.split(":");
+ m_logLevelMap.put(arr[0], arr[1]);
+ }
+ }
+
+ /**
+ * Convenience method that loads default values for tags and log levels that
+ * should be used. This method should be invoked when the application does not
+ * have previous JSON state information of the tags and log levels.
+ */
+ private void loadDefaultSettingItems() {
+ String [] defaults
+ = m_context.getResources().getStringArray(R.array.default_log_tags_and_levels);
+ for (String item : defaults) {
+ String [] arr = item.split(":");
+ m_logcatSettingItems.add(new LogcatSettingItem(arr[0], getVerbosePriorityName(arr[1])));
+ }
+ }
+
+ /**
+ * Convenience method that loads all tags that were previously stored and recorded. This
+ * method populates m_logcatSettingItems for use in a ListView to present all loaded tags and
+ * their relevant log levels.
+ */
+ private void loadSettingItems() {
+ Map<CharSequence, CharSequence> map;
+
+ try {
+ map = m_logcatTagsJSONSerializer.loadTags();
+
+ for (Map.Entry<CharSequence, CharSequence> entry : map.entrySet()) {
+ m_logcatSettingItems
+ .add(new LogcatSettingItem(entry.getKey().toString(),
+ getVerbosePriorityName(entry.getValue().toString())));
+ }
+ } catch (IOException | NullPointerException e) {
+ G.Log("loadSettingItems(): Error in loading tags from file: " + e);
+ }
+ }
+
+ /**
+ * Convenience method to get the verbose priority name. For instance, if
+ * "V" were passed in, the returned string would be "Verbose". This is
+ * dependent on the data that is loaded into m_logLevelMap.
+ *
+ * @param priority Short form priority name, e.g. "V"
+ * @return Verbose priority name, e.g. "Verbose" for a priority argument of "V"
+ */
+ private String getVerbosePriorityName(String priority) {
+ for (Map.Entry<CharSequence, CharSequence> item : m_logLevelMap.entrySet()) {
+ if (item.getValue().equals(priority)) {
+ return item.getKey().toString();
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Convenience method that gets the priority name from the verbose name. For instance,
+ * if "Verbose" were passed in, the returned string would be "V". This is
+ * dependent on the data that is loaded into m_logLevelMap.
+ *
+ * @param priorityVerboseName Verbose priority name, e.g. "Verbose"
+ * @return Short form priority name, e.g. "V"
+ */
+ private String getPriorityName(String priorityVerboseName) {
+ return m_logLevelMap.get(priorityVerboseName).toString();
+ }
+
+ //////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * JSON Serializer used to store JSON Tags and relevant settings to
+ * a local file. The JSON file format that this serializer stores
+ * in the private file is as such:
+ *
+ * <pre>
+ * [
+ * {
+ * "TcpFactory": "V",
+ * "CommandValidator": "V",
+ * "RibManager": "V",
+ * "Strategy": "V",
+ * "FaceTable": "V",
+ * "FibManager": "V",
+ * "FaceManager": "V",
+ * "PrivilegeHelper": "V",
+ * "ManagerBase": "V",
+ * "TcpChannel": "V",
+ * "InternalFace": "V",
+ * "TcpLocalFace": "V",
+ * "RemoteRegistrator": "V",
+ * "GeneralConfigSection": "V",
+ * "UdpFactory": "V",
+ * "StrategyChoice": "V",
+ * "TablesConfigSection": "V"
+ * }
+ * ]
+ * </pre>
+ *
+ * Each line represents a log tag that is to be monitored as well as the
+ * log level to be monitored (aka priority level of log cat). Tags can be any
+ * tag for the logger to filter.
+ *
+ * The log level should be one of the following form:
+ *
+ * <pre>
+ * Log Level | Meaning
+ * ===================
+ * V : Verbose
+ * D : Debug
+ * I : Info
+ * W : Warning
+ * E : Error
+ * F : Fatal
+ * S : Silent
+ * </pre>
+ *
+ */
+ private static class LogcatTagsJSONSerializer {
+
+ public LogcatTagsJSONSerializer(Context context, String filename) {
+ m_context = context;
+ m_filename = filename;
+ }
+
+ /**
+ * Convenience method to save all tags and their respective log levels from the
+ * given map. The map should contain key-value pairs of the following format:
+ *
+ * <pre>
+ * "TagName": "V"
+ * </pre>
+ *
+ * @param map Map to be converted saved as a JSON file
+ * @throws IOException
+ */
+ public void saveTags(Map<CharSequence, CharSequence> map) throws IOException {
+ // Create JSON Array
+ JSONArray array = new JSONArray().put(new JSONObject(map));
+
+ BufferedWriter writer = null;
+ try {
+ OutputStream out = m_context.openFileOutput(m_filename, Context.MODE_PRIVATE);
+ writer = new BufferedWriter(new OutputStreamWriter(out));
+ writer.write(array.toString());
+ } catch (IOException e) {
+ G.Log(String.format("saveTags(): Error while writing to file: %s - %s",
+ m_filename, e));
+ } finally {
+ if (writer != null) {
+ writer.close();
+ }
+ }
+ }
+
+ /**
+ * Convenience method to load all tags that were previously saved to a JSON
+ * file. The format depends on what was previously stored in the JSON file,
+ * but it is recommended to following the format set out in
+ * {@link
+ * net.named_data.nfd.LogcatSettingsManager.LogcatTagsJSONSerializer#saveTags(java.util.Map)}
+ *
+ * @return Map that was previously stored in the JSON file
+ * @throws IOException
+ */
+ public Map<CharSequence, CharSequence> loadTags() throws IOException {
+ Map<CharSequence, CharSequence> map = new HashMap<>();
+
+ BufferedReader reader = null;
+ try {
+ InputStream inputStream = m_context.openFileInput(m_filename);
+ reader = new BufferedReader(new InputStreamReader(inputStream));
+ StringBuilder jsonString = new StringBuilder();
+ String line;
+ while ((line = reader.readLine()) != null) {
+ jsonString.append(line);
+ }
+
+ // Parse JSON array
+ JSONArray array = (JSONArray) new JSONTokener(jsonString.toString()).nextValue();
+
+ // Populate map
+ for (int i=0; i<array.length(); i++) {
+ JSONObject jsonObject = array.getJSONObject(i);
+ Iterator<String> iterator = jsonObject.keys();
+ while (iterator.hasNext()) {
+ String key = iterator.next();
+ map.put(key, (CharSequence) jsonObject.get(key));
+ }
+ }
+ } catch (JSONException | IOException e) {
+ G.Log(String.format("saveTags(): Error while reading from file: %s - %s",
+ m_filename, e));
+ } finally {
+ if (reader != null) {
+ reader.close();
+ }
+ }
+
+ return map;
+ }
+
+ /**
+ * @return true if a previously saved file exists; false otherwise
+ */
+ public boolean logcatTagsFileExists() {
+ return m_context.getFileStreamPath(m_filename).exists();
+ }
+
+ /** Context for storing and retrieving files */
+ private final Context m_context;
+
+ /** File name to store JSON */
+ private final String m_filename;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////
+
+ /** Context for storage and retrieval of logcat settings (e.g. from Preferences or Files) */
+ private final Context m_context;
+
+ /** Array list that contains all the tags that are logged */
+ private final ArrayList<LogcatSettingItem> m_logcatSettingItems;
+
+ /** Mapping of log tag description to logcat priority setting */
+ private final Map<CharSequence, CharSequence> m_logLevelMap;
+
+ /** Reference to JSON Serializer for use */
+ private final LogcatTagsJSONSerializer m_logcatTagsJSONSerializer;
+
+ /** Singleton reference to a LogcatSettingsManager */
+ private static LogcatSettingsManager s_logcatSettingsManager;
+
+ /** NFD Logcat Tags JSON filename */
+ private static final String NFD_LOGCAT_TAGS_FILENAME = "NFD_LOGCAT_TAGS_FILE";
+}
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 e079e7c..945165a 100644
--- a/app/src/main/java/net/named_data/nfd/MainActivity.java
+++ b/app/src/main/java/net/named_data/nfd/MainActivity.java
@@ -19,329 +19,173 @@
package net.named_data.nfd;
-import android.app.Activity;
-import android.app.DialogFragment;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
import android.os.Bundle;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Message;
-import android.os.Messenger;
-import android.os.RemoteException;
-import android.preference.Preference;
-import android.preference.PreferenceFragment;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.app.FragmentTransaction;
+import android.support.v7.app.ActionBar;
+import android.support.v7.app.ActionBarActivity;
+import android.view.Menu;
+import android.view.MenuItem;
-import net.named_data.nfd.service.NfdService;
-import net.named_data.nfd.utils.G;
+import com.intel.jndn.management.types.FaceStatus;
-public class MainActivity extends Activity {
+import java.util.ArrayList;
- MainFragment m_main = new MainFragment();
+/**
+ * Main activity that is loaded for the NFD app.
+ */
+public class MainActivity extends ActionBarActivity
+ implements DrawerFragment.DrawerCallbacks,
+ LogcatFragment.Callbacks,
+ FaceListFragment.Callbacks
+{
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+
+ FragmentManager fragmentManager = getSupportFragmentManager();
+
+ if (savedInstanceState != null) {
+ m_drawerFragment = (DrawerFragment)fragmentManager.findFragmentByTag(DrawerFragment.class.toString());
+ }
+
+ if (m_drawerFragment == null) {
+ ArrayList<DrawerFragment.DrawerItem> items = new ArrayList<DrawerFragment.DrawerItem>();
+
+ items.add(new DrawerFragment.DrawerItem(R.string.drawer_item_general, 0,
+ DRAWER_ITEM_GENERAL));
+ items.add(new DrawerFragment.DrawerItem(R.string.drawer_item_faces, 0,
+ DRAWER_ITEM_FACES));
+ items.add(new DrawerFragment.DrawerItem(R.string.drawer_item_routes, 0,
+ DRAWER_ITEM_ROUTES));
+ // items.add(new DrawerFragment.DrawerItem(R.string.drawer_item_strategies, 0,
+ // DRAWER_ITEM_STRATEGIES));
+ items.add(new DrawerFragment.DrawerItem(R.string.drawer_item_logcat, 0,
+ DRAWER_ITEM_LOGCAT));
+
+ m_drawerFragment = DrawerFragment.newInstance(items);
+
+ fragmentManager
+ .beginTransaction()
+ .replace(R.id.navigation_drawer, m_drawerFragment, DrawerFragment.class.toString())
+ .commit();
+ }
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ if (!m_drawerFragment.isDrawerOpen()) {
+ // Inflate current Activity's menu only if the drawer is not
+ // displayed; otherwise, allow the drawer to inflate its own
+ // menu in the action bar. Inflate activity wide menu here.
+ updateActionBar();
+ return true;
+ }
+ return super.onCreateOptionsMenu(menu);
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ return super.onOptionsItemSelected(item);
+ }
+
+ //////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Convenience method that updates and display the current title in the Action Bar
+ */
+ @SuppressWarnings("deprecation")
+ private void updateActionBar() {
+ ActionBar actionBar = getSupportActionBar();
+ actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
+ actionBar.setDisplayShowTitleEnabled(true);
+ if (m_actionBarTitleId != -1) {
+ actionBar.setTitle(m_actionBarTitleId);
+ }
+ }
+
+ /**
+ * 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) {
+ FragmentManager fragmentManager = getSupportFragmentManager();
+ fragmentManager.beginTransaction()
+ .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
+ .replace(R.id.main_fragment_container, fragment)
+ .addToBackStack(null)
+ .commit();
+ }
+
+ //////////////////////////////////////////////////////////////////////////////
@Override
public void
- onCreate(Bundle savedInstanceState)
- {
- super.onCreate(savedInstanceState);
+ onDrawerItemSelected(int itemCode, int itemNameId) {
- getFragmentManager()
- .beginTransaction()
- .replace(android.R.id.content, m_main)
+ 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) {
+ switch (itemCode) {
+ case DRAWER_ITEM_GENERAL:
+ fragment = MainFragment.newInstance();
+ break;
+ case DRAWER_ITEM_FACES:
+ fragment = FaceListFragment.newInstance();
+ break;
+ case DRAWER_ITEM_ROUTES:
+ fragment = RouteListFragment.newInstance();
+ break;
+ // TODO: Placeholders; Fill these in when their fragments have been created
+ // case DRAWER_ITEM_STRATEGIES:
+ // break;
+ case DRAWER_ITEM_LOGCAT:
+ fragment = LogcatFragment.newInstance();
+ break;
+ default:
+ // Invalid; Nothing else needs to be done
+ return;
+ }
+ }
+
+ // Update ActionBar title
+ m_actionBarTitleId = itemNameId;
+
+ fragmentManager.beginTransaction()
+ .replace(R.id.main_fragment_container, fragment, fragmentTag)
.commit();
}
- public static class MainFragment extends PreferenceFragment {
- @Override
- public void onActivityCreated(Bundle savedInstanceState)
- {
- super.onActivityCreated(savedInstanceState);
-
- ///////////////////////////////////////////////////////////////////////////
- // General settings
- ///////////////////////////////////////////////////////////////////////////
- addPreferencesFromResource(R.xml.pref_general);
-
- m_startStopPref = findPreference("start_stop");
- m_startStopPref.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener()
- {
- @Override
- public boolean onPreferenceClick(Preference preference)
- {
- toggleNfdState();
- return true;
- }
- });
-
- ///////////////////////////////////////////////////////////////////////////
- // Face settings
- ///////////////////////////////////////////////////////////////////////////
- addPreferencesFromResource(R.xml.pref_face);
-
- findPreference("create_face")
- .setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
- @Override
- public boolean onPreferenceClick(Preference preference)
- {
- DialogFragment dialog = new FaceCreateDialog();
- dialog.show(getFragmentManager(), "FaceCreateFragment");
- return true;
- }
- });
-
- ///////////////////////////////////////////////////////////////////////////
- // Routes settings
- ///////////////////////////////////////////////////////////////////////////
- addPreferencesFromResource(R.xml.pref_routes);
-
- findPreference("create_route")
- .setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
- @Override
- public boolean onPreferenceClick(Preference preference)
- {
- DialogFragment dialog = new RouteCreateDialog();
- dialog.show(getFragmentManager(), "RouteCreateFragment");
- return true;
- }
- });
- }
-
- @Override
- public void onResume() {
- super.onResume();
-
- // Bind to NfdService
- bindNfdService();
- }
-
- @Override
- public void onPause() {
- super.onPause();
-
- // Unbind from NfdService
- unbindNfdService();
- }
-
- /**
- * Thread safe way to start and stop the NFD through
- * the UI Button.
- */
- private synchronized void toggleNfdState() {
- if (m_isNfdRunning) {
- m_startStopPref.setTitle(R.string.stopping_nfd);
- sendNfdServiceMessage(NfdService.MESSAGE_STOP_NFD_SERVICE);
- } else {
- m_startStopPref.setTitle(R.string.starting_nfd);
- sendNfdServiceMessage(NfdService.MESSAGE_START_NFD_SERVICE);
- }
- }
-
- /**
- * Convenience method to send a message to the NfdService
- * through a Messenger.
- *
- * @param message Message from a set of predefined NfdService messages.
- */
- private synchronized void sendNfdServiceMessage(int message) {
- try {
- Message msg = Message.obtain(null, message);
- msg.replyTo = m_clientMessenger;
- m_nfdServiceMessenger.send(msg);
- } catch (RemoteException e) {
- // If Service crashes, nothing to do here
- G.Log("Service Disconnected: " + e);
- }
- }
-
- /**
- * Enable UI Button once critical operations are completed.
- */
- private void enableNfdButton() {
- m_startStopPref.setEnabled(true);
- }
-
- /**
- * Disable UI Button to ensure user is unable to hit the button mutiple times.
- */
- private void disableNfdButton() {
- m_startStopPref.setEnabled(false);
- }
-
- /**
- * Thread safe way of flagging that the NFD is running.
- *
- * @param isNfdRunning true if NFD is running; false otherwise
- */
- private synchronized void setNfdRunningState(boolean isNfdRunning) {
- m_isNfdRunning = isNfdRunning;
- }
-
- /**
- * Toggle UI Button text to inform user of the next possible action.
- *
- * @param isNfdRunning true if NFD is currently running; false otherwise
- */
- private void setNfdButtonText(boolean isNfdRunning) {
- m_startStopPref.setTitle(isNfdRunning ? R.string.stop_nfd : R.string.start_nfd);
- }
-
- /**
- * Thread safe way of flagging that application is successfully connected
- * to the NfdService.
- *
- * @param isNfdServiceConnected true if successfully connected to the NfdService;
- * false otherwise
- */
- private synchronized void setNfdServiceConnected(boolean isNfdServiceConnected) {
- m_isNfdServiceConnected = isNfdServiceConnected;
- }
-
- /**
- * Method that binds the current activity to the NfdService.
- */
- private synchronized void bindNfdService() {
- if (m_isNfdServiceBound == false) {
- // Bind to Service
- m_isNfdServiceBound = getActivity().bindService(
- new Intent(getActivity(), NfdService.class),
- m_ServiceConnection, Context.BIND_AUTO_CREATE);
-
- G.Log("MainActivity::bindNfdService()");
- }
- }
-
- /**
- * Method that unbinds the current activity from the NfdService.
- */
- private synchronized void unbindNfdService() {
- if (m_isNfdServiceBound == true) {
- // Unbind from Service
- getActivity().unbindService(m_ServiceConnection);
- m_isNfdServiceBound = false;
-
- G.Log("MainActivity::unbindNfdService()");
- }
- }
-
- /**
- * Client Message Handler.
- *
- * This handler is used to handle messages that are being sent back
- * from the NfdService to the current application.
- */
- class ClientHandler extends Handler
- {
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case NfdService.MESSAGE_NFD_RUNNING:
- setNfdRunningState(true);
- setNfdButtonText(true);
- G.Log("ClientHandler: NFD is Running.");
- break;
-
- case NfdService.MESSAGE_NFD_STOPPED:
- setNfdRunningState(false);
- setNfdButtonText(false);
- G.Log("ClientHandler: NFD is Stopped.");
- break;
-
- default:
- super.handleMessage(msg);
- break;
- }
-
- enableNfdButton();
- }
- }
-
- /**
- * Client ServiceConnection to NfdService.
- */
- private ServiceConnection m_ServiceConnection = new ServiceConnection() {
- @Override
- public void onServiceConnected(ComponentName className, IBinder service) {
- // Establish Messenger to the Service
- m_nfdServiceMessenger = new Messenger(service);
-
- // Set service connected flag
- setNfdServiceConnected(true);
-
- // Check if NFD Service is running
- try {
- Message msg = Message.obtain(null,
- NfdService.MESSAGE_IS_NFD_RUNNING);
- msg.replyTo = m_clientMessenger;
- m_nfdServiceMessenger.send(msg);
- } catch (RemoteException e) {
- // If Service crashes, nothing to do here
- G.Log("onServiceConnected(): " + e);
- }
-
- G.Log("m_ServiceConnection::onServiceConnected()");
- }
-
- @Override
- public void onServiceDisconnected(ComponentName componentName) {
- // In event of unexpected disconnection with the Service; Not expecting to get here.
- G.Log("m_ServiceConnection::onServiceDisconnected()");
-
- // Update UI
- disableNfdButton();
- m_startStopPref.setTitle(R.string.reconnect_to_nfd);
-
- // Reconnect to NfdService
- setNfdServiceConnected(false);
- retryConnectionToNfdService();
- }
- };
-
- /**
- * Attempt to reconnect to the NfdService.
- *
- * This method attempts to reconnect the application to the NfdService
- * when the NfdService has been killed (either by the user or by the OS).
- */
- private void retryConnectionToNfdService() {
- new Thread(){
- @Override
- public void run() {
- while (m_isNfdServiceConnected == false) {
- G.Log("Retrying connection to NFD Service ...");
- bindNfdService();
-
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- // Nothing to do here; Keep going.
- }
- }
-
- G.Log("Reconnection to NFD Service is successful.");
- }
- }.start();
- }
-
- //////////////////////////////////////////////////////////////////////////////
-
- /** Button that starts and stops the NFD */
- private Preference m_startStopPref;
-
- /** Flag that marks that application is bound to the NfdService */
- private boolean m_isNfdServiceBound = false;
-
- /** Flag that marks that application is connected to the NfdService */
- private boolean m_isNfdServiceConnected = false;
-
- /** Client Message Handler */
- private final Messenger m_clientMessenger = new Messenger(new ClientHandler());
-
- /** Messenger connection to NfdService */
- private Messenger m_nfdServiceMessenger = null;
-
- /** Flag that marks if the NFD is running */
- private boolean m_isNfdRunning = false;
+ @Override
+ public void onDisplayLogcatSettings() {
+ replaceContentFragmentWithBackstack(LogcatSettingsFragment.newInstance());
}
+
+ @Override
+ public void onFaceItemSelected(FaceStatus faceStatus) {
+ replaceContentFragmentWithBackstack(FaceStatusFragment.newInstance(faceStatus));
+ }
+
+ //////////////////////////////////////////////////////////////////////////////
+
+ /** Reference to drawer fragment */
+ private DrawerFragment m_drawerFragment;
+
+ /** Title that is to be displayed in the ActionBar */
+ private int m_actionBarTitleId = -1;
+
+ /** Item code for drawer items: For use in onDrawerItemSelected() callback */
+ public static final int DRAWER_ITEM_GENERAL = 1;
+ public static final int DRAWER_ITEM_FACES = 2;
+ public static final int DRAWER_ITEM_ROUTES = 3;
+ public static final int DRAWER_ITEM_STRATEGIES = 4;
+ public static final int DRAWER_ITEM_LOGCAT = 5;
}
diff --git a/app/src/main/java/net/named_data/nfd/MainFragment.java b/app/src/main/java/net/named_data/nfd/MainFragment.java
new file mode 100644
index 0000000..878e7b1
--- /dev/null
+++ b/app/src/main/java/net/named_data/nfd/MainFragment.java
@@ -0,0 +1,318 @@
+/* -*- Mode:jde; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2015 Regents of the University of California
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon) Android.
+ * See AUTHORS.md for complete list of NFD Android authors and contributors.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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.annotation.SuppressLint;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.RemoteException;
+import android.support.annotation.Nullable;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Switch;
+
+import net.named_data.nfd.service.NfdService;
+import net.named_data.nfd.utils.G;
+
+public class MainFragment extends Fragment {
+
+ public static MainFragment newInstance() {
+ // Create fragment arguments here (if necessary)
+ return new MainFragment();
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater,
+ @Nullable ViewGroup container,
+ @Nullable Bundle savedInstanceState)
+ {
+ @SuppressLint("InflateParams")
+ View v = inflater.inflate(R.layout.fragment_main, null);
+
+ m_nfdStartStopSwitch = (Switch) v.findViewById(R.id.nfd_start_stop_switch);
+ m_nfdStartStopSwitch.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ toggleNfdState();
+ }
+ });
+
+ return v;
+ }
+
+ @Override
+ public void onResume () {
+ super.onResume();
+
+ // Bind to NfdService
+ bindNfdService();
+ }
+
+ @Override
+ public void onPause () {
+ super.onPause();
+
+ // Unbind from NfdService
+ unbindNfdService();
+ }
+
+ /**
+ * Thread safe way to start and stop the NFD through
+ * the UI Button.
+ */
+ private synchronized void toggleNfdState() {
+ if (m_isNfdRunning) {
+ m_nfdStartStopSwitch.setText(R.string.stopping_nfd);
+ sendNfdServiceMessage(NfdService.MESSAGE_STOP_NFD_SERVICE);
+ } else {
+ m_nfdStartStopSwitch.setText(R.string.starting_nfd);
+ sendNfdServiceMessage(NfdService.MESSAGE_START_NFD_SERVICE);
+ }
+ }
+
+ /**
+ * Convenience method to send a message to the NfdService
+ * through a Messenger.
+ *
+ * @param message Message from a set of predefined NfdService messages.
+ */
+ private synchronized void sendNfdServiceMessage(int message) {
+ try {
+ Message msg = Message.obtain(null, message);
+ msg.replyTo = m_clientMessenger;
+ m_nfdServiceMessenger.send(msg);
+ } catch (RemoteException e) {
+ // If Service crashes, nothing to do here
+ G.Log("Service Disconnected: " + e);
+ }
+ }
+
+ /**
+ * Enable UI Switch once critical operations are completed.
+ */
+ private void enableNfdSwitch() {
+ m_nfdStartStopSwitch.setEnabled(true);
+ }
+
+ /**
+ * Disable UI Switch to ensure user is unable to hit the switch multiple times.
+ */
+ private void disableNfdSwitch() {
+ m_nfdStartStopSwitch.setEnabled(false);
+ }
+
+ /**
+ * Thread safe way of flagging that the NFD is running.
+ *
+ * @param isNfdRunning true if NFD is running; false otherwise
+ */
+ private synchronized void setNfdRunningState(boolean isNfdRunning) {
+ m_isNfdRunning = isNfdRunning;
+ }
+
+ /**
+ * Toggle UI Switch to inform user of the next possible action.
+ *
+ * @param isNfdRunning true if NFD is currently running; false otherwise
+ */
+ private void setNfdSwitchState(boolean isNfdRunning) {
+ m_nfdStartStopSwitch.setText(isNfdRunning ? R.string.nfd_started : R.string.nfd_stopped);
+ m_nfdStartStopSwitch.setChecked(isNfdRunning);
+ }
+
+ /**
+ * Update UI Switch to inform user that the NFD Service has been disconnected
+ * and an attempt is made to reconnect with the NFD Service.
+ */
+ private void setNfdDisconnectedSwitchState() {
+ disableNfdSwitch();
+ m_nfdStartStopSwitch.setText(R.string.reconnect_to_nfd);
+ m_nfdStartStopSwitch.setChecked(false);
+ }
+
+ /**
+ * Thread safe way of flagging that application is successfully connected
+ * to the NfdService.
+ *
+ * @param isNfdServiceConnected true if successfully connected to the NfdService;
+ * false otherwise
+ */
+ private synchronized void setNfdServiceConnected(boolean isNfdServiceConnected) {
+ m_isNfdServiceConnected = isNfdServiceConnected;
+ }
+
+ /**
+ * Method that binds the current activity to the NfdService.
+ */
+ private synchronized void bindNfdService() {
+ if (!m_isNfdServiceBound) {
+ // Bind to Service
+ m_isNfdServiceBound = getActivity().bindService(
+ new Intent(getActivity(), NfdService.class),
+ m_ServiceConnection, Context.BIND_AUTO_CREATE);
+
+ G.Log("MainFragment::bindNfdService()");
+ }
+ }
+
+ /**
+ * Method that unbinds the current activity from the NfdService.
+ */
+ private synchronized void unbindNfdService() {
+ if (m_isNfdServiceBound) {
+ // Unbind from Service
+ getActivity().unbindService(m_ServiceConnection);
+ m_isNfdServiceBound = false;
+
+ G.Log("MainFragment::unbindNfdService()");
+ }
+ }
+
+ /**
+ * Client Message Handler.
+ *
+ * This handler is used to handle messages that are being sent back
+ * from the NfdService to the current application.
+ */
+ private class ClientHandler extends Handler {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case NfdService.MESSAGE_NFD_RUNNING:
+ setNfdRunningState(true);
+ setNfdSwitchState(true);
+ G.Log("ClientHandler: NFD is Running.");
+ break;
+
+ case NfdService.MESSAGE_NFD_STOPPED:
+ setNfdRunningState(false);
+ setNfdSwitchState(false);
+ G.Log("ClientHandler: NFD is Stopped.");
+ break;
+
+ default:
+ super.handleMessage(msg);
+ break;
+ }
+
+ enableNfdSwitch();
+ }
+ }
+
+ /**
+ * Client ServiceConnection to NfdService.
+ */
+ private final ServiceConnection m_ServiceConnection = new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName className, IBinder service) {
+ // Establish Messenger to the Service
+ m_nfdServiceMessenger = new Messenger(service);
+
+ // Set service connected flag
+ setNfdServiceConnected(true);
+
+ // Check if NFD Service is running
+ try {
+ Message msg = Message.obtain(null,
+ NfdService.MESSAGE_IS_NFD_RUNNING);
+ msg.replyTo = m_clientMessenger;
+ m_nfdServiceMessenger.send(msg);
+ } catch (RemoteException e) {
+ // If Service crashes, nothing to do here
+ G.Log("onServiceConnected(): " + e);
+ }
+
+ G.Log("m_ServiceConnection::onServiceConnected()");
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName componentName) {
+ // In event of unexpected disconnection with the Service; Not expecting to get here.
+ G.Log("m_ServiceConnection::onServiceDisconnected()");
+
+ // Update UI
+ setNfdDisconnectedSwitchState();
+
+ // Reconnect to NfdService
+ setNfdServiceConnected(false);
+ retryConnectionToNfdService();
+ }
+ };
+
+ /**
+ * Attempt to reconnect to the NfdService.
+ *
+ * This method attempts to reconnect the application to the NfdService
+ * when the NfdService has been killed (either by the user or by the OS).
+ */
+ private void retryConnectionToNfdService() {
+ new Thread(){
+ @Override
+ public void run() {
+ // TODO: Trying infinitely doesn't make sense.
+ // Convert this to an AsyncTask that:
+ // - has a fixed number of retries
+ // - update UI to inform user of the progress
+ // - set switch to appropriate state when service fails to come online
+ while (!m_isNfdServiceConnected) {
+ G.Log("Retrying connection to NFD Service ...");
+ bindNfdService();
+
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ // Nothing to do here; Keep going.
+ }
+ }
+
+ G.Log("Reconnection to NFD Service is successful.");
+ }
+ }.start();
+ }
+
+ //////////////////////////////////////////////////////////////////////////////
+
+ /** Button that starts and stops the NFD */
+ private Switch m_nfdStartStopSwitch;
+
+ /** Flag that marks that application is bound to the NfdService */
+ private boolean m_isNfdServiceBound = false;
+
+ /** Flag that marks that application is connected to the NfdService */
+ private boolean m_isNfdServiceConnected = false;
+
+ /** Client Message Handler */
+ private final Messenger m_clientMessenger = new Messenger(new ClientHandler());
+
+ /** Messenger connection to NfdService */
+ private Messenger m_nfdServiceMessenger = null;
+
+ /** Flag that marks if the NFD is running */
+ private boolean m_isNfdRunning = false;
+}
diff --git a/app/src/main/java/net/named_data/nfd/RouteCreateDialog.java b/app/src/main/java/net/named_data/nfd/RouteCreateDialog.java
deleted file mode 100644
index aef371a..0000000
--- a/app/src/main/java/net/named_data/nfd/RouteCreateDialog.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/* -*- Mode:jde; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (c) 2015 Regents of the University of California
- *
- * This file is part of NFD (Named Data Networking Forwarding Daemon) Android.
- * See AUTHORS.md for complete list of NFD Android authors and contributors.
- *
- * 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.
- *
- * 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.
- *
- * 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.app.DialogFragment;
-import android.content.DialogInterface;
-import android.os.Bundle;
-import android.view.LayoutInflater;
-import android.view.WindowManager;
-import android.widget.EditText;
-
-import net.named_data.jndn.Name;
-import net.named_data.jndn_xx.util.FaceUri;
-import net.named_data.nfd.utils.Nfdc;
-import net.named_data.nfd.utils.NfdcAsyncTask;
-
-public class RouteCreateDialog extends DialogFragment
-{
- @Override
- public Dialog
- onCreateDialog(Bundle savedInstanceState) {
- AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
- LayoutInflater inflater = getActivity().getLayoutInflater();
- builder
- .setView(inflater.inflate(R.layout.create_route, null))
- .setPositiveButton("Create route", new DialogInterface.OnClickListener()
- {
- @Override
- public void onClick(DialogInterface dialog, int id)
- {
- 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();
- new NfdcAsyncTask(getActivity(),
- new NfdcAsyncTask.Task()
- {
- public String
- runTask() throws Exception
- {
- try {
- Nfdc nfdc = new Nfdc();
- int faceId = nfdc.faceCreate(m_uri);
- boolean ok = nfdc.ribRegisterPrefix(new Name(prefix), faceId, 10, true, false);
- nfdc.shutdown();
- if (ok) {
- return "OK";
- }
- else {
- return "Failed register prefix";
- }
- } catch (FaceUri.CanonizeError e) {
- return "Error creating face (" + e.getMessage() + ")";
- } catch (FaceUri.Error e) {
- return "Error creating face (" + e.getMessage() + ")";
- }
- }
-
- ///////////////////////////
- private String m_uri = uri;
- }).execute();
- }
- })
- .setNegativeButton("Cancel", new DialogInterface.OnClickListener()
- {
- public void onClick(DialogInterface dialog, int id)
- {
- RouteCreateDialog.this.getDialog().cancel();
- }
- })
- ;
-
- Dialog faceCreateDialog = builder.create();
- faceCreateDialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
- return faceCreateDialog;
- }
-}
diff --git a/app/src/main/java/net/named_data/nfd/RouteCreateDialogFragment.java b/app/src/main/java/net/named_data/nfd/RouteCreateDialogFragment.java
new file mode 100644
index 0000000..6517b32
--- /dev/null
+++ b/app/src/main/java/net/named_data/nfd/RouteCreateDialogFragment.java
@@ -0,0 +1,77 @@
+/* -*- Mode:jde; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2015 Regents of the University of California
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon) Android.
+ * See AUTHORS.md for complete list of NFD Android authors and contributors.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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.v4.app.DialogFragment;
+import android.view.LayoutInflater;
+import android.view.WindowManager;
+import android.widget.EditText;
+
+import net.named_data.jndn.Name;
+
+public class RouteCreateDialogFragment extends DialogFragment
+{
+ public static interface OnRouteCreateRequested {
+ public void
+ createRoute(Name prefix, String faceUri);
+ }
+
+ public static RouteCreateDialogFragment
+ newInstance() {
+ return new RouteCreateDialogFragment();
+ }
+
+ @NonNull @Override
+ public Dialog
+ onCreateDialog(Bundle savedInstanceState) {
+ AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+ LayoutInflater inflater = getActivity().getLayoutInflater();
+ builder
+ .setView(inflater.inflate(R.layout.create_route, null))
+ .setPositiveButton(R.string.route_add_dialog_create_route, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int id)
+ {
+ 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();
+
+ ((OnRouteCreateRequested)getTargetFragment()).createRoute(new Name(prefix), uri);
+ }
+ })
+ .setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id)
+ {
+ RouteCreateDialogFragment.this.getDialog().cancel();
+ }
+ })
+ ;
+
+ Dialog faceCreateDialog = builder.create();
+ faceCreateDialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
+ return faceCreateDialog;
+ }
+}
diff --git a/app/src/main/java/net/named_data/nfd/RouteListActivity.java b/app/src/main/java/net/named_data/nfd/RouteListActivity.java
deleted file mode 100644
index 5eca4cd..0000000
--- a/app/src/main/java/net/named_data/nfd/RouteListActivity.java
+++ /dev/null
@@ -1,192 +0,0 @@
-/* -*- Mode:jde; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (c) 2015 Regents of the University of California
- *
- * This file is part of NFD (Named Data Networking Forwarding Daemon) Android.
- * See AUTHORS.md for complete list of NFD Android authors and contributors.
- *
- * 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.
- *
- * 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.
- *
- * 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.Activity;
-import android.app.FragmentManager;
-import android.app.FragmentTransaction;
-import android.app.ListFragment;
-import android.content.Context;
-import android.os.Bundle;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.AdapterView;
-import android.widget.BaseAdapter;
-import android.widget.TextView;
-
-import com.intel.jndn.management.types.RibEntry;
-import com.intel.jndn.management.types.Route;
-
-import net.named_data.nfd.utils.Nfdc;
-import net.named_data.nfd.utils.NfdcAsyncTask;
-
-import org.apache.commons.lang.StringUtils;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class RouteListActivity extends Activity
-{
- @Override
- public void
- onCreate(Bundle savedInstanceState)
- {
- super.onCreate(savedInstanceState);
-
- FragmentManager fm = getFragmentManager();
- FragmentTransaction ft = fm.beginTransaction();
- if (fm.findFragmentById(android.R.id.content) == null) {
- ft.add(android.R.id.content, m_routeListFragment);
- }
- else {
- ft.replace(android.R.id.content, m_routeListFragment);
- }
- ft.commit();
- }
-
- public static class RouteListFragment extends ListFragment {
- @Override
- public void onActivityCreated(Bundle savedInstanceState)
- {
- super.onActivityCreated(savedInstanceState);
-
- RouteListAdapter adapter = new RouteListAdapter(getActivity());
- setListAdapter(adapter);
-
- adapter.updateFaceList();
- }
-
- private class RouteListAdapter extends BaseAdapter
- {
- public RouteListAdapter(Context context)
- {
- this.m_inflater = LayoutInflater.from(context);
- this.m_context = context;
- }
-
- public void
- updateFaceList()
- {
- new NfdcAsyncTask(m_context,
- new NfdcAsyncTask.Task() {
- public String
- runTask() throws Exception
- {
- synchronized (m_routesLock) {
- Nfdc nfdc = new Nfdc();
- m_routes = nfdc.ribList();
- nfdc.shutdown();
- }
-
- getActivity().runOnUiThread(new Runnable() {
- @Override
- public void run()
- {
- notifyDataSetChanged();
- }
- });
- return null;
- }
- }).execute();
- }
-
- @Override
- public int
- getCount()
- {
- synchronized (m_routesLock) {
- if (m_routes == null)
- return 0;
- else
- return m_routes.size();
- }
- }
-
- @Override
- public Object
- getItem(int position)
- {
- synchronized (m_routesLock) {
- assert m_routes != null && position < m_routes.size();
- return m_routes.get(position);
- }
- }
-
- @Override
- public long
- getItemId(int position)
- {
- return position;
- }
-
- @Override
- public View
- getView(int position, View convertView, ViewGroup parent)
- {
- RouteListItemViewHolder holder;
- if (convertView == null) {
- convertView = this.m_inflater.inflate(android.R.layout.simple_list_item_2, parent, false);
- holder = new RouteListItemViewHolder(convertView);
- convertView.setTag(holder);
- } else {
- holder = (RouteListItemViewHolder)convertView.getTag();
- }
-
- RibEntry e;
- synchronized (m_routesLock) {
- e = m_routes.get(position);
- }
- holder.text1.setText(e.getName().toUri());
-
- List<String> faceList = new ArrayList<>();
- for (Route r : e.getRoutes()) {
- faceList.add(String.valueOf(r.getFaceId()));
- }
- holder.text2.setText(StringUtils.join(faceList, ", "));
-
- return convertView;
- }
-
- /////////////////////////////////////////////////////////////////////////
- private LayoutInflater m_inflater;
- private Context m_context;
- private List<RibEntry> m_routes;
- private final Object m_routesLock = new Object();
-
- }
-
- private static class RouteListItemViewHolder
- {
- RouteListItemViewHolder(View v)
- {
- text1 = (TextView)v.findViewById(android.R.id.text1);
- text2 = (TextView)v.findViewById(android.R.id.text2);
- }
-
- /////////////////////////////////////////////////////////////////////////
- public TextView text1;
- public TextView text2;
- }
- }
-
- /////////////////////////////////////////////////////////////////////////////
- private RouteListFragment m_routeListFragment = new RouteListFragment();
-}
diff --git a/app/src/main/java/net/named_data/nfd/RouteListFragment.java b/app/src/main/java/net/named_data/nfd/RouteListFragment.java
new file mode 100644
index 0000000..f6c787f
--- /dev/null
+++ b/app/src/main/java/net/named_data/nfd/RouteListFragment.java
@@ -0,0 +1,375 @@
+/* -*- Mode:jde; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2015 Regents of the University of California
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon) Android.
+ * See AUTHORS.md for complete list of NFD Android authors and contributors.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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.content.Context;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.support.v4.app.ListFragment;
+import android.text.TextUtils;
+import android.util.Pair;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.Button;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+import android.widget.Toast;
+
+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_xx.util.FaceUri;
+import net.named_data.nfd.utils.Nfdc;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class RouteListFragment extends ListFragment implements RouteCreateDialogFragment.OnRouteCreateRequested {
+
+ public static RouteListFragment
+ newInstance() {
+ return new RouteListFragment();
+ }
+
+ @Override
+ public void
+ onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ setListAdapter(new RouteListAdapter(getActivity()));
+ }
+
+ @Override
+ public View
+ onCreateView(LayoutInflater inflater,
+ ViewGroup container,
+ Bundle savedInstanceState)
+ {
+ View v = inflater.inflate(R.layout.fragment_route_list, null);
+ m_routeListInfoUnavailableView = v.findViewById(R.id.route_list_info_unavailable);
+
+ // Get progress bar spinner view
+ m_reloadingListProgressBar
+ = (ProgressBar)v.findViewById(R.id.route_list_reloading_list_progress_bar);
+
+ Button refreshRouteListButton = (Button) v.findViewById(R.id.route_list_refresh_button);
+ refreshRouteListButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ retrieveRouteList();
+ }
+ });
+
+ Button addRouteButton = (Button)v.findViewById(R.id.route_list_add_button);
+ addRouteButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view)
+ {
+ RouteCreateDialogFragment dialog = RouteCreateDialogFragment.newInstance();
+ dialog.setTargetFragment(RouteListFragment.this, 0);
+ dialog.show(getFragmentManager(), "RouteCreateFragment");
+ }
+ });
+
+ return v;
+ }
+
+ @Override
+ public void
+ onResume() {
+ super.onResume();
+ startRouteListInfoRetrievalTask();
+ }
+
+ @Override
+ public void
+ onPause() {
+ super.onPause();
+ stopRouteListInfoRetrievalTask();
+
+ if (m_routeCreateAsyncTask != null) {
+ m_routeCreateAsyncTask.cancel(false);
+ m_routeCreateAsyncTask = null;
+ }
+ }
+
+ @Override
+ public void
+ createRoute(Name prefix, String faceUri)
+ {
+ m_routeCreateAsyncTask = new RouteCreateAsyncTask(prefix, faceUri);
+ m_routeCreateAsyncTask.execute();
+ }
+
+
+ /////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Updates the underlying adapter with the given list of RibEntry.
+ *
+ * Note: This method should only be called from the UI thread.
+ *
+ * @param list Update ListView with the given List<RibEntry>
+ */
+ private void updateRouteList(List<RibEntry> list) {
+ if (list == null) {
+ m_routeListInfoUnavailableView.setVisibility(View.VISIBLE);
+ return;
+ }
+
+ ((RouteListAdapter)getListAdapter()).updateList(list);
+ }
+
+ /**
+ * Convenience method that starts the AsyncTask that retrieves the
+ * list of available routes.
+ */
+ private void retrieveRouteList() {
+ // Update UI
+ m_routeListInfoUnavailableView.setVisibility(View.GONE);
+
+ // Stop if running; before starting the new Task
+ stopRouteListInfoRetrievalTask();
+ startRouteListInfoRetrievalTask();
+ }
+
+ /**
+ * Create a new AsynTask for route list information retrieval.
+ */
+ private void startRouteListInfoRetrievalTask() {
+ m_routeListAsyncTask = new RouteListAsyncTask();
+ m_routeListAsyncTask.execute();
+ }
+
+ /**
+ * Stops a previously started AsyncTask.
+ */
+ private void stopRouteListInfoRetrievalTask() {
+ if (m_routeListAsyncTask != null) {
+ m_routeListAsyncTask.cancel(false);
+ m_routeListAsyncTask = null;
+ }
+ }
+
+ /////////////////////////////////////////////////////////////////////////
+
+ private static class RouteListAdapter extends BaseAdapter {
+
+ public RouteListAdapter(Context context) {
+ m_layoutInflater = LayoutInflater.from(context);
+ }
+
+ public void
+ updateList(List<RibEntry> ribEntries) {
+ m_ribEntries = ribEntries;
+ notifyDataSetChanged();
+ }
+
+ @Override
+ public int getCount()
+ {
+ return (m_ribEntries == null) ? 0 : m_ribEntries.size();
+ }
+
+ @Override
+ public RibEntry
+ getItem(int i)
+ {
+ assert m_ribEntries != null;
+ return m_ribEntries.get(i);
+ }
+
+ @Override
+ public long
+ getItemId(int i)
+ {
+ return i;
+ }
+
+ @Override
+ public View
+ getView(int position, View convertView, ViewGroup parent) {
+ RouteItemHolder holder;
+
+ if (convertView == null) {
+ holder = new RouteItemHolder();
+
+ convertView = m_layoutInflater.inflate(R.layout.list_item_route_item, null);
+ convertView.setTag(holder);
+
+ holder.m_uri = (TextView) convertView.findViewById(R.id.list_item_route_uri);
+ holder.m_faceList = (TextView) convertView.findViewById(R.id.list_item_face_list);
+ } else {
+ holder = (RouteItemHolder) convertView.getTag();
+ }
+
+ RibEntry entry = getItem(position);
+
+ // Prefix
+ holder.m_uri.setText(entry.getName().toUri());
+
+ // List of faces
+ List<String> faceList = new ArrayList<>();
+ for (Route r : entry.getRoutes()) {
+ faceList.add(String.valueOf(r.getFaceId()));
+ }
+ holder.m_faceList.setText(TextUtils.join(", ", faceList));
+
+ return convertView;
+ }
+
+ private static class RouteItemHolder {
+ private TextView m_uri;
+ private TextView m_faceList;
+ }
+
+ private final LayoutInflater m_layoutInflater;
+ private List<RibEntry> m_ribEntries;
+ }
+
+ 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) {
+ Nfdc nfdc = new Nfdc();
+ Exception returnException = null;
+ List<RibEntry> routes = null;
+ try {
+ routes = nfdc.ribList();
+ }
+ catch (Exception e) {
+ returnException = e;
+ }
+ nfdc.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();
+ }
+
+ updateRouteList(result.first);
+ }
+ }
+
+
+ private class RouteCreateAsyncTask extends AsyncTask<Void, Void, String> {
+ public
+ RouteCreateAsyncTask(Name prefix, String faceUri)
+ {
+ m_prefix = prefix;
+ m_faceUri = faceUri;
+ }
+
+ @Override
+ protected String
+ doInBackground(Void... params)
+ {
+ try {
+ Nfdc nfdc = new Nfdc();
+ int faceId = nfdc.faceCreate(m_faceUri);
+ boolean ok = 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 "Error creating face (" + e.getMessage() + ")";
+ } catch (FaceUri.Error e) {
+ return "Error creating face (" + e.getMessage() + ")";
+ }
+ catch (Exception e) {
+ return "Error communicating with NFD (" + e.getMessage() + ")";
+ }
+ }
+
+ @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();
+
+ retrieveRouteList();
+ }
+
+ @Override
+ protected void
+ onCancelled()
+ {
+ // Remove progress bar
+ m_reloadingListProgressBar.setVisibility(View.GONE);
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ private Name m_prefix;
+ private String m_faceUri;
+ }
+
+ /////////////////////////////////////////////////////////////////////////////
+
+ /** Reference to the most recent AsyncTask that was created for listing routes */
+ private RouteListAsyncTask m_routeListAsyncTask;
+
+ /** Reference to the view to be displayed when no information is available */
+ private View m_routeListInfoUnavailableView;
+
+ /** Progress bar spinner to display to user when destroying faces */
+ private ProgressBar m_reloadingListProgressBar;
+
+ /** Reference to the most recent AsyncTask that was created for creating a route */
+ private RouteCreateAsyncTask m_routeCreateAsyncTask;
+}
\ No newline at end of file
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 2657790..069356b 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
@@ -32,7 +32,7 @@
/**
* NfdService that runs the native NFD.
*
- * NfdSevice runs as an independent process within the Android OS that provides
+ * NfdService runs as an independent process within the Android OS that provides
* service level features to start and stop the NFD native code through the
* NFD JNI wrapper.
*
@@ -44,7 +44,7 @@
*/
static {
// At least on Galaxy S3 (4.1.1), all shared library dependencies that are located
- // in app's lib folder (not in /system/lib) need to be expliclity loaded.
+ // in app's lib folder (not in /system/lib) need to be explicitly loaded.
// The script https://gist.github.com/cawka/11fe9c23b7a13960330b can be used to
// calculate proper dependency load list.
// For example:
@@ -144,7 +144,7 @@
* started flag.
*/
private synchronized void serviceStartNfd() {
- if (m_isNfdStarted == false) {
+ if (!m_isNfdStarted) {
m_isNfdStarted = true;
startNfd(getFilesDir().getAbsolutePath());
@@ -165,7 +165,7 @@
* started flag.
*/
private synchronized void serviceStopNfd() {
- if (m_isNfdStarted == true) {
+ if (m_isNfdStarted) {
m_isNfdStarted = false;
// TODO: Save NFD and NRD in memory data structures.
@@ -188,7 +188,7 @@
/**
* Message handler for the the NFD Service.
*/
- class NfdServiceMessageHandler extends Handler {
+ private class NfdServiceMessageHandler extends Handler {
@Override
public void handleMessage(Message message) {
diff --git a/app/src/main/java/net/named_data/nfd/utils/LogcatTags.java b/app/src/main/java/net/named_data/nfd/utils/LogcatTags.java
deleted file mode 100644
index 8d20321..0000000
--- a/app/src/main/java/net/named_data/nfd/utils/LogcatTags.java
+++ /dev/null
@@ -1,181 +0,0 @@
-/* -*- Mode:jde; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (c) 2015 Regents of the University of California
- *
- * This file is part of NFD (Named Data Networking Forwarding Daemon) Android.
- * See AUTHORS.md for complete list of NFD Android authors and contributors.
- *
- * 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.
- *
- * 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.
- *
- * 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.utils;
-
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.text.TextUtils;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * Utility class to generate and retrieve log tags
- */
-public class LogcatTags
-{
-
- /**
- * Get tags that are stored for the given application's context.
- *
- * The method returns a string representation of tags that should be displayed
- * to the UI. These tags and their output levels have been saved by the settings
- * UI in the given context.
- *
- * An example of the return string is as such:
- *
- * <pre>
- * NFDService:S Strategy:S TcpChannel:S TcpFactory:S TcpLocalFace:S UdpFactory:S *:S
- * </pre>
- *
- * @param context Current application context to retrieve log tags for
- * @return String representation of log tags ready for use as arguments
- * to logcat.
- */
- public static String getTags(Context context) {
- SharedPreferences preferences = context.getSharedPreferences(
- PREFERENCE_NFD_TAGS_FILENAME, Context.MODE_PRIVATE);
- String tagsString = preferences.getString(PREFERENCE_NFD_TAGS_KEY, "");
-
- G.Log("loadCommand(): " + tagsString);
-
- return tagsString;
- }
-
- /**
- * Save tags as a string to the current context's preference.
- *
- * An example of a tag string that should be saved is shown as follows:
- *
- * <pre>
- * NFDService:S Strategy:S TcpChannel:S TcpFactory:S TcpLocalFace:S UdpFactory:S *:S
- * </pre>
- *
- * NdfLogTagUtil.TagBuilder provides convenient methods to generate tag strings.
- *
- * @param context Current application context to save tag string to
- * @param tagsString String representation of the tags to be saved
- */
- public static void saveTags(Context context, String tagsString) {
- // Save preferred log level
- SharedPreferences.Editor editor
- = context.getSharedPreferences(
- PREFERENCE_NFD_TAGS_FILENAME, Context.MODE_PRIVATE).edit();
- editor.putString(PREFERENCE_NFD_TAGS_KEY, tagsString);
- editor.commit();
-
- G.Log("saveTags(): " + tagsString);
- }
-
- /**
- * Convenience class to create and generate tags for use as arguments
- * to logcat.
- */
- public static class TagBuilder {
-
- private TagBuilder() {
- m_tagMap = new HashMap<CharSequence, CharSequence>();
- }
-
- /**
- * Get a new instance of a TagBuilder object.
- *
- * @return New TagBuilder ojbect for use.
- */
- public static TagBuilder getTagBuilder() {
- return new TagBuilder();
- }
-
- /**
- * @bried Add a tag with an associated log level value.
- *
- * Tag can be any tag for the logger to filter.
- *
- * The log level should be one of the following form:
- * <pre>
- * Log Level | Meaning
- * ===================
- * V : Verbose
- * D : Debug
- * I : Info
- * W : Warning
- * E : Error
- * F : Fatal
- * S : Silent
- * </pre>
- *
- * @param tag Tag for the logger to filter for.
- * @param logLevel Log level for specified tag.
- */
- public void addTag(CharSequence tag, CharSequence logLevel) {
- m_tagMap.put(tag, logLevel);
- }
-
- /**
- * Silence all tags that are not added to the current TagBuilder
- * object.
- */
- public synchronized void addSilenceNonRelatedTags() {
- m_silenceNonRelatedTags = true;
- }
-
- /**
- * Generate a string representing all the tags to be filtered and the
- * relevant log levels.
- *
- * An example of a string returned by this method is:
- *
- * <pre>
- * NFDService:S Strategy:S TcpChannel:S TcpFactory:S TcpLocalFace:S UdpFactory:S *:S
- * </pre>
- *
- * @return String representation of the tags and their relevant log levels to be
- * filtered.
- */
- public String generateTagString() {
- ArrayList<String> tags = new ArrayList<String>();
- for (Map.Entry<CharSequence, CharSequence> item : m_tagMap.entrySet()) {
- tags.add(String.format("%s:%s", item.getKey(), item.getValue()));
- }
-
- Collections.sort(tags);
-
- if (m_silenceNonRelatedTags) {
- tags.add("*:S");
- }
-
- return TextUtils.join(" ", tags);
- }
-
- /** Mapping of tag and log levels */
- private Map<CharSequence, CharSequence> m_tagMap;
-
- /** Flag that determines if all non related tags should be silenced */
- private boolean m_silenceNonRelatedTags;
- }
-
- /** Preference filename */
- private static final String PREFERENCE_NFD_TAGS_FILENAME = "NFD_TAGS_PREFERENCE_FILE";
-
- /** Key in SharedPreference that stores the string of tags */
- private static final String PREFERENCE_NFD_TAGS_KEY = "NFD_TAGS";
-}
diff --git a/app/src/main/java/net/named_data/nfd/utils/NfdcAsyncTask.java b/app/src/main/java/net/named_data/nfd/utils/NfdcAsyncTask.java
deleted file mode 100644
index cbf1406..0000000
--- a/app/src/main/java/net/named_data/nfd/utils/NfdcAsyncTask.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/* -*- Mode:jde; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (c) 2015 Regents of the University of California
- *
- * This file is part of NFD (Named Data Networking Forwarding Daemon) Android.
- * See AUTHORS.md for complete list of NFD Android authors and contributors.
- *
- * 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.
- *
- * 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.
- *
- * 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.utils;
-
-import android.app.ProgressDialog;
-import android.content.Context;
-import android.os.AsyncTask;
-import android.widget.Toast;
-
-
-public class NfdcAsyncTask extends AsyncTask<Void, Void, String> {
-
- public NfdcAsyncTask(Context context, Task task)
- {
- m_context = context;
- m_progressBar = new ProgressDialog(m_context);
- m_task = task;
- }
-
- public interface Task {
- public String
- runTask() throws Exception;
- }
-
- @Override
- protected String
- doInBackground(Void... params)
- {
- try {
- return m_task.runTask();
- }
- catch (Exception e) {
- return "Error communicating with NFD (" + e.getMessage() + ")";
- }
- }
-
- @Override
- protected void
- onPostExecute(String result)
- {
- m_progressBar.dismiss();
- if (result != null)
- Toast.makeText(m_context.getApplicationContext(), result, Toast.LENGTH_LONG).show();
- }
-
- @Override
- protected void
- onPreExecute()
- {
- m_progressBar.setMessage("Communicating with NFD...");
- m_progressBar.show();
- }
-
- @Override
- protected void
- onProgressUpdate(Void... values)
- {
- }
-
- /////////////////////////////////////////////////////////////////////////////
-
- private Context m_context = null;
- private ProgressDialog m_progressBar = null;
- private Task m_task = null;
-}
diff --git a/app/src/main/res/drawable/custom_white_button.xml b/app/src/main/res/drawable/custom_white_button.xml
new file mode 100644
index 0000000..8edfc54
--- /dev/null
+++ b/app/src/main/res/drawable/custom_white_button.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item
+ android:state_pressed="true"
+ android:drawable="@android:color/darker_gray"
+ />
+ <item
+ android:state_pressed="false"
+ android:drawable="@android:color/transparent"
+ />
+</selector>
\ No newline at end of file
diff --git a/app/src/main/res/drawable/drawer_item_background_activated.xml b/app/src/main/res/drawable/drawer_item_background_activated.xml
new file mode 100644
index 0000000..1b497c0
--- /dev/null
+++ b/app/src/main/res/drawable/drawer_item_background_activated.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item
+ android:state_activated="true"
+ android:drawable="@color/ndn_color_fire_bush"
+ />
+</selector>
\ No newline at end of file
diff --git a/app/src/main/res/drawable/face_list_item_background_activated.xml b/app/src/main/res/drawable/face_list_item_background_activated.xml
new file mode 100644
index 0000000..f6a9b13
--- /dev/null
+++ b/app/src/main/res/drawable/face_list_item_background_activated.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item
+ android:state_activated="true"
+ android:drawable="@android:color/darker_gray"
+ />
+</selector>
\ No newline at end of file
diff --git a/app/src/main/res/drawable/item_background_activated.xml b/app/src/main/res/drawable/item_background_activated.xml
new file mode 100644
index 0000000..f6a9b13
--- /dev/null
+++ b/app/src/main/res/drawable/item_background_activated.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item
+ android:state_activated="true"
+ android:drawable="@android:color/darker_gray"
+ />
+</selector>
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_fragment.xml b/app/src/main/res/layout/activity_fragment.xml
new file mode 100644
index 0000000..98ee139
--- /dev/null
+++ b/app/src/main/res/layout/activity_fragment.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<FrameLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/fragment_container"
+ android:layout_height="match_parent"
+ android:layout_width="match_parent"
+ >
+
+</FrameLayout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
new file mode 100644
index 0000000..6d8b08a
--- /dev/null
+++ b/app/src/main/res/layout/activity_main.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<android.support.v4.widget.DrawerLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:id="@+id/drawer_layout"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ tools:context=".MainActivity">
+
+ <!-- Main container for fragments to be presented in -->
+ <FrameLayout
+ android:id="@+id/main_fragment_container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ />
+
+ <!-- DrawerFragment for user navigation -->
+ <FrameLayout
+ android:id="@+id/navigation_drawer"
+ android:layout_width="@dimen/drawer_width"
+ android:layout_height="match_parent"
+ android:layout_gravity="start"
+ tools:layout="@layout/activity_main_drawer_listview"
+ />
+
+</android.support.v4.widget.DrawerLayout>
diff --git a/app/src/main/res/layout/activity_main_drawer_listview.xml b/app/src/main/res/layout/activity_main_drawer_listview.xml
new file mode 100644
index 0000000..7ca3700
--- /dev/null
+++ b/app/src/main/res/layout/activity_main_drawer_listview.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<ListView xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:choiceMode="singleChoice"
+ android:divider="@android:color/transparent"
+ android:dividerHeight="0dp"
+ android:background="#cccc"
+ tools:context=".DrawerFragment"
+/>
diff --git a/app/src/main/res/layout/create_face.xml b/app/src/main/res/layout/create_face.xml
index 6588dcc..02d40a6 100644
--- a/app/src/main/res/layout/create_face.xml
+++ b/app/src/main/res/layout/create_face.xml
@@ -7,7 +7,7 @@
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- style="@style/dialog_margin"
+ style="@style/default_dialog_margin"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="Enter FaceUri for the remote NDN daemon"
android:layout_gravity="center_horizontal"/>
@@ -16,7 +16,7 @@
android:id="@+id/faceUri"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- style="@style/dialog_margin"
+ style="@style/default_dialog_margin"
android:hint="Face URI"
android:inputType="text"
android:focusable="true"
diff --git a/app/src/main/res/layout/create_route.xml b/app/src/main/res/layout/create_route.xml
index ddf7fb2..67c7677 100644
--- a/app/src/main/res/layout/create_route.xml
+++ b/app/src/main/res/layout/create_route.xml
@@ -7,7 +7,7 @@
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- style="@style/dialog_margin"
+ style="@style/default_dialog_margin"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="Enter prefix and FaceUri to register with NDN daemon"
android:layout_gravity="center_horizontal"/>
@@ -16,7 +16,7 @@
android:id="@+id/prefix"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- style="@style/dialog_margin"
+ style="@style/default_dialog_margin"
android:hint="Prefix"
android:inputType="text"
android:focusable="true"
@@ -29,7 +29,7 @@
android:id="@+id/faceUri"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- style="@style/dialog_margin"
+ style="@style/default_dialog_margin"
android:hint="Face URI"
android:inputType="text"
android:focusable="true"
diff --git a/app/src/main/res/layout/face_status_item.xml b/app/src/main/res/layout/face_status_item.xml
deleted file mode 100644
index 9fd2a6b..0000000
--- a/app/src/main/res/layout/face_status_item.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="horizontal"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:padding="10dp">
-
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:text="Title"
- android:id="@+id/title"
- android:textColor="@android:color/primary_text_light"/>
-
- <TextView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:text="Value"
- android:id="@+id/value"
- android:textAlignment="gravity"
- android:gravity="right"
- android:textColor="@android:color/secondary_text_dark"
- android:layout_gravity="right"/>
-</LinearLayout>
diff --git a/app/src/main/res/layout/fragment_face_detail.xml b/app/src/main/res/layout/fragment_face_detail.xml
new file mode 100644
index 0000000..c251036
--- /dev/null
+++ b/app/src/main/res/layout/fragment_face_detail.xml
@@ -0,0 +1,21 @@
+<?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="match_parent"
+ style="@style/default_linear_layout_padding"
+ >
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/fragment_face_details_title"
+ style="?android:listSeparatorTextViewStyle"
+ />
+
+ <include
+ layout="@android:layout/list_content"
+ />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_face_list.xml b/app/src/main/res/layout/fragment_face_list.xml
new file mode 100644
index 0000000..f7c2388
--- /dev/null
+++ b/app/src/main/res/layout/fragment_face_list.xml
@@ -0,0 +1,80 @@
+<?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="match_parent"
+ style="@style/default_linear_layout_padding"
+ >
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/face_list_actions_title"
+ style="?android:listSeparatorTextViewStyle"
+ />
+
+ <Button
+ android:id="@+id/face_list_refresh_button"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/face_list_refresh_face_list"
+ style="@style/default_custom_white_button"
+ />
+ <Button
+ android:id="@+id/face_list_add_button"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/face_list_add_face"
+ style="@style/default_custom_white_button"
+ />
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/face_list_list_of_faces_title"
+ style="?android:listSeparatorTextViewStyle"
+ />
+
+ <FrameLayout
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ >
+
+ <ProgressBar
+ android:id="@+id/face_list_reloading_list_progress_bar"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:visibility="gone"
+ />
+
+ <LinearLayout
+ android:id="@+id/face_list_info_unavailable"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:visibility="gone"
+ >
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/oops"
+ />
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:text="@string/error_cannot_communicate_with_nfd"
+ />
+
+ </LinearLayout>
+
+ <include
+ layout="@android:layout/list_content"
+ />
+
+ </FrameLayout>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_log.xml b/app/src/main/res/layout/fragment_logcat_output.xml
similarity index 100%
rename from app/src/main/res/layout/activity_log.xml
rename to app/src/main/res/layout/fragment_logcat_output.xml
diff --git a/app/src/main/res/layout/fragment_logcat_tags_list.xml b/app/src/main/res/layout/fragment_logcat_tags_list.xml
new file mode 100644
index 0000000..2688e0d
--- /dev/null
+++ b/app/src/main/res/layout/fragment_logcat_tags_list.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="match_parent"
+ style="@style/default_linear_layout_padding"
+ >
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/fragment_logcat_general_operations_category"
+ style="?android:listSeparatorTextViewStyle"
+ />
+
+ <Button
+ android:id="@+id/logcat_reset_loglevel_defaults"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/logcat_reset_log_level_defaults"
+ style="@style/default_custom_white_button"
+ />
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/fragment_logcat_tags_n_log_levels"
+ style="?android:listSeparatorTextViewStyle"
+ />
+
+ <include
+ layout="@android:layout/list_content"
+ />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_main.xml b/app/src/main/res/layout/fragment_main.xml
new file mode 100644
index 0000000..9fa4afa
--- /dev/null
+++ b/app/src/main/res/layout/fragment_main.xml
@@ -0,0 +1,25 @@
+<?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="match_parent"
+ style="@style/default_linear_layout_padding"
+ >
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/pref_category_title_general"
+ style="?android:listSeparatorTextViewStyle"
+ />
+
+ <Switch
+ android:id="@+id/nfd_start_stop_switch"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:text="@string/checking_on_nfd"
+ />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_route_list.xml b/app/src/main/res/layout/fragment_route_list.xml
new file mode 100644
index 0000000..b1d481b
--- /dev/null
+++ b/app/src/main/res/layout/fragment_route_list.xml
@@ -0,0 +1,80 @@
+<?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="match_parent"
+ style="@style/default_linear_layout_padding"
+ >
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/route_list_actions_title"
+ style="?android:listSeparatorTextViewStyle"
+ />
+
+ <Button
+ android:id="@+id/route_list_refresh_button"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/route_list_refresh_route_list"
+ style="@style/default_custom_white_button"
+ />
+ <Button
+ android:id="@+id/route_list_add_button"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/route_list_add_route"
+ style="@style/default_custom_white_button"
+ />
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/route_list_list_of_routes_title"
+ style="?android:listSeparatorTextViewStyle"
+ />
+
+ <FrameLayout
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ >
+
+ <ProgressBar
+ android:id="@+id/route_list_reloading_list_progress_bar"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:visibility="gone"
+ />
+
+ <LinearLayout
+ android:id="@+id/route_list_info_unavailable"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:visibility="gone"
+ >
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/oops"
+ />
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:text="@string/error_cannot_communicate_with_nfd"
+ />
+
+ </LinearLayout>
+
+ <include
+ layout="@android:layout/list_content"
+ />
+
+ </FrameLayout>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/list_item_drawer_item.xml b/app/src/main/res/layout/list_item_drawer_item.xml
new file mode 100644
index 0000000..08a598b
--- /dev/null
+++ b/app/src/main/res/layout/list_item_drawer_item.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@drawable/drawer_item_background_activated"
+ android:paddingLeft="@dimen/default_padding_left"
+ android:paddingRight="@dimen/default_padding_right"
+ >
+
+ <ImageView
+ android:id="@+id/drawer_item_icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ />
+
+ <TextView
+ android:id="@+id/drawer_item_text"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:textAppearance="?android:attr/textAppearanceListItemSmall"
+ android:minHeight="?android:attr/listPreferredItemHeightSmall"
+ android:gravity="center_vertical"
+ />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/list_item_face_generic_item.xml b/app/src/main/res/layout/list_item_face_generic_item.xml
new file mode 100644
index 0000000..7683c68
--- /dev/null
+++ b/app/src/main/res/layout/list_item_face_generic_item.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ >
+
+ <TextView
+ android:id="@+id/list_item_generic_title"
+ android:text="Title"
+ style="@style/two_column_item_title"
+ />
+
+ <TextView
+ android:id="@+id/list_item_generic_value"
+ android:text="Value"
+ style="@style/two_column_item_secondary"
+ />
+
+</LinearLayout>
diff --git a/app/src/main/res/layout/list_item_face_status_item.xml b/app/src/main/res/layout/list_item_face_status_item.xml
new file mode 100644
index 0000000..0b6a1d0
--- /dev/null
+++ b/app/src/main/res/layout/list_item_face_status_item.xml
@@ -0,0 +1,22 @@
+<?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"
+ android:background="@drawable/item_background_activated"
+ >
+
+ <TextView
+ android:id="@+id/list_item_face_uri"
+ android:text="FaceUri"
+ style="@style/two_row_item_title"
+ />
+
+ <TextView
+ android:id="@+id/list_item_face_id"
+ android:text="FaceId"
+ style="@style/two_row_item_secondary"
+ />
+
+</LinearLayout>
diff --git a/app/src/main/res/layout/log_item.xml b/app/src/main/res/layout/list_item_log.xml
similarity index 100%
rename from app/src/main/res/layout/log_item.xml
rename to app/src/main/res/layout/list_item_log.xml
diff --git a/app/src/main/res/layout/list_item_route_item.xml b/app/src/main/res/layout/list_item_route_item.xml
new file mode 100644
index 0000000..baa6da0
--- /dev/null
+++ b/app/src/main/res/layout/list_item_route_item.xml
@@ -0,0 +1,22 @@
+<?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"
+ android:background="@drawable/item_background_activated"
+ >
+
+ <TextView
+ android:id="@+id/list_item_route_uri"
+ android:text="Route"
+ style="@style/two_row_item_title"
+ />
+
+ <TextView
+ android:id="@+id/list_item_face_list"
+ android:text="Faces"
+ style="@style/two_row_item_secondary"
+ />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/list_item_setting_item.xml b/app/src/main/res/layout/list_item_setting_item.xml
new file mode 100644
index 0000000..4d8498b
--- /dev/null
+++ b/app/src/main/res/layout/list_item_setting_item.xml
@@ -0,0 +1,20 @@
+<?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"
+ android:background="@drawable/item_background_activated"
+ >
+
+ <TextView
+ android:id="@+id/list_item_log_tag"
+ style="@style/two_row_item_title"
+ />
+
+ <TextView
+ android:id="@+id/list_item_setting_log_level"
+ style="@style/two_row_item_secondary"
+ />
+
+</LinearLayout>
\ 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
new file mode 100644
index 0000000..1664611
--- /dev/null
+++ b/app/src/main/res/menu/menu_face_list_multiple_modal_menu.xml
@@ -0,0 +1,12 @@
+<?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_delete_face_item"
+ android:icon="@android:drawable/ic_menu_delete"
+ android:title="@string/menu_item_delete_face_item"
+ app:showAsAction="ifRoom|withText"
+ />
+
+</menu>
\ No newline at end of file
diff --git a/app/src/main/res/menu/menu_log.xml b/app/src/main/res/menu/menu_log.xml
index b749bbe..a530929 100644
--- a/app/src/main/res/menu/menu_log.xml
+++ b/app/src/main/res/menu/menu_log.xml
@@ -7,6 +7,7 @@
android:id="@+id/action_log_settings"
android:title="@string/log_settings"
android:orderInCategory="100"
- app:showAsAction="never" />
+ app:showAsAction="never"
+ />
</menu>
diff --git a/app/src/main/res/menu/menu_logcat_settings_multiple_modal_menu.xml b/app/src/main/res/menu/menu_logcat_settings_multiple_modal_menu.xml
new file mode 100644
index 0000000..2bbf336
--- /dev/null
+++ b/app/src/main/res/menu/menu_logcat_settings_multiple_modal_menu.xml
@@ -0,0 +1,12 @@
+<?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_delete_setting_item"
+ android:icon="@android:drawable/ic_menu_delete"
+ android:title="@string/menu_item_delete_setting_item"
+ app:showAsAction="ifRoom|withText"
+ />
+
+</menu>
\ No newline at end of file
diff --git a/app/src/main/res/values-sw600dp/dimens.xml b/app/src/main/res/values-sw600dp/dimens.xml
new file mode 100644
index 0000000..a125d29
--- /dev/null
+++ b/app/src/main/res/values-sw600dp/dimens.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <dimen name="default_padding_left">48dp</dimen>
+ <dimen name="default_padding_right">48dp</dimen>
+</resources>
\ No newline at end of file
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
new file mode 100644
index 0000000..92b2b4b
--- /dev/null
+++ b/app/src/main/res/values/colors.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <item name="ndn_color_fire_bush" type="color">#DB9710</item>
+ <item name="ndn_color_grenadier" type="color">#C04818</item>
+</resources>
\ No newline at end of file
diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml
index 47c8224..5d96952 100644
--- a/app/src/main/res/values/dimens.xml
+++ b/app/src/main/res/values/dimens.xml
@@ -2,4 +2,8 @@
<!-- Default screen margins, per the Android Design guidelines. -->
<dimen name="activity_horizontal_margin">16dp</dimen>
<dimen name="activity_vertical_margin">16dp</dimen>
+
+ <dimen name="default_padding_left">16dp</dimen>
+ <dimen name="default_padding_right">16dp</dimen>
+ <dimen name="drawer_width">192dp</dimen>
</resources>
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index a8f78fd..dc86688 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -2,15 +2,56 @@
<string name="app_name">NFD</string>
<string name="service_name">NFD Service</string>
<string name="action_settings">Settings</string>
- <string name="stop_nfd">Stop NFD</string>
- <string name="start_nfd">Start NFD</string>
- <string name="reconnecting_to_nfd">Please wait while we connect to the NFD Service.</string>
- <string name="stopping_nfd">Stopping NFD ...</string>
- <string name="starting_nfd">Starting NFD ...</string>
- <string name="reconnect_to_nfd">Reconnecting to NFD Service</string>
- <string name="loading_logger">Loading logger ...</string>
- <string name="nfd_logger">NFD Logger</string>
+ <string name="nfd_stopped">NFD is stopped</string>
+ <string name="nfd_started">NFD is started</string>
+ <string name="stopping_nfd">Stopping NFD …</string>
+ <string name="starting_nfd">Starting NFD …</string>
+ <string name="reconnect_to_nfd">Reconnecting to NFD Service …</string>
+ <string name="loading_logger">Loading logger …</string>
<string name="log_settings">Log Settings</string>
- <string name="nfd_log_settings">NFD Log Settings</string>
- <string name="checking_on_nfd">Checking on NFD Service ...</string>
+ <string name="checking_on_nfd">Checking on NFD Service …</string>
+ <string name="accessibility_open_drawer">Open NFD Navigation Drawer</string>
+ <string name="accessibility_close_drawer">Close NFD Navigation Drawer</string>
+ <string name="drawer_item_general">General</string>
+ <string name="drawer_item_faces">Faces</string>
+ <string name="drawer_item_routes">Routes</string>
+ <string name="drawer_item_strategies">Strategies</string>
+ <string name="drawer_item_logcat">Logcat</string>
+ <string name="menu_item_delete_setting_item">Delete</string>
+ <string name="fragment_logcat_general_operations_category">General Actions</string>
+ <string name="fragment_logcat_tags_n_log_levels">Tags & Log Levels</string>
+ <string name="logcat_reset_log_level_defaults">Reset Log Level Defaults</string>
+ <string name="reset_log_level_dialog_title">Select default value for all tags</string>
+ <string name="route_list_actions_title">Route List Actions</string>
+ <string name="oops">Oops!</string>
+ <string name="error_cannot_communicate_with_nfd">Not available, check that NFD is started</string>
+ <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="face_list_actions_title">Face List Actions</string>
+ <string name="face_list_refresh_face_list">Refresh Face List</string>
+ <string name="face_list_add_face">Add Face</string>
+ <string name="face_list_list_of_faces_title">List of Faces</string>
+ <string name="fragment_face_details_title">Face Details</string>
+ <string name="menu_item_delete_face_item">Delete</string>
+ <string name="expire_never">Never</string>
+
+ <string-array name="face_scopes">
+ <item>Local</item>
+ <item>Non-local</item>
+ </string-array>
+
+ <string-array name="face_persistency">
+ <item>Persistent</item>
+ <item>On-demand</item>
+ <item>Permanent</item>
+ </string-array>
+
+ <string-array name="face_link_types">
+ <item>Point-to-point</item>
+ <item>Multi-access</item>
+ </string-array>
+
+ <string name="face_add_dialog_create_face">Create face</string>
+ <string name="route_add_dialog_create_route">Create route</string>
</resources>
diff --git a/app/src/main/res/values/strings_logcat_settings_activity.xml b/app/src/main/res/values/strings_logcat_settings_activity.xml
index 36e89a7..47d5221 100644
--- a/app/src/main/res/values/strings_logcat_settings_activity.xml
+++ b/app/src/main/res/values/strings_logcat_settings_activity.xml
@@ -2,56 +2,8 @@
<!-- Strings related to NFD Log Settings -->
- <!-- Set all tags log level -->
- <string name="pref_tags_log_level_title_key">All_Log_Levels_Key</string>
- <string name="pref_tags_log_level_title">All Log Levels</string>
- <string name="pref_tags_log_level_key">Reset_All_Tags_Log_Level_Key</string>
- <string name="pref_tags_log_level">Reset</string>
-
- <!-- Tags -->
- <string name="pref_category_title_tags">NFD Tags & Log Levels</string>
- <string name="pref_category_title_tags_key">NFD_Tags_Key</string>
-
- <!-- Tag Display Names -->
- <string name="pref_tag_commandvalidator">CommandValidator</string>
- <string name="pref_tag_facemanager">FaceManager</string>
- <string name="pref_tag_facetable">FaceTable</string>
- <string name="pref_tag_fibmanager">FibManager</string>
- <string name="pref_tag_generalconfigsection">GeneralConfigSection</string>
- <string name="pref_tag_internalface">InternalFace</string>
- <string name="pref_tag_managerbase">ManagerBase</string>
- <string name="pref_tag_privilegehelper">PrivilegeHelper</string>
- <string name="pref_tag_remoteregistrator">RemoteRegistrator</string>
- <string name="pref_tag_ribmanager">RibManager</string>
- <string name="pref_tag_strategy">Strategy</string>
- <string name="pref_tag_strategychoice">StrategyChoice</string>
- <string name="pref_tag_tablesconfigsection">TablesConfigSection</string>
- <string name="pref_tag_tcpchannel">TcpChannel</string>
- <string name="pref_tag_tcpfactory">TcpFactory</string>
- <string name="pref_tag_tcplocalface">TcpLocalFace</string>
- <string name="pref_tag_udpfactory">UdpFactory</string>
-
- <!-- Tag Keys -->
- <string name="pref_tag_commandvalidator_key">CommandValidator</string>
- <string name="pref_tag_facemanager_key">FaceManager</string>
- <string name="pref_tag_facetable_key">FaceTable</string>
- <string name="pref_tag_fibmanager_key">FibManager</string>
- <string name="pref_tag_generalconfigsection_key">GeneralConfigSection</string>
- <string name="pref_tag_internalface_key">InternalFace</string>
- <string name="pref_tag_managerbase_key">ManagerBase</string>
- <string name="pref_tag_privilegehelper_key">PrivilegeHelper</string>
- <string name="pref_tag_remoteregistrator_key">RemoteRegistrator</string>
- <string name="pref_tag_ribmanager_key">RibManager</string>
- <string name="pref_tag_strategy_key">Strategy</string>
- <string name="pref_tag_strategychoice_key">StrategyChoice</string>
- <string name="pref_tag_tablesconfigsection_key">TablesConfigSection</string>
- <string name="pref_tag_tcpchannel_key">TcpChannel</string>
- <string name="pref_tag_tcpfactory_key">TcpFactory</string>
- <string name="pref_tag_tcplocalface_key">TcpLocalFace</string>
- <string name="pref_tag_udpfactory_key">UdpFactory</string>
-
<!-- Log Levels -->
- <string-array name="pref_log_levels">
+ <string-array name="reset_log_level_values">
<item>Verbose</item>
<item>Debug</item>
<item>Info</item>
@@ -61,15 +13,40 @@
<item>Silent</item>
</string-array>
- <!-- Log Level Command Tag-->
- <string-array name="pref_log_level_values">
- <item>V</item>
- <item>D</item>
- <item>I</item>
- <item>W</item>
- <item>E</item>
- <item>F</item>
- <item>S</item>
+ <!-- Log Level Mapping -->
+ <!--
+ This mapping is used for Logcat arguments and should be in the format of:
+ <display description>:<logcat priority value>
+ -->
+ <string-array name="logcat_log_level_map">
+ <item>Verbose:V</item>
+ <item>Debug:D</item>
+ <item>Info:I</item>
+ <item>Warn:W</item>
+ <item>Error:E</item>
+ <item>Fatal:F</item>
+ <item>Silent:S</item>
+ </string-array>
+
+ <!-- Default lag tags and log levels when no previous settings are found -->
+ <string-array name="default_log_tags_and_levels">
+ <item>CommandValidator:V</item>
+ <item>FaceManager:V</item>
+ <item>FaceTable:V</item>
+ <item>FibManager:V</item>
+ <item>GeneralConfigSection:V</item>
+ <item>InternalFace:V</item>
+ <item>ManagerBase:V</item>
+ <item>PrivilegeHelper:V</item>
+ <item>RemoteRegistrator:V</item>
+ <item>RibManager:V</item>
+ <item>Strategy:V</item>
+ <item>StrategyChoice:V</item>
+ <item>TablesConfigSection:V</item>
+ <item>TcpChannel:V</item>
+ <item>TcpFactory:V</item>
+ <item>TcpLocalFace:V</item>
+ <item>UdpFactory:V</item>
</string-array>
</resources>
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index 9484591..08a8a5c 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -5,11 +5,57 @@
<!-- Customize your theme here. -->
</style>
- <style name="dialog_margin">
+ <style name="default_dialog_margin">
<item name="android:layout_marginTop">16dp</item>
<item name="android:layout_marginLeft">4dp</item>
<item name="android:layout_marginRight">4dp</item>
<item name="android:layout_marginBottom">4dp</item>
</style>
+ <style name="default_linear_layout_padding">
+ <item name="android:paddingLeft">@dimen/default_padding_left</item>
+ <item name="android:paddingRight">@dimen/default_padding_right</item>
+ </style>
+
+ <style name="default_custom_white_button">
+ <item name="android:gravity">left|center_vertical</item>
+ <item name="android:background">@drawable/custom_white_button</item>
+ <item name="android:textColor">@android:color/primary_text_light</item>
+ <item name="android:textAppearance">?android:textAppearanceSmall</item>
+ </style>
+
+ <style name="item_title">
+ <item name="android:textAppearance">?android:textAppearanceSmall</item>
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:textColor">@android:color/primary_text_light</item>
+ </style>
+
+ <style name="item_secondary">
+ <item name="android:textAppearance">?android:textAppearanceSmall</item>
+ <item name="android:textColor">@android:color/secondary_text_dark</item>
+ </style>
+
+ <style name="two_row_item_title" parent="item_title">
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">wrap_content</item>
+ </style>
+
+ <style name="two_row_item_secondary" parent="item_secondary">
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">wrap_content</item>
+ </style>
+
+ <style name="two_column_item_title" parent="item_title">
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">wrap_content</item>
+ </style>
+
+ <style name="two_column_item_secondary" parent="item_secondary">
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:gravity">right</item>
+ <item name="android:layout_gravity">right</item>
+ </style>
+
</resources>
diff --git a/app/src/main/res/xml/pref_general.xml b/app/src/main/res/xml/pref_general.xml
deleted file mode 100644
index 7195806..0000000
--- a/app/src/main/res/xml/pref_general.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
- <!-- General section -->
- <PreferenceCategory
- android:key="@string/pref_category_title_general"
- android:title="@string/pref_category_title_general">
-
- <Preference
- android:title="@string/start_nfd"
- android:key="start_stop" />
-
- <PreferenceScreen
- android:title="NFD log"
- android:key="nfd_log">
- <intent
- android:action="android.intent.action.VIEW"
- android:targetPackage="net.named_data.nfd"
- android:targetClass="net.named_data.nfd.LogcatActivity" />
- </PreferenceScreen>
-
- </PreferenceCategory>
-</PreferenceScreen>
diff --git a/app/src/main/res/xml/pref_nfd_log.xml b/app/src/main/res/xml/pref_nfd_log.xml
deleted file mode 100644
index 37a0432..0000000
--- a/app/src/main/res/xml/pref_nfd_log.xml
+++ /dev/null
@@ -1,175 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
- <PreferenceCategory
- android:key="@string/pref_tags_log_level_title_key"
- android:title="@string/pref_tags_log_level_title">
-
- <ListPreference
- android:key="@string/pref_tags_log_level_key"
- android:title="@string/pref_tags_log_level"
- android:entries="@array/pref_log_levels"
- android:entryValues="@array/pref_log_level_values"
- android:negativeButtonText="@null"
- android:positiveButtonText="@null" />
-
- </PreferenceCategory>
-
- <PreferenceCategory
- android:key="@string/pref_category_title_tags_key"
- android:title="@string/pref_category_title_tags">
-
- <ListPreference
- android:key="@string/pref_tag_commandvalidator_key"
- android:title="@string/pref_tag_commandvalidator"
- android:entries="@array/pref_log_levels"
- android:entryValues="@array/pref_log_level_values"
- android:defaultValue="I"
- android:negativeButtonText="@null"
- android:positiveButtonText="@null" />
-
- <ListPreference
- android:key="@string/pref_tag_facemanager_key"
- android:title="@string/pref_tag_facemanager"
- android:entries="@array/pref_log_levels"
- android:entryValues="@array/pref_log_level_values"
- android:defaultValue="I"
- android:negativeButtonText="@null"
- android:positiveButtonText="@null" />
-
- <ListPreference
- android:key="@string/pref_tag_facetable_key"
- android:title="@string/pref_tag_facetable"
- android:entries="@array/pref_log_levels"
- android:entryValues="@array/pref_log_level_values"
- android:defaultValue="I"
- android:negativeButtonText="@null"
- android:positiveButtonText="@null" />
-
- <ListPreference
- android:key="@string/pref_tag_fibmanager_key"
- android:title="@string/pref_tag_fibmanager"
- android:entries="@array/pref_log_levels"
- android:entryValues="@array/pref_log_level_values"
- android:defaultValue="I"
- android:negativeButtonText="@null"
- android:positiveButtonText="@null" />
-
- <ListPreference
- android:key="@string/pref_tag_generalconfigsection_key"
- android:title="@string/pref_tag_generalconfigsection"
- android:entries="@array/pref_log_levels"
- android:entryValues="@array/pref_log_level_values"
- android:defaultValue="I"
- android:negativeButtonText="@null"
- android:positiveButtonText="@null" />
-
- <ListPreference
- android:key="@string/pref_tag_internalface_key"
- android:title="@string/pref_tag_internalface"
- android:entries="@array/pref_log_levels"
- android:entryValues="@array/pref_log_level_values"
- android:defaultValue="I"
- android:negativeButtonText="@null"
- android:positiveButtonText="@null" />
-
- <ListPreference
- android:key="@string/pref_tag_managerbase_key"
- android:title="@string/pref_tag_managerbase"
- android:entries="@array/pref_log_levels"
- android:entryValues="@array/pref_log_level_values"
- android:defaultValue="I"
- android:negativeButtonText="@null"
- android:positiveButtonText="@null" />
-
- <ListPreference
- android:key="@string/pref_tag_privilegehelper_key"
- android:title="@string/pref_tag_privilegehelper"
- android:entries="@array/pref_log_levels"
- android:entryValues="@array/pref_log_level_values"
- android:defaultValue="I"
- android:negativeButtonText="@null"
- android:positiveButtonText="@null" />
-
- <ListPreference
- android:key="@string/pref_tag_remoteregistrator_key"
- android:title="@string/pref_tag_remoteregistrator"
- android:entries="@array/pref_log_levels"
- android:entryValues="@array/pref_log_level_values"
- android:defaultValue="I"
- android:negativeButtonText="@null"
- android:positiveButtonText="@null" />
-
- <ListPreference
- android:key="@string/pref_tag_ribmanager_key"
- android:title="@string/pref_tag_ribmanager"
- android:entries="@array/pref_log_levels"
- android:entryValues="@array/pref_log_level_values"
- android:defaultValue="I"
- android:negativeButtonText="@null"
- android:positiveButtonText="@null" />
-
- <ListPreference
- android:key="@string/pref_tag_strategy_key"
- android:title="@string/pref_tag_strategy"
- android:entries="@array/pref_log_levels"
- android:entryValues="@array/pref_log_level_values"
- android:defaultValue="I"
- android:negativeButtonText="@null"
- android:positiveButtonText="@null" />
-
- <ListPreference
- android:key="@string/pref_tag_strategychoice_key"
- android:title="@string/pref_tag_strategychoice"
- android:entries="@array/pref_log_levels"
- android:entryValues="@array/pref_log_level_values"
- android:defaultValue="I"
- android:negativeButtonText="@null"
- android:positiveButtonText="@null" />
-
- <ListPreference
- android:key="@string/pref_tag_tablesconfigsection_key"
- android:title="@string/pref_tag_tablesconfigsection"
- android:entries="@array/pref_log_levels"
- android:entryValues="@array/pref_log_level_values"
- android:defaultValue="I"
- android:negativeButtonText="@null"
- android:positiveButtonText="@null" />
-
- <ListPreference
- android:key="@string/pref_tag_tcpchannel_key"
- android:title="@string/pref_tag_tcpchannel"
- android:entries="@array/pref_log_levels"
- android:entryValues="@array/pref_log_level_values"
- android:defaultValue="I"
- android:negativeButtonText="@null"
- android:positiveButtonText="@null" />
-
- <ListPreference
- android:key="@string/pref_tag_tcpfactory_key"
- android:title="@string/pref_tag_tcpfactory"
- android:entries="@array/pref_log_levels"
- android:entryValues="@array/pref_log_level_values"
- android:defaultValue="I"
- android:negativeButtonText="@null"
- android:positiveButtonText="@null" />
-
- <ListPreference
- android:key="@string/pref_tag_tcplocalface_key"
- android:title="@string/pref_tag_tcplocalface"
- android:entries="@array/pref_log_levels"
- android:entryValues="@array/pref_log_level_values"
- android:defaultValue="I"
- android:negativeButtonText="@null"
- android:positiveButtonText="@null" />
-
- <ListPreference
- android:key="@string/pref_tag_udpfactory_key"
- android:title="@string/pref_tag_udpfactory"
- android:entries="@array/pref_log_levels"
- android:entryValues="@array/pref_log_level_values"
- android:defaultValue="I"
- android:negativeButtonText="@null"
- android:positiveButtonText="@null" />
-
- </PreferenceCategory>
-</PreferenceScreen>