diff --git a/res/layout/fragment_netdb_leaseset_detail.xml b/res/layout/fragment_netdb_leaseset_detail.xml
index 93575eb7d..87bbdddd9 100644
--- a/res/layout/fragment_netdb_leaseset_detail.xml
+++ b/res/layout/fragment_netdb_leaseset_detail.xml
@@ -14,11 +14,53 @@
android:textAppearance="?android:attr/textAppearanceMedium" />
+
+
+
+
+
+
+
+
+
+
+
diff --git a/res/layout/fragment_netdb_router_detail.xml b/res/layout/fragment_netdb_router_detail.xml
index f0eb57eb1..938cee4f2 100644
--- a/res/layout/fragment_netdb_router_detail.xml
+++ b/res/layout/fragment_netdb_router_detail.xml
@@ -10,4 +10,53 @@
android:layout_alignParentLeft="true"
android:text="Router hash" />
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/net/i2p/android/router/activity/NetDbActivity.java b/src/net/i2p/android/router/activity/NetDbActivity.java
index e52256482..c4b79ca44 100644
--- a/src/net/i2p/android/router/activity/NetDbActivity.java
+++ b/src/net/i2p/android/router/activity/NetDbActivity.java
@@ -4,7 +4,7 @@ import net.i2p.android.router.R;
import net.i2p.android.router.fragment.NetDbDetailFragment;
import net.i2p.android.router.fragment.NetDbListFragment;
import net.i2p.android.router.fragment.NetDbSummaryPagerFragment;
-import net.i2p.android.router.loader.NetDbEntry;
+import net.i2p.data.Hash;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.Fragment;
@@ -110,22 +110,22 @@ public class NetDbActivity extends I2PActivityBase implements
// NetDbListFragment.OnEntrySelectedListener
- public void onEntrySelected(NetDbEntry entry) {
+ public void onEntrySelected(boolean isRouterInfo, Hash entryHash) {
if (mTwoPane) {
// In two-pane mode, show the detail view in this activity by
// adding or replacing the detail fragment using a
// fragment transaction.
NetDbDetailFragment detailFrag = NetDbDetailFragment.newInstance(
- entry.isRouterInfo(), entry.getHash());
+ isRouterInfo, entryHash);
getSupportFragmentManager().beginTransaction()
.replace(R.id.detail_fragment, detailFrag).commit();
} else {
// In single-pane mode, simply start the detail activity
// for the selected item ID.
Intent detailIntent = new Intent(this, NetDbDetailActivity.class);
- detailIntent.putExtra(NetDbDetailFragment.IS_RI, entry.isRouterInfo());
+ detailIntent.putExtra(NetDbDetailFragment.IS_RI, isRouterInfo);
detailIntent.putExtra(NetDbDetailFragment.ENTRY_HASH,
- entry.getHash().toBase64());
+ entryHash.toBase64());
startActivity(detailIntent);
}
}
diff --git a/src/net/i2p/android/router/activity/NetDbDetailActivity.java b/src/net/i2p/android/router/activity/NetDbDetailActivity.java
index 62c8f7d1c..b670dcc49 100644
--- a/src/net/i2p/android/router/activity/NetDbDetailActivity.java
+++ b/src/net/i2p/android/router/activity/NetDbDetailActivity.java
@@ -2,13 +2,16 @@ package net.i2p.android.router.activity;
import net.i2p.android.router.R;
import net.i2p.android.router.fragment.NetDbDetailFragment;
+import net.i2p.android.router.fragment.NetDbListFragment;
import net.i2p.android.router.service.RouterService;
import net.i2p.android.router.util.Util;
import net.i2p.data.DataFormatException;
import net.i2p.data.Hash;
+import android.content.Intent;
import android.os.Bundle;
-public class NetDbDetailActivity extends I2PActivityBase {
+public class NetDbDetailActivity extends I2PActivityBase implements
+ NetDbListFragment.OnEntrySelectedListener {
NetDbDetailFragment mDetailFrag;
@Override
@@ -34,4 +37,15 @@ public class NetDbDetailActivity extends I2PActivityBase {
protected void onRouterBind(RouterService svc) {
mDetailFrag.onRouterBind();
}
+
+ // NetDbListFragment.OnEntrySelectedListener
+
+ public void onEntrySelected(boolean isRouterInfo, Hash entryHash) {
+ // Start the detail activity for the selected item ID.
+ Intent detailIntent = new Intent(this, NetDbDetailActivity.class);
+ detailIntent.putExtra(NetDbDetailFragment.IS_RI, isRouterInfo);
+ detailIntent.putExtra(NetDbDetailFragment.ENTRY_HASH,
+ entryHash.toBase64());
+ startActivity(detailIntent);
+ }
}
diff --git a/src/net/i2p/android/router/fragment/NetDbDetailFragment.java b/src/net/i2p/android/router/fragment/NetDbDetailFragment.java
index f9f7b6bf0..0b1fac803 100644
--- a/src/net/i2p/android/router/fragment/NetDbDetailFragment.java
+++ b/src/net/i2p/android/router/fragment/NetDbDetailFragment.java
@@ -1,22 +1,36 @@
package net.i2p.android.router.fragment;
+import java.util.Map;
+import java.util.Set;
+
import net.i2p.android.router.R;
+import net.i2p.android.router.fragment.NetDbListFragment.OnEntrySelectedListener;
import net.i2p.android.router.loader.NetDbEntry;
import net.i2p.android.router.util.Util;
import net.i2p.data.DataFormatException;
+import net.i2p.data.DataHelper;
import net.i2p.data.Hash;
+import net.i2p.data.Lease;
import net.i2p.data.LeaseSet;
+import net.i2p.data.RouterAddress;
import net.i2p.data.RouterInfo;
+import android.app.Activity;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
+import android.view.View.OnClickListener;
import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.LinearLayout;
+import android.widget.TableLayout;
+import android.widget.TableRow;
import android.widget.TextView;
public class NetDbDetailFragment extends I2PFragmentBase {
public static final String IS_RI = "is_routerinfo";
public static final String ENTRY_HASH = "entry_hash";
+ OnEntrySelectedListener mEntrySelectedCallback;
private NetDbEntry mEntry;
public static NetDbDetailFragment newInstance(boolean isRI, Hash hash) {
@@ -28,6 +42,21 @@ public class NetDbDetailFragment extends I2PFragmentBase {
return f;
}
+ @Override
+ public void onAttach(Activity activity) {
+ super.onAttach(activity);
+
+ // This makes sure that the container activity has implemented
+ // the callback interface. If not, it throws an exception
+ try {
+ mEntrySelectedCallback = (OnEntrySelectedListener) activity;
+ } catch (ClassCastException e) {
+ throw new ClassCastException(activity.toString()
+ + " must implement OnEntrySelectedListener");
+ }
+
+ }
+
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
@@ -60,21 +89,162 @@ public class NetDbDetailFragment extends I2PFragmentBase {
try {
hash.fromBase64(getArguments().getString(ENTRY_HASH));
if (getArguments().getBoolean(IS_RI)) {
+ // Load RouterInfo
RouterInfo ri = getNetDb().lookupRouterInfoLocally(hash);
- mEntry = NetDbEntry.fromRouterInfo(getRouterContext(), ri);
+ loadRouterInfo(ri);
} else {
+ // Load LeaseSet
LeaseSet ls = getNetDb().lookupLeaseSetLocally(hash);
- mEntry = NetDbEntry.fromLeaseSet(getRouterContext(), ls);
-
- TextView nickname = (TextView) getView().findViewById(R.id.ls_nickname);
- nickname.setText(mEntry.getNickname());
+ loadLeaseSet(ls);
}
-
- TextView entryHash = (TextView) getView().findViewById(R.id.dbentry_hash);
- entryHash.setText(hash.toBase64());
} catch (DataFormatException e) {
Util.e(e.toString());
}
}
}
+
+ private void loadRouterInfo(RouterInfo ri) {
+ mEntry = NetDbEntry.fromRouterInfo(getRouterContext(), ri);
+
+ if (mEntry.isUs())
+ getActivity().setTitle("Our info");
+ else
+ getActivity().setTitle("Peer info");
+
+ TextView entryHash = (TextView) getView().findViewById(R.id.dbentry_hash);
+ entryHash.setText(mEntry.getHash().toBase64());
+
+ if (mEntry.isUs() && getRouter().isHidden()) {
+ TextView pubLabel = (TextView) getView().findViewById(R.id.label_ri_published);
+ pubLabel.setText("Hidden, Updated:");
+ }
+
+ TextView published = (TextView) getView().findViewById(R.id.ri_published);
+ long age = getRouterContext().clock().now() - ri.getPublished();
+ if (age > 0) {
+ published.setText(DataHelper.formatDuration(age) + " ago");
+ } else {
+ // shouldn't happen
+ published.setText(DataHelper.formatDuration(0-age) + " ago???");
+ }
+
+ LinearLayout addresses = (LinearLayout) getView().findViewById(R.id.ri_addresses);
+ for (RouterAddress addr : ri.getAddresses()) {
+ addAddress(addresses, addr);
+ }
+
+ TableLayout stats = (TableLayout) getView().findViewById(R.id.ri_stats);
+ Map p = ri.getOptionsMap();
+ for (Map.Entry e : (Set>) p.entrySet()) {
+ String key = e.getKey();
+ String val = e.getValue();
+ addTableRow(stats, DataHelper.stripHTML(key), DataHelper.stripHTML(val));
+ }
+ }
+
+ private void addAddress(LinearLayout addresses, RouterAddress addr) {
+ TableLayout table = new TableLayout(getActivity());
+
+ String style = addr.getTransportStyle();
+ addTableRow(table, "Style", style);
+
+ int cost = addr.getCost();
+ if (!((style.equals("SSU") && cost == 5) || (style.equals("NTCP") && cost == 10)))
+ addTableRow(table, "cost", ""+cost);
+
+ Map p = addr.getOptionsMap();
+ for (Map.Entry e : (Set>) p.entrySet()) {
+ String key = e.getKey();
+ String val = e.getValue();
+ addTableRow(table, DataHelper.stripHTML(key), DataHelper.stripHTML(val));
+ }
+
+ addresses.addView(table);
+ }
+
+ private void loadLeaseSet(LeaseSet ls) {
+ mEntry = NetDbEntry.fromLeaseSet(getRouterContext(), ls);
+
+ getActivity().setTitle("LeaseSet");
+
+ TextView nickname = (TextView) getView().findViewById(R.id.ls_nickname);
+ nickname.setText(mEntry.getNickname());
+
+ TextView type = (TextView) getView().findViewById(R.id.ls_type);
+ if (mEntry.isLocal()) {
+ if (mEntry.isUnpublished())
+ type.setText("Local Unpublished Destination");
+ else
+ type.setText("Local Destination");
+ }
+
+ TextView entryHash = (TextView) getView().findViewById(R.id.dbentry_hash);
+ entryHash.setText(mEntry.getHash().toBase64());
+
+ TextView expiry = (TextView) getView().findViewById(R.id.ls_expiry);
+ long exp = ls.getLatestLeaseDate() - getRouterContext().clock().now();
+ if (exp > 0) {
+ expiry.setText(DataHelper.formatDuration(exp));
+ } else {
+ TextView expiryLabel = (TextView) getView().findViewById(R.id.label_ls_expiry);
+ expiryLabel.setText("Expired:");
+ expiry.setText(DataHelper.formatDuration(exp) + " ago");
+ }
+
+ LinearLayout leases = (LinearLayout) getView().findViewById(R.id.ls_leases);
+ for (int i = 0; i < ls.getLeaseCount(); i++) {
+ Lease lease = ls.getLease(i);
+ addLease(leases, lease, i);
+ }
+ }
+
+ private void addLease(LinearLayout leases, Lease lease, int i) {
+ TableLayout table = new TableLayout(getActivity());
+
+ addTableRow(table, "Lease", ""+(i+1));
+
+ TableRow gateway = new TableRow(getActivity());
+ gateway.setPadding(10, 0, 0, 0);
+
+ TextView gatewayLabel = new TextView(getActivity());
+ gatewayLabel.setText("Gateway");
+
+ Button gatewayButton = new Button(getActivity());
+ gatewayButton.setText(lease.getGateway().toBase64().substring(0, 4));
+ final Hash gatewayHash = lease.getGateway();
+ gatewayButton.setOnClickListener(new OnClickListener() {
+ public void onClick(View view) {
+ mEntrySelectedCallback.onEntrySelected(
+ true, gatewayHash);
+ }
+ });
+
+ gateway.addView(gatewayLabel);
+ gateway.addView(gatewayButton);
+
+ table.addView(gateway);
+
+ addTableRow(table, "Tunnel", ""+lease.getTunnelId().getTunnelId());
+
+ leases.addView(table);
+ }
+
+ private void addTableRow(TableLayout table, String key, String val) {
+ TableRow row;
+ TextView tl1, tl2;
+
+ row = new TableRow(getActivity());
+ row.setPadding(10, 0, 0, 0);
+
+ tl1 = new TextView(getActivity());
+ tl2 = new TextView(getActivity());
+
+ tl1.setText(key);
+ tl2.setText(val);
+
+ row.addView(tl1);
+ row.addView(tl2);
+
+ table.addView(row);
+ }
}
diff --git a/src/net/i2p/android/router/fragment/NetDbListFragment.java b/src/net/i2p/android/router/fragment/NetDbListFragment.java
index 1328aabe4..4d336ce70 100644
--- a/src/net/i2p/android/router/fragment/NetDbListFragment.java
+++ b/src/net/i2p/android/router/fragment/NetDbListFragment.java
@@ -6,6 +6,7 @@ import net.i2p.android.router.R;
import net.i2p.android.router.adapter.NetDbEntryAdapter;
import net.i2p.android.router.loader.NetDbEntry;
import net.i2p.android.router.loader.NetDbEntryLoader;
+import net.i2p.data.Hash;
import net.i2p.router.RouterContext;
import android.app.Activity;
@@ -48,7 +49,7 @@ public class NetDbListFragment extends ListFragment
// Container Activity must implement this interface
public interface OnEntrySelectedListener {
- public void onEntrySelected(NetDbEntry entry);
+ public void onEntrySelected(boolean isRouterInfo, Hash entryHash);
}
@Override
@@ -124,7 +125,9 @@ public class NetDbListFragment extends ListFragment
@Override
public void onListItemClick(ListView parent, View view, int pos, long id) {
super.onListItemClick(parent, view, pos, id);
- mEntrySelectedCallback.onEntrySelected(mAdapter.getItem(pos));
+ NetDbEntry entry = mAdapter.getItem(pos);
+ mEntrySelectedCallback.onEntrySelected(
+ entry.isRouterInfo(), entry.getHash());
}
@Override
diff --git a/src/net/i2p/android/router/loader/NetDbEntry.java b/src/net/i2p/android/router/loader/NetDbEntry.java
index 0328f7759..d37131d83 100644
--- a/src/net/i2p/android/router/loader/NetDbEntry.java
+++ b/src/net/i2p/android/router/loader/NetDbEntry.java
@@ -15,21 +15,31 @@ public class NetDbEntry {
private final boolean mIsRI;
private final DatabaseEntry mEntry;
+ private final boolean mIsUs;
private final String mCountry;
private final String mNick;
+ private final boolean mLocal;
+ private final boolean mUnpublished;
public static NetDbEntry fromRouterInfo(RouterContext ctx, RouterInfo ri) {
+ Hash us = ctx.routerHash();
+ boolean isUs = ri.getHash().equals(us);
String country = ctx.commSystem().getCountry(ri.getIdentity().getHash());
- return new NetDbEntry(true, ri, country, "");
+ return new NetDbEntry(ri, isUs, country);
}
public static NetDbEntry fromLeaseSet(RouterContext ctx, LeaseSet ls) {
- String nick;
+ String nick = "";
+ boolean local = false;
+ boolean unpublished = false;
Destination dest = ls.getDestination();
+ Hash key = dest.calculateHash();
if (ctx.clientManager().isLocal(dest)) {
- TunnelPoolSettings in = ctx.tunnelManager().getInboundSettings(
- dest.calculateHash());
+ local = true;
+ if (! ctx.clientManager().shouldPublishLeaseSet(key))
+ unpublished = true;
+ TunnelPoolSettings in = ctx.tunnelManager().getInboundSettings(key);
if (in != null && in.getDestinationNickname() != null)
nick = in.getDestinationNickname();
else
@@ -41,18 +51,32 @@ public class NetDbEntry {
else
nick = dest.toBase64().substring(0, 6);
}
- return new NetDbEntry(false, ls, "", nick);
+ return new NetDbEntry(ls, nick, local, unpublished);
}
- public NetDbEntry(boolean isRI, DatabaseEntry entry,
- String country,
- String nick) {
- mIsRI = isRI;
- mEntry = entry;
+ public NetDbEntry(RouterInfo ri,
+ boolean isUs, String country) {
+ mIsRI = true;
+ mEntry = ri;
+ mIsUs = isUs;
mCountry = country;
+ mNick = "";
+ mLocal = mUnpublished = false;
+ }
+
+ public NetDbEntry(LeaseSet ls,
+ String nick, boolean local, boolean unpublished) {
+ mIsRI = false;
+ mEntry = ls;
+
mNick = nick;
+ mLocal = local;
+ mUnpublished = unpublished;
+
+ mIsUs = false;
+ mCountry = "";
}
public boolean isRouterInfo() {
@@ -67,6 +91,10 @@ public class NetDbEntry {
// RouterInfo-specific methods
+ public boolean isUs() {
+ return mIsUs;
+ }
+
public int getCountryIcon() {
// http://daniel-codes.blogspot.com/2009/12/dynamically-retrieving-resources-in.html
try {
@@ -84,4 +112,12 @@ public class NetDbEntry {
public String getNickname() {
return mNick;
}
+
+ public boolean isLocal() {
+ return mLocal;
+ }
+
+ public boolean isUnpublished() {
+ return mUnpublished;
+ }
}