diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 8bb553b0396924d27cd165278de05a2dedf0b0d4..80353f24d57fbd67d79880ae1ad8f40563016162 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -20,6 +20,7 @@ <activity android:name=".activity.MainActivity" android:label="@string/app_name" android:icon="@drawable/ic_launcher_itoopie" + android.theme="@android:style/Theme.NoTitleBar" android:launchMode="singleTask" > <intent-filter> <action android:name="android.intent.action.MAIN" /> @@ -30,5 +31,9 @@ android:label="@string/app_name" android.theme="@android:style/Theme.NoTitleBar" > </activity> + <activity android:name=".activity.TextResourceActivity" + android:label="@string/app_name" + android.theme="@android:style/Theme.NoTitleBar" > + </activity> </application> </manifest> diff --git a/build.xml b/build.xml index b40e02996b60e04bee39e308240a58dfd9c187c4..21d83490e21390ca3f2332d784001da27cc8f808 100644 --- a/build.xml +++ b/build.xml @@ -150,6 +150,16 @@ <copy file="${i2pbase}/installer/resources/themes/console/images/i2plogo.png" todir="res/drawable/" /> <copy file="${i2pbase}/installer/resources/blocklist.txt" tofile="res/raw/blocklist_txt" /> <copy file="${i2pbase}/installer/resources/hosts.txt" tofile="res/raw/hosts_txt" /> + <copy file="${i2pbase}/licenses/LICENSE-ElGamalDSA.txt" tofile="res/raw/license_elgamaldsa_txt" /> + <copy file="${i2pbase}/licenses/LICENSE-SHA256.txt" tofile="res/raw/license_sha256_txt" /> + <copy file="${i2pbase}/licenses/LICENSE-BSD.txt" tofile="res/raw/license_bsd_txt" /> + <copy file="${i2pbase}/licenses/LICENSE-SNTP.txt" tofile="res/raw/license_sntp_txt" /> + <copy file="${i2pbase}/licenses/LICENSE-LGPLv2.1.txt" tofile="res/raw/license_lgplv2_1_txt" /> + <copy file="${i2pbase}/licenses/LICENSE-InstallCert.txt" tofile="res/raw/license_installcert_txt" /> + <copy file="${i2pbase}/licenses/LICENSE-BlockFile.txt" tofile="res/raw/license_blockfile_txt" /> + <copy file="${i2pbase}/licenses/LICENSE-GPLv2.txt" tofile="res/raw/license_gplv2_txt" /> + <copy file="${i2pbase}/licenses/LICENSE-GPLv3.txt" tofile="res/raw/license_gplv3_txt" /> + <copy file="${i2pbase}/licenses/LICENSE-LGPLv3.txt" tofile="res/raw/license_lgplv3_txt" /> </target> <target name="hackcleanup"> @@ -182,8 +192,21 @@ <delete file="res/drawable/i2plogo.png" verbose="${verbose}"/> <delete file="res/raw/blocklist_txt" verbose="${verbose}" /> <delete file="res/raw/hosts_txt" verbose="${verbose}" /> + <delete file="res/raw/license_elgamaldsa_txt" /> + <delete file="res/raw/license_sha256_txt" /> + <delete file="res/raw/license_bsd_txt" /> + <delete file="res/raw/license_sntp_txt" /> + <delete file="res/raw/license_lgplv2_1_txt" /> + <delete file="res/raw/license_installcert_txt" /> + <delete file="res/raw/license_blockfile_txt" /> + <delete file="res/raw/license_gplv2_txt" /> + <delete file="res/raw/license_gplv3_txt" /> + <delete file="res/raw/license_lgplv3_txt" /> <delete dir="jni/build/" verbose="${verbose}" /> + <echo message="Not deleting jni/libjbigi.so" /> +<!-- <delete file="jni/libjbigi.so" verbose="${verbose}" /> +--> <delete file="scripts/build.number" verbose="${verbose}" /> <delete file="scripts/version.properties" verbose="${verbose}" /> </target> diff --git a/res/layout/main.xml b/res/layout/main.xml index cf9ce895c3e4ad8a0784c4bc71ab086ed407e656..c942bdf9ea498e37c5723a424ff08d4ffc9c5f94 100644 --- a/res/layout/main.xml +++ b/res/layout/main.xml @@ -15,24 +15,48 @@ android:layout_height="wrap_content" android:src="@drawable/i2plogo" /> -<Button +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="horizontal" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + > + <Button android:id="@+id/news_button" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:text="Go to news" + android:text="News" + /> + <Button + android:id="@+id/releasenotes_button" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="Release Notes" + /> + <Button + android:id="@+id/licenses_button" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="Licenses" /> -<Button +</LinearLayout> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="horizontal" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + > + <Button android:id="@+id/router_start_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Start router" /> -<Button + <Button android:id="@+id/router_stop_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Stop router" /> +</LinearLayout> <TextView android:id="@+id/main_status_text" android:layout_width="fill_parent" diff --git a/res/layout/text_resource.xml b/res/layout/text_resource.xml new file mode 100644 index 0000000000000000000000000000000000000000..0d1503f3e959baa6b69d4d7c50f1ec0196213874 --- /dev/null +++ b/res/layout/text_resource.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="vertical" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + > +<TextView + android:id="@+id/text_resource_text" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:scrollbars="vertical" + android:text="Release Notes" + /> +</LinearLayout> + diff --git a/res/raw/i2ptunnel_config b/res/raw/i2ptunnel_config index 37a71106d253ef09b9c33b5bab57ff44feae1a10..55d0648a68911b006e8830f181be5c982e6c6ba0 100644 --- a/res/raw/i2ptunnel_config +++ b/res/raw/i2ptunnel_config @@ -15,10 +15,10 @@ tunnel.0.option.i2cp.reduceIdleTime=600000 tunnel.0.option.i2cp.reduceOnIdle=true tunnel.0.option.i2cp.reduceQuantity=1 tunnel.0.option.i2p.streaming.connectDelay=1000 -tunnel.0.option.inbound.length=2 -tunnel.0.option.inbound.lengthVariance=0 -tunnel.0.option.outbound.length=2 -tunnel.0.option.outbound.lengthVariance=0 +tunnel.0.option.inbound.length=1 +tunnel.0.option.inbound.lengthVariance=1 +tunnel.0.option.outbound.length=1 +tunnel.0.option.outbound.lengthVariance=1 tunnel.0.startOnLoad=true # irc @@ -38,8 +38,8 @@ tunnel.1.option.i2cp.reduceIdleTime=600000 tunnel.1.option.i2cp.reduceOnIdle=true tunnel.1.option.i2cp.reduceQuantity=1 tunnel.1.option.i2p.streaming.connectDelay=1000 -tunnel.1.option.inbound.length=2 -tunnel.1.option.inbound.lengthVariance=0 -tunnel.1.option.outbound.length=2 -tunnel.1.option.outbound.lengthVariance=0 +tunnel.1.option.inbound.length=1 +tunnel.1.option.inbound.lengthVariance=1 +tunnel.1.option.outbound.length=1 +tunnel.1.option.outbound.lengthVariance=1 tunnel.1.startOnLoad=true diff --git a/res/raw/licenses_txt b/res/raw/licenses_txt new file mode 100644 index 0000000000000000000000000000000000000000..e5a679788ab45128fb653db2116f277214966d2a --- /dev/null +++ b/res/raw/licenses_txt @@ -0,0 +1,121 @@ +This product includes both public domain code and licensed code as described below. +For all code, unless otherwise stated in the appropriate license, the following applies: + + + NO WARRANTY + + BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + + +LICENSES +-------- + +Core (i2p.jar): +Public domain except as listed below: + + ElGamal and DSA code: + Copyright (c) 2003, TheCrypto + See LICENSE-ElGamalDSA.txt + + SHA256 and HMAC-SHA256: + Copyright (c) 2000 - 2004 The Legion Of The Bouncy Castle + See LICENSE-SHA256.txt + + AES code: + Under the Cryptix (MIT) license, written by the Cryptix team + (That's what our website says but all our AES code looks like it is public domain) + + Crypto filters: + From the xlattice app - http://xlattice.sourceforge.net/ + See LICENSE-BSD.txt + + SNTP code: + Copyright (c) 2004, Adam Buckley + See LICENSE-SNTP.txt + + PRNG: + Copyright (C) 2001, 2002, Free Software Foundation, Inc. + See LICENSE-LGPLv2.1.txt + + HashCash code: + Copyright 2006 Gregory Rubin grrubin@gmail.com + See LICENSE-HashCash.txt + + GettextResource from gettext v0.18: + Copyright (C) 2001, 2007 Free Software Foundation, Inc. + See LICENSE-LGPLv2.1.txt + + SSLEepGet: + Contains some code Copyright 2006 Sun Microsystems, Inc. + See LICENSE-InstallCert.txt + + BlockFile: + Copyright (c) 2006, Matthew Estes + See LICENSE-BlockFile.txt + + +Router (router.jar): +Public domain except as listed below: + UPnP.java: + From freenet + See LICENSE-GPLv2.txt + + UPnP subsystem 1.7: + Copyright (C) 2003-2006 Satoshi Konno + See LICENSE-UPnP.txt + +Jbigi Libraries (jbigi.jar): + JNI code public domain. + + GMP 4.3.2 / 5.0.2: + Copyright 1991, 1996, 1999, 2000, 2007 Free Software Foundation, Inc. + See LICENSE-LGPLv3.txt + + +Applications: + + Addressbook: + Copyright (c) 2004 Ragnarok + See LICENSE-Addressbook.txt + + I2PTunnel: + (c) 2003 - 2004 mihi + GPLv2 with exception. + See LICENSE-I2PTunnel.txt + See LICENSE-GPLv2.txt + + I2PTunnel SOCKS Proxy: + Copyright (c) 2004 by human + GPLv2 with exception. + See LICENSE-I2PTunnel.txt + See LICENSE-GPLv2.txt + + I2PTunnel UDP and Streamr: + By welterde. + See LICENSE-GPLv2.txt + + Ministreaming Lib: + By mihi. + See LICENSE-BSD.txt + + Streaming Lib: + Public domain. diff --git a/res/raw/releasenotes_txt b/res/raw/releasenotes_txt new file mode 100644 index 0000000000000000000000000000000000000000..51b40ef0129d71dc0a7dc16e507ad1e4fc0e85ea --- /dev/null +++ b/res/raw/releasenotes_txt @@ -0,0 +1,15 @@ +This is ALPHA SOFTWARE. It may crash your phone. Do not rely upon it for strong anonymity. Tunnels may be as short as one hop. + +This is only tested on the Droid. You need at least 256 MB of RAM. 512 should be much better. + +The app may be moved to the SD card if you have Froyo (2.2) or higher. + +The app will work best when you are not changing IPs. If you are moving around, changing WIFI nodes, or switching from cellular to WIFI networks, it won't work well. + +There is an HTTP proxy at localhost port 4444 and a transparent IRC proxy at localhost port 6668. + +The HTTP proxy is untested (other than with the news fetcher). It should work with Firefox 4 Mobile and the ProxyMob Firefox plugin, if you have at least 512 MB of RAM. + +The IRC proxy is tested with the "Android IRC Free" app. + +Report results and bugs on the zzz.i2p Android forum. diff --git a/res/raw/router_config b/res/raw/router_config index b448224c28b6e19df2b29e7959e6d9cfb7da6803..cd1015180bf389218fa1ec9f733d0050bef4c94e 100644 --- a/res/raw/router_config +++ b/res/raw/router_config @@ -19,12 +19,12 @@ i2cp.disableInterface=true ##### Tunnels # router.inboundPool.backupQuantity=0 -router.inboundPool.length=2 -router.inboundPool.lengthVariance=0 +router.inboundPool.length=1 +router.inboundPool.lengthVariance=1 router.inboundPool.quantity=2 router.outboundPool.backupQuantity=0 -router.outboundPool.length=2 -router.outboundPool.lengthVariance=0 +router.outboundPool.length=1 +router.outboundPool.lengthVariance=1 router.outboundPool.quantity=2 router.maxParticipatingTunnels=0 router.sharePercentage=10 diff --git a/res/values/strings.xml b/res/values/strings.xml index d1ab96508e6091b8634eb9c74ce5dc8d58ab8692..de7c12c8f0f4aae8b54da8ac7ce93ee2a5c630b2 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -1,4 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <resources> <string name="app_name">I2P</string> + <string name="welcome_new_install">Welcome to I2P! This app is ALPHA software and it does not provide strong anonymity. Please read the release notes and license information.</string> + <string name="welcome_new_version">New version installed. Please read the release notes. Version:</string> </resources> diff --git a/src/net/i2p/android/router/activity/I2PWebViewClient.java b/src/net/i2p/android/router/activity/I2PWebViewClient.java new file mode 100644 index 0000000000000000000000000000000000000000..a2564e482163f6e5b2dd20a5d95f6c846e46d6a6 --- /dev/null +++ b/src/net/i2p/android/router/activity/I2PWebViewClient.java @@ -0,0 +1,43 @@ +package net.i2p.android.router.activity; + +import android.webkit.WebView; +import android.webkit.WebViewClient; + +import java.net.URI; +import java.net.URISyntaxException; + +class I2PWebViewClient extends WebViewClient { + + // TODO add some inline style + private static final String HEADER = "<html><head></head><body>"; + private static final String FOOTER = "</body></html>"; + private static final String ERROR_EEPSITE = HEADER + "Sorry, eepsites not yet supported" + FOOTER; + + @Override + public boolean shouldOverrideUrlLoading(WebView view, String url) { + System.err.println("Should override? " + url); + try { + URI uri = new URI(url); + String s = uri.getScheme(); + if (s == null) + return false; + s = s.toLowerCase(); + if (!(s.equals("http") || s.equals("https"))) + return false; + String h = uri.getHost(); + if (h == null) + return false; + h = h.toLowerCase(); + if (h.endsWith(".i2p")) { + // if (s.equals("https") + // return false; + view.loadData(ERROR_EEPSITE, "text/html", "UTF-8"); + } else { + view.loadUrl(url); + } + return true; + } catch (URISyntaxException use) { + return false; + } + } +} diff --git a/src/net/i2p/android/router/activity/MainActivity.java b/src/net/i2p/android/router/activity/MainActivity.java index 97abaa67af5583a02a2e482dbed2d80c85070337..305c7a3b223888f522636cccac5af2ca860a1dab 100644 --- a/src/net/i2p/android/router/activity/MainActivity.java +++ b/src/net/i2p/android/router/activity/MainActivity.java @@ -1,5 +1,8 @@ package net.i2p.android.router.activity; +import android.app.AlertDialog; +import android.app.Dialog; +import android.content.DialogInterface; import android.content.Intent; import android.os.Bundle; import android.os.Handler; @@ -17,7 +20,12 @@ public class MainActivity extends I2PActivityBase { private Handler _handler; private Runnable _updater; - private int _counter; + private String _savedStatus; + + protected static final String PROP_NEW_INSTALL = "i2p.newInstall"; + protected static final String PROP_NEW_VERSION = "i2p.newVersion"; + protected static final int DIALOG_NEW_INSTALL = 0; + protected static final int DIALOG_NEW_VERSION = 1; /** Called when the activity is first created. */ @Override @@ -34,6 +42,24 @@ public class MainActivity extends I2PActivityBase { } }); + Button notes = (Button) findViewById(R.id.releasenotes_button); + notes.setOnClickListener(new View.OnClickListener() { + public void onClick(View view) { + Intent intent = new Intent(view.getContext(), TextResourceActivity.class); + intent.putExtra(TextResourceActivity.TEXT_RESOURCE_ID, R.raw.releasenotes_txt); + startActivityForResult(intent, 0); + } + }); + + Button licenses = (Button) findViewById(R.id.licenses_button); + licenses.setOnClickListener(new View.OnClickListener() { + public void onClick(View view) { + Intent intent = new Intent(view.getContext(), TextResourceActivity.class); + intent.putExtra(TextResourceActivity.TEXT_RESOURCE_ID, R.raw.licenses_txt); + startActivityForResult(intent, 0); + } + }); + Button start = (Button) findViewById(R.id.router_start_button); start.setOnClickListener(new View.OnClickListener() { public void onClick(View view) { @@ -54,6 +80,13 @@ public class MainActivity extends I2PActivityBase { } }); + if (savedInstanceState != null) { + String saved = savedInstanceState.getString("status"); + if (saved != null) { + _savedStatus = saved; + } + } + _handler = new Handler(); _updater = new Updater(); } @@ -64,7 +97,11 @@ public class MainActivity extends I2PActivityBase { { super.onStart(); _handler.removeCallbacks(_updater); - _handler.postDelayed(_updater, 50); + if (_savedStatus != null) { + TextView tv = (TextView) findViewById(R.id.main_status_text); + tv.setText(_savedStatus); + } + _handler.postDelayed(_updater, 100); } @Override @@ -78,14 +115,30 @@ public class MainActivity extends I2PActivityBase { public void onResume() { super.onResume(); + checkDialog(); updateVisibility(); updateStatus(); } + @Override + public void onSaveInstanceState(Bundle outState) + { + if (_savedStatus != null) + outState.putString("status", _savedStatus); + super.onSaveInstanceState(outState); + } + private class Updater implements Runnable { + private boolean needsCheck = true; + private int counter; + public void run() { + if (getRouterContext() != null && needsCheck) { + checkDialog(); + needsCheck = false; + } updateVisibility(); - if (++_counter % 3 == 0) + if (counter++ % 3 == 0) updateStatus(); _handler.postDelayed(this, 2500); } @@ -129,22 +182,99 @@ public class MainActivity extends I2PActivityBase { fmt = new DecimalFormat("#0.00"); String status = - "Router status: " + - " Peers " + active + '/' + known + - "; Expl. Tunnels " + inEx + '/' + outEx + - "; Client Tunnels " + inCl + '/' + outCl; + "ROUTER STATUS" + + "\nPeers active/known: " + active + " / " + known + + "\nExploratory Tunnels in/out: " + inEx + " / " + outEx + + "\nClient Tunnels in/out: " + inCl + " / " + outCl; //" Pt " + part + String details = - "; Bandwidth " + fmt.format(inBW) + '/' + fmt.format(outBW) + " KBps" + - "; Job Lag " + jobLag + - "; Msg Delay " + msgDelay + - "; Up " + uptime; + "\nBandwidth in/out: " + fmt.format(inBW) + " / " + fmt.format(outBW) + " KBps" + + "\nJob Lag: " + jobLag + + "\nMsg Delay: " + msgDelay + + "\nUptime: " + uptime; - tv.setText(status + details); + _savedStatus = status + details; + tv.setText(_savedStatus); tv.setVisibility(View.VISIBLE); } else { tv.setVisibility(View.INVISIBLE); } } + + private void checkDialog() { + if (Boolean.valueOf(System.getProperty(PROP_NEW_INSTALL)).booleanValue()) { + showDialog(DIALOG_NEW_INSTALL); + } else if (Boolean.valueOf(System.getProperty(PROP_NEW_VERSION)).booleanValue()) { + showDialog(DIALOG_NEW_VERSION); + } + } + + protected Dialog onCreateDialog(int id) { + Dialog rv = null; + AlertDialog.Builder b = new AlertDialog.Builder(this); + switch (id) { + case DIALOG_NEW_INSTALL: + b.setMessage(getResources().getText(R.string.welcome_new_install)) + .setCancelable(false) + .setPositiveButton("OK", new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + System.setProperty(PROP_NEW_INSTALL, "false"); + System.setProperty(PROP_NEW_VERSION, "false"); + dialog.cancel(); + MainActivity.this.removeDialog(id); + } + }) + .setNeutralButton("Release Notes", new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + System.setProperty(PROP_NEW_INSTALL, "false"); + System.setProperty(PROP_NEW_VERSION, "false"); + dialog.cancel(); + MainActivity.this.removeDialog(id); + Intent intent = new Intent(MainActivity.this, TextResourceActivity.class); + intent.putExtra(TextResourceActivity.TEXT_RESOURCE_ID, R.raw.releasenotes_txt); + startActivityForResult(intent, 0); + } + }) + .setNegativeButton("Licenses", new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + System.setProperty(PROP_NEW_INSTALL, "false"); + System.setProperty(PROP_NEW_VERSION, "false"); + dialog.cancel(); + MainActivity.this.removeDialog(id); + Intent intent = new Intent(MainActivity.this, TextResourceActivity.class); + intent.putExtra(TextResourceActivity.TEXT_RESOURCE_ID, R.raw.licenses_txt); + startActivityForResult(intent, 0); + } + }); + rv = b.create(); + break; + + case DIALOG_NEW_VERSION: + b.setMessage(getResources().getText(R.string.welcome_new_version) + " " + System.getProperty("i2p.version")) + .setCancelable(true) + .setPositiveButton("OK", new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + System.setProperty(PROP_NEW_VERSION, "false"); + dialog.cancel(); + MainActivity.this.removeDialog(id); + } + }) + .setNegativeButton("Release Notes", new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + System.setProperty(PROP_NEW_VERSION, "false"); + dialog.cancel(); + MainActivity.this.removeDialog(id); + Intent intent = new Intent(MainActivity.this, TextResourceActivity.class); + intent.putExtra(TextResourceActivity.TEXT_RESOURCE_ID, R.raw.releasenotes_txt); + startActivityForResult(intent, 0); + } + }); + + + rv = b.create(); + break; + } + return rv; + } } diff --git a/src/net/i2p/android/router/activity/NewsActivity.java b/src/net/i2p/android/router/activity/NewsActivity.java index bfee330c8414c9d5d177fbe4acace4e7f74b78ac..906ab83098473830e9010521e3d4b691e09e14b6 100644 --- a/src/net/i2p/android/router/activity/NewsActivity.java +++ b/src/net/i2p/android/router/activity/NewsActivity.java @@ -26,7 +26,6 @@ public class NewsActivity extends I2PActivityBase { // TODO add some inline style private static final String HEADER = "<html><head></head><body>"; private static final String FOOTER = "</body></html>"; - private static final String ERROR_EEPSITE = HEADER + "Sorry, eepsites not yet supported" + FOOTER; @Override public void onCreate(Bundle savedInstanceState) @@ -34,7 +33,7 @@ public class NewsActivity extends I2PActivityBase { super.onCreate(savedInstanceState); setContentView(R.layout.news); WebView wv = (WebView) findViewById(R.id.news_webview); - wv.setWebViewClient(new NewsWebViewClient()); + wv.setWebViewClient(new I2PWebViewClient()); } @Override @@ -97,34 +96,4 @@ public class NewsActivity extends I2PActivityBase { } return super.onKeyDown(keyCode, event); } - - private static class NewsWebViewClient extends WebViewClient { - @Override - public boolean shouldOverrideUrlLoading(WebView view, String url) { - System.err.println("Should override? " + url); - try { - URI uri = new URI(url); - String s = uri.getScheme(); - if (s == null) - return false; - s = s.toLowerCase(); - if (!(s.equals("http") || s.equals("https"))) - return false; - String h = uri.getHost(); - if (h == null) - return false; - h = h.toLowerCase(); - if (h.endsWith(".i2p")) { - // if (s.equals("https") - // return false; - view.loadData(ERROR_EEPSITE, "text/html", "UTF-8"); - } else { - view.loadUrl(url); - } - return true; - } catch (URISyntaxException use) { - return false; - } - } - } } diff --git a/src/net/i2p/android/router/activity/TextResourceActivity.java b/src/net/i2p/android/router/activity/TextResourceActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..a343d2703e3f19a7e19090a1df9d6fc5c40a9c9c --- /dev/null +++ b/src/net/i2p/android/router/activity/TextResourceActivity.java @@ -0,0 +1,64 @@ +package net.i2p.android.router.activity; + +import android.content.res.Resources; +import android.content.Intent; +import android.os.Bundle; +import android.text.method.ScrollingMovementMethod; +import android.widget.TextView; + +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.io.IOException; +import java.io.UnsupportedEncodingException; + +import net.i2p.android.router.R; + +/** + * Display a raw text resource. + * The resource ID must be passed as an extra in the intent. + */ +public class TextResourceActivity extends I2PActivityBase { + + final static String TEXT_RESOURCE_ID = "text_resource_id"; + + @Override + public void onCreate(Bundle savedInstanceState) + { + super.onCreate(savedInstanceState); + setContentView(R.layout.text_resource); + TextView tv = (TextView) findViewById(R.id.text_resource_text); + tv.setMovementMethod(ScrollingMovementMethod.getInstance()); + Intent intent = getIntent(); + int id = intent.getIntExtra(TEXT_RESOURCE_ID, R.raw.releasenotes_txt); + if (id == R.raw.releasenotes_txt) + tv.setText("Release Notes for Release " + System.getProperty("i2p.version") + "\n\n" + + getResourceAsString(id)); + else + tv.setText(getResourceAsString(id)); + } + + private String getResourceAsString(int id) { + InputStream in = null; + ByteArrayOutputStream out = new ByteArrayOutputStream(2048); + byte buf[] = new byte[1024]; + try { + in = getResources().openRawResource(id); + + int read = 0; + while ( (read = in.read(buf)) != -1) + out.write(buf, 0, read); + + } catch (IOException ioe) { + System.err.println("resource error " + ioe); + } catch (Resources.NotFoundException nfe) { + System.err.println("resource error " + nfe); + } finally { + if (in != null) try { in.close(); } catch (IOException ioe) {} + } + try { + return out.toString("UTF-8"); + } catch (UnsupportedEncodingException uee) { + } + return ""; + } +} diff --git a/src/net/i2p/android/router/service/Init.java b/src/net/i2p/android/router/service/Init.java index 4c95a49527bb54db454fe1c08efe4a0a1319b4f3..c99341add470c4db7e20d426c50e5ace1962c8f2 100644 --- a/src/net/i2p/android/router/service/Init.java +++ b/src/net/i2p/android/router/service/Init.java @@ -26,11 +26,19 @@ class Init { private final Context ctx; private final String myDir; + private final String _ourVersion; private String _apkPath; + private static final String CONFIG_FILE = "android.config"; + private static final String PROP_NEW_INSTALL = "i2p.newInstall"; + private static final String PROP_NEW_VERSION = "i2p.newVersion"; + private static final String PROP_INSTALLED_VERSION = "i2p.version"; + public Init(Context c) { ctx = c; myDir = c.getFilesDir().getAbsolutePath(); + _ourVersion = getOurVersion(); + System.setProperty(PROP_INSTALLED_VERSION, _ourVersion); } void debugStuff() { @@ -46,7 +54,7 @@ class Init { System.err.println("getFilesDir()" + ": " + myDir); System.err.println("max mem" + ": " + DataHelper.formatSize(Runtime.getRuntime().maxMemory())); System.err.println("Package" + ": " + ctx.getPackageName()); - System.err.println("Version" + ": " + getOurVersion()); + System.err.println("Version" + ": " + _ourVersion); System.err.println("MODEL" + ": " + Build.MODEL); System.err.println("DISPLAY" + ": " + Build.DISPLAY); System.err.println("VERSION" + ": " + Build.VERSION.RELEASE); @@ -73,15 +81,17 @@ class Init { } void initialize() { - Properties props = new Properties(); - props.setProperty("i2p.dir.temp", myDir + "/tmp"); - props.setProperty("i2p.dir.pid", myDir + "/tmp"); - mergeResourceToFile(R.raw.router_config, "router.config", props); - mergeResourceToFile(R.raw.logger_config, "logger.config", null); - mergeResourceToFile(R.raw.i2ptunnel_config, "i2ptunnel.config", null); - // FIXME this is a memory hog to merge this way - mergeResourceToFile(R.raw.hosts_txt, "hosts.txt", null); - copyResourceToFile(R.raw.blocklist_txt, "blocklist.txt"); + if (checkNewVersion()) { + Properties props = new Properties(); + props.setProperty("i2p.dir.temp", myDir + "/tmp"); + props.setProperty("i2p.dir.pid", myDir + "/tmp"); + mergeResourceToFile(R.raw.router_config, "router.config", props); + mergeResourceToFile(R.raw.logger_config, "logger.config", null); + mergeResourceToFile(R.raw.i2ptunnel_config, "i2ptunnel.config", null); + // FIXME this is a memory hog to merge this way + mergeResourceToFile(R.raw.hosts_txt, "hosts.txt", null); + copyResourceToFile(R.raw.blocklist_txt, "blocklist.txt"); + } (new File(myDir, "wrapper.log")).delete(); @@ -155,4 +165,39 @@ class Init { } } + /** + * Check for new version. + * Sets system properties i2p.newVersion and i2p.newInstall + * @return true if new version + */ + private boolean checkNewVersion() { + Properties props = new Properties(); + + InputStream fin = null; + try { + fin = ctx.openFileInput(CONFIG_FILE); + DataHelper.loadProps(props, fin); + } catch (IOException ioe) { + System.err.println("Looks like a new install"); + } finally { + if (fin != null) try { fin.close(); } catch (IOException ioe) {} + } + + String oldVersion = props.getProperty(PROP_INSTALLED_VERSION); + boolean newInstall = oldVersion == null; + boolean newVersion = !_ourVersion.equals(oldVersion); + System.setProperty(PROP_NEW_INSTALL, Boolean.toString(newInstall)); + System.setProperty(PROP_NEW_VERSION, Boolean.toString(newVersion)); + + if (newVersion) { + System.err.println("New version " + _ourVersion); + props.setProperty(PROP_INSTALLED_VERSION, _ourVersion); + try { + DataHelper.storeProps(props, ctx.getFileStreamPath(CONFIG_FILE)); + } catch (IOException ioe) { + System.err.println("Failed to write " + CONFIG_FILE); + } + } + return newVersion; + } }