From 0e8d900ed4f6197eaeeb473859966fd9ed43d57d Mon Sep 17 00:00:00 2001 From: str4d <str4d@mail.i2p> Date: Mon, 10 Nov 2014 01:56:35 +0000 Subject: [PATCH] I2PTunnel secondary action to open linkable tunnels --- .../i2ptunnel/TunnelDetailFragment.java | 4 +- .../i2p/android/i2ptunnel/TunnelEntry.java | 82 +++++++++++++----- .../android/i2ptunnel/TunnelEntryAdapter.java | 32 +++++-- .../ic_open_in_browser_white_24dp.png | Bin 0 -> 276 bytes .../ic_open_in_browser_white_24dp.png | Bin 0 -> 234 bytes .../ic_open_in_browser_white_24dp.png | Bin 0 -> 348 bytes .../ic_open_in_browser_white_24dp.png | Bin 0 -> 480 bytes .../main/res/layout/listitem_i2ptunnel.xml | 22 ++++- 8 files changed, 106 insertions(+), 34 deletions(-) create mode 100644 app/src/main/res/drawable-hdpi/ic_open_in_browser_white_24dp.png create mode 100644 app/src/main/res/drawable-mdpi/ic_open_in_browser_white_24dp.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_open_in_browser_white_24dp.png create mode 100644 app/src/main/res/drawable-xxhdpi/ic_open_in_browser_white_24dp.png diff --git a/app/src/main/java/net/i2p/android/i2ptunnel/TunnelDetailFragment.java b/app/src/main/java/net/i2p/android/i2ptunnel/TunnelDetailFragment.java index 6d51f3054..f23b3a00e 100644 --- a/app/src/main/java/net/i2p/android/i2ptunnel/TunnelDetailFragment.java +++ b/app/src/main/java/net/i2p/android/i2ptunnel/TunnelDetailFragment.java @@ -97,10 +97,10 @@ public class TunnelDetailFragment extends Fragment { description.setText(mTunnel.getDescription()); TextView targetIfacePort = (TextView) v.findViewById(R.id.tunnel_target_interface_port); - targetIfacePort.setText(mTunnel.getIfacePort()); + targetIfacePort.setText(mTunnel.getTunnelLink(false)); TextView accessIfacePort = (TextView) v.findViewById(R.id.tunnel_access_interface_port); - accessIfacePort.setText(mTunnel.getIfacePort()); + accessIfacePort.setText(mTunnel.getTunnelLink(false)); CheckBox autoStart = (CheckBox) v.findViewById(R.id.tunnel_autostart); autoStart.setChecked(mTunnel.startAutomatically()); diff --git a/app/src/main/java/net/i2p/android/i2ptunnel/TunnelEntry.java b/app/src/main/java/net/i2p/android/i2ptunnel/TunnelEntry.java index d2e1d982d..4c8a4550b 100644 --- a/app/src/main/java/net/i2p/android/i2ptunnel/TunnelEntry.java +++ b/app/src/main/java/net/i2p/android/i2ptunnel/TunnelEntry.java @@ -90,6 +90,16 @@ public class TunnelEntry { else return NOT_RUNNING; } + public boolean isRunning() { + switch (getStatus()) { + case STANDBY: + case RUNNING: + return true; + default: + return false; + } + } + public boolean isClient() { return TunnelUtil.isClient(mController.getType()); } @@ -100,18 +110,42 @@ public class TunnelEntry { return Boolean.parseBoolean(mController.getSharedClient()); } + /** + * Call this to see if it is okay to linkify getClientLink() + * @return true if getClientLink() can be linkified, false otherwise. + */ + public boolean isClientLinkValid() { + return ("ircclient".equals(mController.getType())) && + mController.getListenOnInterface() != null && + mController.getListenPort() != null; + } + + /** + * @return valid host:port only if isClientLinkValid() is true + */ + public String getClientLink(boolean linkify) { + String host = getClientInterface(); + String port = getClientPort(); + String link = host + ":" + port; + if (linkify) { + if ("ircclient".equals(mController.getType())) + link = "irc://" + link; + } + return link; + } + public String getClientInterface() { + String rv; if ("streamrclient".equals(mController.getType())) - return mController.getTargetHost(); + rv = mController.getTargetHost(); else - return mController.getListenOnInterface(); + rv = mController.getListenOnInterface(); + return rv != null ? rv : ""; } public String getClientPort() { String rv = mController.getListenPort(); - if (rv != null) - return rv; - return ""; + return rv != null ? rv : ""; } public String getClientDestination() { @@ -128,10 +162,10 @@ public class TunnelEntry { /* Server tunnel data */ /** - * Call this to see if it is okay to linkify getServerTarget() - * @return true if getServerTarget() can be linkified, false otherwise. + * Call this to see if it is okay to linkify getServerLink() + * @return true if getServerLink() can be linkified, false otherwise. */ - public boolean isServerTargetLinkValid() { + public boolean isServerLinkValid() { return ("httpserver".equals(mController.getType()) || "httpbidirserver".equals(mController.getType())) && mController.getTargetHost() != null && @@ -139,9 +173,9 @@ public class TunnelEntry { } /** - * @return valid host:port only if isServerTargetLinkValid() is true + * @return valid host:port only if isServerLinkValid() is true */ - public String getServerTarget() { + public String getServerLink(boolean linkify) { String host; if ("streamrserver".equals(getInternalType())) host = mController.getListenOnInterface(); @@ -152,7 +186,13 @@ public class TunnelEntry { if (port == null) port = ""; if (host.indexOf(':') >= 0) host = '[' + host + ']'; - return host + ":" + port; + String link = host + ":" + port; + if (linkify) { + if ("httpserver".equals(mController.getType()) || + "httpbidirserver".equals(mController.getType())) + link = "http://" + link; + } + return link; } public String getDestinationBase64() { @@ -183,18 +223,14 @@ public class TunnelEntry { /* Other output formats */ - public String getIfacePort() { - if (isClient()) { - String host; - if ("streamrclient".equals(getInternalType())) - host = mController.getTargetHost(); - else - host = mController.getListenOnInterface(); - String port = mController.getListenPort(); - if (host == null) host = ""; - if (port == null) port = ""; - return host + ":" + port; - } else return getServerTarget(); + public boolean isTunnelLinkValid() { + if (isClient()) return isClientLinkValid(); + else return isServerLinkValid(); + } + + public String getTunnelLink(boolean linkify) { + if (isClient()) return getClientLink(linkify); + else return getServerLink(linkify); } public String getDetails() { diff --git a/app/src/main/java/net/i2p/android/i2ptunnel/TunnelEntryAdapter.java b/app/src/main/java/net/i2p/android/i2ptunnel/TunnelEntryAdapter.java index b1139969d..223d4c448 100644 --- a/app/src/main/java/net/i2p/android/i2ptunnel/TunnelEntryAdapter.java +++ b/app/src/main/java/net/i2p/android/i2ptunnel/TunnelEntryAdapter.java @@ -1,9 +1,9 @@ package net.i2p.android.i2ptunnel; -import java.util.List; - -import net.i2p.android.router.R; import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.os.Build; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -11,6 +11,10 @@ import android.widget.ArrayAdapter; import android.widget.ImageView; import android.widget.TextView; +import net.i2p.android.router.R; + +import java.util.List; + public class TunnelEntryAdapter extends ArrayAdapter<TunnelEntry> { private final LayoutInflater mInflater; @@ -31,11 +35,14 @@ public class TunnelEntryAdapter extends ArrayAdapter<TunnelEntry> { @Override public View getView(int position, View convertView, ViewGroup parent) { View v = mInflater.inflate(R.layout.listitem_i2ptunnel, parent, false); - TunnelEntry tunnel = getItem(position); + final TunnelEntry tunnel = getItem(position); ImageView status = (ImageView) v.findViewById(R.id.tunnel_status); status.setImageDrawable(tunnel.getStatusIcon()); - status.setBackground(tunnel.getStatusBackground()); + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) + status.setBackgroundDrawable(tunnel.getStatusBackground()); + else + status.setBackground(tunnel.getStatusBackground()); TextView name = (TextView) v.findViewById(R.id.tunnel_name); name.setText(tunnel.getName()); @@ -44,7 +51,20 @@ public class TunnelEntryAdapter extends ArrayAdapter<TunnelEntry> { type.setText(tunnel.getDescription()); TextView ifacePort = (TextView) v.findViewById(R.id.tunnel_interface_port); - ifacePort.setText(tunnel.getIfacePort()); + ifacePort.setText(tunnel.getTunnelLink(false)); + + if (tunnel.isRunning() && tunnel.isTunnelLinkValid()) { + View open = v.findViewById(R.id.tunnel_open); + open.setVisibility(View.VISIBLE); + open.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent i = new Intent(Intent.ACTION_VIEW); + i.setData(Uri.parse(tunnel.getTunnelLink(true))); + getContext().startActivity(i); + } + }); + } return v; } diff --git a/app/src/main/res/drawable-hdpi/ic_open_in_browser_white_24dp.png b/app/src/main/res/drawable-hdpi/ic_open_in_browser_white_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..b5b0f1b632059eb0f914a8c8007dbd01f8d3f19c GIT binary patch literal 276 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k0wldT1B8K;Lb6AYF9SoB8UsT^3j@P1pisjL z28L1t28LG&3=CE?7#PG0=Ijcz0ZK3>dAqwX{BQ3+vmeOgEbxddW?<k3n!+v2$S`Y; z1W>TY)5S5w<M`XFXE_@Tcvv62Q?%+x2-nK{z$S9nb<efucfZIl)$r9<z3~1*i%Xzw zaY*wkhgsUX!H=J~y=`KXJJZ{|w}r?1kOzmWz&>WhoezF6v-q0{d!0Eh=WuN~OVjQv zI|cs4PG(lT({R;px8r(;&C9O{d_S>b>S24nw{K!zXY5+L*dS$RLC)^~w=b|h{#5Lg T*mCJT&|M6ku6{1-oD!M<vQcA8 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-mdpi/ic_open_in_browser_white_24dp.png b/app/src/main/res/drawable-mdpi/ic_open_in_browser_white_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..1585ff18dff3327d71c82398df20015032cf1e68 GIT binary patch literal 234 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM0wlfaz7_*1g=CK)Uj~LMH3o);76yi2K%s^g z3=E|P3=FRl7#OT(FffQ0%-I!a1C(G&@^*J&_}|`tW<QX}S>O=~G=W<fgc%uT%>kL6 z<muuVVsSe8$9V^-6p1}jO#k=)>F3|`OTJ+h<NhLniq2Jy5)M1rYUVB7*T$xx;^@pg z<G#b1Hntt+(j6BsGzb~-9{I(nUN4Yc(K?M~LMBH=<0?f4&AmyNKRnw1e!=-gF3t>> XV((sL@(NG{+Q#7N>gTe~DWM4fIZ#Q| literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_open_in_browser_white_24dp.png b/app/src/main/res/drawable-xhdpi/ic_open_in_browser_white_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..2da8b3feeb6ed5b38df3d61afeae4ca6b131355a GIT binary patch literal 348 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA0wn)(8}a}tg=CK)Uj~LMH3o);76yi2K%s^g z3=E|}g|8AA7_4S6Fo+k-*%fF5lweBoc6VX;-`;;_Kaj^+;1OBOz`!jG!i)^F=12eq zuXwsRhD02Gd)<+%$w8#yVf{7H*u%;@%H%JmX3c#2%IuL<RC&t_p}-rr#8}Th=y@W| z+hYE}spbFVzz>;OZLw~QtjE|@-khAlneFelW@k%di}B|Z(fcOfYT*{qslGAw(z+c7 zocCCMTlJ=k`^(oOy-XJy1lzJ%|1mt7pRAye&i$szMdib}%T6wg_iJW!Fx;u>5MVyL zXTAW_zdii|j1Oxjchvc^UKb5WC~-Kt<g0QV`?-3#JziqA46Liy9nKej;C5<jZjJo} nLs2GCceAp%`h_9^3=dc*E||y|AE9mr^dEz#tDnm{r-UW|7#n}E literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxhdpi/ic_open_in_browser_white_24dp.png b/app/src/main/res/drawable-xxhdpi/ic_open_in_browser_white_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..f3fedfa5c3ce8c56fb79d08eb0db8b7b9df2ca15 GIT binary patch literal 480 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY0wn)GsXhaw6p}rHd>I(3)EF2VS{N990fib~ zFff!FFfhDIU|_JC!N4G1FlSew4N!t9$=lt9;eUJonf*W>XMsm#F#`j)FbFd;%$g&? zz`z*c>EalYaqsPov%ZHN1Xv%Ww-m6LE@9qrk!2B!R0Fe9z`@t7fjll8B0j1MCKO2K zaXcxt;eK7{kpFGhx4Kzh&z}ivJKLqpp)$dNiBly&Frb(F&LdW{0}+qp!e^AMnX@M? zt617<Ue2tj-J3$n(kwV`%w=njsND9(q=os-<1^oR=C;@#?3@}D{jF=S!UgFv+XW|- zHeG5DTu{${>s&22S4-w;7NHmHjvH=R-;jzw96t5ZnKLiu?EUsn)#1;av%U-;Z`btk zCatb`K0`t6H)kJfQhN7cLx-5#rG`>R?zv5vsIaRl*sbwJ-gHUEq%ijLcYc5Wni`tM z`s4LaEqfLr4~0e+t%6@0o$gi#P5gcSmDQJ$)EAaIvc3Ez!fd;~m97)cu6ixwUwc`c zf7|6a+o=mx`+`pD$n;wr+pX_x5Rp6GZ1YhC$*3E1=PuuLIn?l#H6$1=#52`0)O|bF U;9Fbd3=DV%Pgg&ebxsLQ0EnQzrT_o{ literal 0 HcmV?d00001 diff --git a/app/src/main/res/layout/listitem_i2ptunnel.xml b/app/src/main/res/layout/listitem_i2ptunnel.xml index afb819226..8833f51c2 100644 --- a/app/src/main/res/layout/listitem_i2ptunnel.xml +++ b/app/src/main/res/layout/listitem_i2ptunnel.xml @@ -30,18 +30,32 @@ android:text="Tunnel name" android:textAppearance="@style/TextAppearance.AppCompat.Primary" /> + <!-- Open link --> + <ImageView + android:id="@+id/tunnel_open" + android:layout_width="@dimen/listitem_icon_size" + android:layout_height="@dimen/listitem_icon_size" + android:layout_alignParentEnd="true" + android:layout_alignParentRight="true" + android:layout_centerVertical="true" + android:layout_marginLeft="@dimen/listitem_horizontal_margin" + android:layout_marginStart="@dimen/listitem_horizontal_margin" + android:contentDescription="Open" + android:src="@drawable/ic_open_in_browser_white_24dp" + android:visibility="gone" /> + <!-- Interface:port the tunnel listens on or points to --> <TextView android:id="@+id/tunnel_interface_port" - android:layout_width="wrap_content" + android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_alignParentEnd="true" - android:layout_alignParentRight="true" android:layout_alignTop="@id/tunnel_name" android:layout_marginLeft="4dp" android:layout_marginStart="4dp" android:layout_toEndOf="@id/tunnel_name" + android:layout_toLeftOf="@id/tunnel_open" android:layout_toRightOf="@id/tunnel_name" + android:layout_toStartOf="@id/tunnel_open" android:ellipsize="start" android:gravity="right" android:maxLines="1" @@ -57,6 +71,8 @@ android:layout_alignParentBottom="true" android:layout_alignStart="@+id/tunnel_name" android:layout_marginBottom="@dimen/listitem_text_bottom_margin_two_lines" + android:layout_toLeftOf="@id/tunnel_open" + android:layout_toStartOf="@id/tunnel_open" android:ellipsize="end" android:maxLines="1" android:text="Tunnel description" -- GitLab