Compare commits

...

1275 Commits

Author SHA1 Message Date
6b585822f1 0.9.20
i2p.i2p revision: 747e9d409223a108623b0b38d084097335d6c195
2015-06-18 05:26:44 +00:00
c81c57daa0 Updated translations 2015-06-16 11:39:36 +00:00
f28be9cb02 Updated CHANGELOG 2015-06-16 11:35:28 +00:00
6582f67ed5 Fix tunnel backup quantity fetching in advanced tunnel prefs 2015-06-16 11:35:10 +00:00
d138c482d9 Change to bar plot, update range step when plot updates 2015-06-16 09:12:28 +00:00
fc2d962cad Hide stats in final shutdown 2015-06-16 07:32:48 +00:00
c541ae0347 Remove HTML entities from clock skew error, code style 2015-06-15 11:32:19 +00:00
d6e79ed0a7 Improved graph axes 2015-06-15 11:30:54 +00:00
7ec20fe60c Updated TODO 2015-06-15 11:30:13 +00:00
f3464c5095 SU3 news 2015-06-06 10:36:12 +00:00
32512fecbc Code style 2015-06-06 07:36:16 +00:00
1d7fcd47ef Filter proxy error page resources to remove routerconsole links 2015-06-06 03:56:44 +00:00
f156c591ad Disable countries table in netDB page (because no GeoIP data) 2015-06-06 00:07:18 +00:00
fb6ca0d61e Fixed NPE (linked to previous commit) 2015-06-05 23:50:33 +00:00
a4662984a7 Added missing setContentView() 2015-06-05 23:38:49 +00:00
6cccf1fb23 Don't change lights for graceful shutdown 2015-06-05 23:13:09 +00:00
39f32acd5b Update release notes 2015-06-04 10:45:21 +00:00
3d60d10f8e Make tunnel length default 2 in tunnel prefs, to match default i2ptunnel.config 2015-06-04 10:43:23 +00:00
8cbc11dff0 Updated translations 2015-06-03 00:03:14 +00:00
858f007e21 Client library 0.7
i2p.i2p tag: i2p-0.9.20
2015-06-02 23:53:02 +00:00
02f830e472 Upgraded support libraries 2015-06-02 23:40:26 +00:00
d32ef0bb9b Unregister onLocaleChanged broadcast listener 2015-05-29 11:02:21 +00:00
6ae103373e Helper method to check if tunnels are active 2015-05-27 10:41:33 +00:00
b2a82b9809 Use state to define isStarted() 2015-05-26 03:20:40 +00:00
73b6898d76 Bugfix: hard-code IRouterState action string so it always matches the manifest 2015-05-26 03:19:11 +00:00
be9336228c New helper bind method with callback to notify caller as soon as helper is bound 2015-05-26 03:18:43 +00:00
62546a779a Updated ignores 2015-05-24 07:20:33 +00:00
b4afc3b4b2 Initial unit tests for client library 2015-05-24 07:17:53 +00:00
4415a5fc25 Updated translations 2015-05-23 22:34:41 +00:00
bddb02f6ba Handle edge cases with ViewPager disabling after shutting down router 2015-05-21 12:14:34 +00:00
f2c3f30224 Move process killing on exit into I2PActivity 2015-05-21 02:57:51 +00:00
90ff16009c Improve usage stats unit handling 2015-05-21 02:25:56 +00:00
4cd97536c5 Center text in the three console status labels 2015-05-20 12:55:30 +00:00
4f2a5fdc1f Dynamically include proxy header files
These get translated with the proxy message classes included in i2ptunnel.jar,
but the footer appended by I2PTunnelHTTPClientBase.writeErrorMessage() is not
because its strings are included in i2ptunnel.war.
2015-05-20 12:51:08 +00:00
c35d13270a Scroll padding fix 2015-05-20 12:46:43 +00:00
6c9bb31da7 Dropped unused images 2015-05-20 06:03:15 +00:00
d5f6be4428 Better side shadow for two-pane tunnel details 2015-05-20 01:56:29 +00:00
77c6e8702d Side shadow for console status 2015-05-20 01:53:29 +00:00
c4fc10f552 Bugfix 2015-05-20 01:27:46 +00:00
4b0f8eb571 Performance tweak 2015-05-20 00:20:21 +00:00
f94d2c57db Move findViewById() calls into onCreateView() for efficiency 2015-05-20 00:18:20 +00:00
fc2d6f5f09 Fix landscape view when router not running 2015-05-19 23:59:37 +00:00
c6ab6f64e9 Reorganized console status view to only show net status when no internet 2015-05-19 23:54:07 +00:00
5315771118 Updated translations 2015-05-19 23:30:22 +00:00
39b8bff6a2 Updated translations 2015-05-19 11:42:46 +00:00
c2a7c8ebde String tweaks 2015-05-19 11:38:54 +00:00
32a8c71bf1 Show net status level 2015-05-19 11:32:30 +00:00
f35257fc65 Handle all net statuses, extract console strings 2015-05-19 11:22:07 +00:00
3ab1fa7c97 Extracted more strings for translation 2015-05-18 23:13:36 +00:00
551910abce Updated translations 2015-05-18 02:13:36 +00:00
170f8afafd Console layout fixes 2015-05-17 12:31:08 +00:00
20c08b1929 New console status layout 2015-05-17 12:22:21 +00:00
e943c31ef9 Improve layout performance 2015-05-17 06:44:25 +00:00
601b979d4e Re-increase routerlogo size, center portrait, fix view bounds issue 2015-05-17 05:15:19 +00:00
973808b392 Reduced size of routerlogo, moved usage stats to bottom toolbar 2015-05-17 05:01:02 +00:00
25811b742f Do full i2p.i2p rebuild after clean 2015-05-15 09:29:16 +00:00
2d57d7cad7 Updated translations 2015-05-15 08:13:03 +00:00
687a62656b Extracted remaining hard-coded strings that won't be changed 2015-05-15 08:05:53 +00:00
5a7c33d9b9 Updated translations 2015-05-15 05:44:31 +00:00
e66c98fbfe Language name tweak 2015-05-14 06:31:56 +00:00
2897bfcb77 Updated translations after string push 2015-05-13 11:34:18 +00:00
b8aca7badc Updated translations 2015-05-13 11:14:39 +00:00
edb2506083 Renamed addressbook page headers 2015-05-13 11:05:06 +00:00
eceb7f14a4 Change "No client tunnels..." to "No tunnels..." 2015-05-13 10:47:35 +00:00
b165f41266 Separate "graphs not ready" dialog, make dialogs non-cancelable 2015-05-13 10:45:01 +00:00
9dd15e550d Added icons to main settings categories 2015-05-12 10:41:53 +00:00
e94984901d Moved graphs from advanced to general 2015-05-12 10:17:06 +00:00
55d682fdfc Updated translations 2015-05-12 05:27:46 +00:00
c231a9f851 Fixed libjbigi building for x86 and mips 2015-05-11 12:13:12 +00:00
bbde471e99 Updated target SDK and build tools to API 22 2015-05-11 11:28:08 +00:00
51c5409f12 Updated Gradle plugin version 2015-05-11 11:24:10 +00:00
1ff96d5530 Updated translations after removing strings 2015-05-11 10:13:53 +00:00
5e099d0e3b Removed some old strings 2015-05-11 10:09:59 +00:00
c27e8ff513 Updated translations 2015-05-11 10:04:34 +00:00
632ed5b4b3 Extract more hard-coded strings 2015-05-11 09:44:35 +00:00
407b5c1441 Moved start/stop/restart all tunnels to TunnelsContainer 2015-05-10 13:41:14 +00:00
fd2050bc1f Updated translations 2015-05-09 13:35:59 +00:00
c615497a9e Translate news strings 2015-05-09 13:30:40 +00:00
e48b2f1dff Translate "shared clients" properly in-house 2015-05-09 13:21:31 +00:00
44cd0a6d55 Update router.config with language 2015-05-09 11:06:57 +00:00
196b6ffbbc Fixed plurals to match Transifex language rules 2015-05-08 13:17:30 +00:00
6cf01e3db0 Updated translations 2015-05-08 13:01:33 +00:00
204f2d8adc Lint 2015-05-08 13:01:14 +00:00
93853bd6b6 Lint: Unnecessary (un)boxing 2015-05-08 11:23:13 +00:00
4095b48a82 Lint 2015-05-08 11:20:49 +00:00
3ab1a68b94 Collated constants 2015-05-08 11:03:22 +00:00
7675d78d0d Converted hard-coded log strings to translatable strings 2015-05-08 10:59:19 +00:00
1b2fa9bda6 Rate graph styling 2015-05-08 10:36:01 +00:00
8819bbfa44 Removed redundant text 2015-05-08 08:58:46 +00:00
2e6ff0ac07 Fix default graphs 2015-05-08 08:18:22 +00:00
8d9a532424 Fixed console FAM visibility 2015-05-08 04:15:50 +00:00
6f5e3e2386 Replaced hard-coded activity titles with translatable strings 2015-05-08 04:07:30 +00:00
fb63f1eee7 Material design for TextResourceDialog 2015-05-07 02:08:20 +00:00
8c65812fa0 Add Ok button to FirstStartDialog 2015-05-07 01:37:55 +00:00
adfc6415b3 Display up button on Licenses 2015-05-07 01:37:39 +00:00
bb2a1c7c62 Prevent race condition if language choice restarts Activity 2015-05-06 22:15:38 +00:00
3d63269286 Choose language on first start 2015-05-06 13:04:53 +00:00
6dde8d2a88 Added Ok button to About dialog 2015-05-06 11:45:31 +00:00
d0c6bcff7d Tunnel interfaces for bidir and Streamr server tunnels 2015-05-06 06:50:26 +00:00
b938bc9698 NPE fix 2015-05-06 02:34:35 +00:00
2cb877d61b List available interfaces in tunnel preferences 2015-05-06 02:34:06 +00:00
77368e370b Updated translations 2015-05-06 02:04:50 +00:00
2e6589ea74 Status bar fixes 2015-05-06 01:56:28 +00:00
90367b0f9c Mark notification statuses for translation 2015-05-06 01:46:58 +00:00
97a350c482 Fixed deprecation 2015-05-06 01:26:53 +00:00
57d7708ae6 Enable language to be changed from default 2015-05-05 04:17:14 +00:00
913d39a9a2 Updated language code rewrites
See https://developer.android.com/reference/java/util/Locale.html for details
2015-05-05 03:15:50 +00:00
fa83742386 New client translations for ca 2015-05-05 03:14:42 +00:00
94539b8ebb Updated translations 2015-05-05 03:14:16 +00:00
bccbe30074 AppCompat v22.1.*: more deprecations 2015-05-02 11:54:21 +00:00
4e954eef50 AppCompat v22.1.*: Material design dialogs 2015-05-02 11:27:39 +00:00
6eeafb64f5 AppCompat v22.1.*: deprecations 2015-05-02 11:14:33 +00:00
d7184e9c99 Add up nav to one-pane tunnel details 2015-05-02 11:09:04 +00:00
be8016c02c Display selected tunnel setting in ListPreference summary 2015-05-02 04:59:32 +00:00
11d4e05518 Fix tunnel preference ordering 2015-05-02 00:02:19 +00:00
fdccadda04 Prevent PERSISTENT_KEY and NEW_KEYS from being set simultaneously 2015-05-01 23:42:46 +00:00
ccb1c73cf3 Lint 2015-05-01 12:29:39 +00:00
f3168f0dc2 Updated CHANGELOG 2015-05-01 12:08:40 +00:00
b4210cfb33 propagate from branch 'i2p.android.base.fragments' (head d590551a58afc8cebc67722afc73494e4f8836c0)
to branch 'i2p.android.base' (head e20ea0056b24eb0050ae3be6d84aac6e5157503d)
2015-05-01 10:25:16 +00:00
6e0a66292d Lint 2015-05-01 09:57:13 +00:00
71856397de Lint 2015-05-01 09:01:09 +00:00
568cdeca36 Lint: Rename values-id to values-in
See java.util.Locale for details
2015-05-01 08:58:15 +00:00
4e64fb3095 Updated translations 2015-05-01 08:48:16 +00:00
f33f26987b Fix adding entries to private addressbook 2015-05-01 08:39:13 +00:00
99fa7fbec6 Fix loading B64 from file 2015-05-01 08:37:35 +00:00
315931a032 Move from Maven Central to JCenter, fix up some dependencies
- JCenter is now the Android Studio default, it imports from MC
- Updated to materialish-progress 1.5
- Fixed viewpagerindicator hash (author accidentally overwrote it on MC)
2015-04-29 12:52:31 +00:00
8c63fb0ce2 Updated Android plugin
The IDE class path issue is fixed with Android Studio 1.2
2015-04-29 12:16:41 +00:00
31b7e18aad Updated Android support libraries
According to https://code.google.com/p/android/issues/detail?id=160591#c16 the
button theme bug is fixed. I still see it with API 10 (but fixed in 19+) in the
Android Studio renderer, but apparently it does work on Gingerbread devices.
2015-04-29 12:14:42 +00:00
b51ca8b27c Fix child fragments not getting an updated two-pane status on screen rotate 2015-04-28 12:51:22 +00:00
13af3d7869 Fix default router lights in landscape 2015-04-28 12:50:32 +00:00
c91de6f7ab Don't allow users to stop the router until it has finished starting 2015-04-25 05:35:08 +00:00
d961b5f8b1 Added scrolling to tunnel details 2015-04-21 13:05:07 +00:00
7d8141f62b Downgrade Android Support libraries to 21.0.3
Waiting on this issue to be resolved:
https://code.google.com/p/android/issues/detail?id=160591
2015-04-21 12:16:38 +00:00
6ef5d793f4 Save and restore console light status 2015-04-21 07:49:24 +00:00
c5c97366b8 Create the WizardModel before super.onCreate() to prevent NPEs in Fragments 2015-04-21 05:15:40 +00:00
124692db8e Reverse the Lollipop transition when finishing TunnelDetailActivity 2015-04-21 03:58:16 +00:00
72461cb678 Lollipop shared-element transition when opening TunnelDetailActivity 2015-04-21 03:52:29 +00:00
6f84f3ce06 Enable devices on API 21+ to use nice transitions 2015-04-21 03:08:05 +00:00
cbe21d94c9 Fix reloading of toolbar to update start/stop buttons in TDF 2015-04-21 02:47:19 +00:00
9c8c462089 Fixed up navigation issues from EditTunnelActivity and SettingsActivity 2015-04-20 22:56:09 +00:00
cc7c67c494 Updated TODO 2015-04-20 12:45:59 +00:00
0e14ed20e6 Split tunnel preferences into two Fragments
This prevents the advanced PreferenceScreen from going fullscreen.
2015-04-20 12:44:07 +00:00
d620535246 Fix ISE if screen rotating while router state changes 2015-04-20 12:40:19 +00:00
350d8a1363 Handle ActionBar up nav properly in SettingsActivity 2015-04-20 05:19:17 +00:00
23e80ec72b Split preferences into individual support PreferenceFragments 2015-04-20 04:11:05 +00:00
fd052f1b38 "Fix" race between RouterContext initialization and first console status update 2015-04-19 12:17:06 +00:00
865f5d271a Updated translations 2015-04-19 11:39:33 +00:00
d1293f5949 Mark property strings as non-translatable 2015-04-19 11:36:49 +00:00
2a354288bf Updated TODO 2015-04-19 11:26:14 +00:00
f20e82a25e Scroll entire console fragment in portrait (so stats are more visible on phones) 2015-04-19 11:24:23 +00:00
4a7899ce59 Update menus, FAMs etc. on router state change 2015-04-19 07:12:04 +00:00
2adc368307 Clear console status info as soon as the router has stopped 2015-04-19 07:02:12 +00:00
2bb57d2c4d Divider and margins for addressbook two-pane view 2015-04-19 05:15:07 +00:00
e649ac448b Added link icon to tunnel details page 2015-04-19 05:02:23 +00:00
337c93bb6c Updated TODO 2015-04-19 04:47:25 +00:00
f5624cf259 Differentiate between router shutting down and not running when tabs disabled 2015-04-19 04:46:28 +00:00
6afd9b950d Remove padding from top of addressbook list (headers do the job) 2015-04-19 04:45:56 +00:00
94c46d4a43 Divider for tunnel details, fixed strings 2015-04-19 04:33:05 +00:00
dcf072905c Move tunnel open link to details page 2015-04-19 04:19:52 +00:00
c67aeddb3b Material design: master-detail tunnel view
Detail shadowing method credit:
http://sapandiwakar.in/adding-shadows-to-views-in-android-using-9-patch-image/
2015-04-19 03:52:51 +00:00
f125079aa5 Added elevation to main toolbar
Pre-21 shadow uses code from the I/O 2014 source:
https://github.com/google/iosched/blob/master/android/src/main/java/com/google/samples/apps/iosched/ui/widget/DrawShadowFrameLayout.java
2015-04-19 03:49:41 +00:00
0ddd9e5f4c Material design tablet margins 2015-04-19 02:22:39 +00:00
0074cf5a19 Use separate toolbar for tunnel details menu 2015-04-19 02:22:11 +00:00
19082db9a6 Start unifying list styles, first pass at improving tunnel details 2015-04-19 01:06:59 +00:00
109aeb7796 Disable tunnels and addressbook when router not running 2015-04-18 12:38:38 +00:00
3e06a11017 Updated TODO 2015-04-18 12:37:57 +00:00
dafd438982 Common style for pager indicators 2015-04-18 03:57:37 +00:00
063fd63fe2 Updated comment to match 2015-04-18 03:18:25 +00:00
5e27a93df9 Only show tunnels in two-pane for w720dp 2015-04-18 03:14:59 +00:00
c428195127 Attempted fix of IllegalStateException 2015-04-18 00:55:21 +00:00
1fba23a144 Use correct parent for TunnelDetailListener 2015-04-18 00:41:48 +00:00
3cc1e2b4bb Hide unusable console options when router is not running 2015-04-18 00:39:28 +00:00
77b05fa6e0 Open correct help page for correct tab 2015-04-18 00:32:55 +00:00
3553065ce2 Don't show start/stop/restart until TCG has started 2015-04-18 00:28:35 +00:00
167c06225f Added missing FAB to two-pane tunnels container 2015-04-18 00:10:00 +00:00
3420c04735 Improved title indicator for container ViewPagers 2015-04-17 23:42:50 +00:00
973282ab59 Updated TODO 2015-04-17 22:22:50 +00:00
7c04a96639 Re-enable tunnel editing 2015-04-17 22:22:36 +00:00
b2db1f4a6c Start TCG in LoadClientsJob 2015-04-17 11:24:08 +00:00
e3e0960ed8 Test settings navigation (to help pick up bugs like the IntListPreference one) 2015-04-16 11:24:08 +00:00
78ad153c47 Fixed integration tests for swapped tabs 2015-04-16 11:11:58 +00:00
fa6ba6bdce Updated CHANGELOG 2015-04-16 00:52:06 +00:00
8f302e6eeb 0.9.19.1
i2p.i2p tag: 0.9.19
2015-04-16 00:51:40 +00:00
93d2677b34 Fix for when an IntListPreference was previously stored in a ListPreference 2015-04-16 00:51:15 +00:00
1d02535158 StackOverflowException fix 2015-04-15 23:30:29 +00:00
955e40b0fc Updated client library dependencies 2015-04-13 12:06:01 +00:00
b4367843cd Gradle build script lint 2015-04-13 12:05:23 +00:00
76fd69544d Updated library versions 2015-04-13 12:03:18 +00:00
99b582a005 propagate from branch 'i2p.android.base' (head d8a24ace7d2d7616fcc2b12ac9a663f4cdbb7be8)
to branch 'i2p.android.base.fragments' (head 376be71890e893e97d2b8fed60d2a567c235ba99)
2015-04-13 08:29:00 +00:00
8e0e5ed5c4 Updated CHANGELOG 2015-04-13 02:21:38 +00:00
234bc6e5a0 0.9.19
i2p.i2p tag: i2p-0.9.19
2015-04-13 02:20:51 +00:00
b0131843ae Handle saved strings from older version 2015-04-13 01:52:24 +00:00
c32bda66b5 Client library 0.9.19
i2p.i2p tag: i2p-0.9.19
2015-04-13 01:18:21 +00:00
6d726df1dc Updated translations 2015-04-13 00:01:20 +00:00
5b5a99f512 Removed duplicate info from tunnel details page 2015-04-10 10:32:19 +00:00
a11dd1e4e6 Rebuilt libjbigi.so for armeabi with new build.sh, new build for armeabi-v7a
Both tested on my local device, router starts and builds tunnels.

armeabi:     native = 77% of pure java time
armeabi-v7a: native = 62% of pure java time
2015-04-10 04:03:36 +00:00
2190c59d73 Updated jbigi build.sh to support building all ABIs
Now uses make-standalone-toolchain.sh and flags obtained from
https://github.com/Rupan/gmp
2015-04-10 03:59:24 +00:00
c6e06e25a8 Updated translations 2015-04-09 23:50:36 +00:00
a559eb4fab Fixed location of uk translations 2015-04-09 23:49:02 +00:00
d1110aefc4 Fixes for jbigi building 2015-04-09 13:56:10 +00:00
9a5c63f620 Updated translations 2015-04-08 21:53:41 +00:00
d4e9195a6c Updated translations 2015-04-07 12:27:17 +00:00
e9d2b9f53c String fix 2015-04-07 12:26:01 +00:00
c124cafe3c Dividers and touch feedback for browser config list 2015-04-07 12:18:06 +00:00
24f0d72aae Touch feedback for tunnels and addresses in RecyclerView 2015-04-07 12:13:44 +00:00
8780d69be5 Decrease height of addressbook section headers 2015-04-07 12:11:59 +00:00
1853f5bcfd Add divider below addressbook labels in two pane mode 2015-04-07 12:10:32 +00:00
3f6caf18b4 Added missing headers to two-pane addressbook 2015-04-07 10:42:34 +00:00
97aa6e64bc Added dividers to tunnels and addressbook 2015-04-07 09:41:47 +00:00
f1bfd7d4aa Updated TODO 2015-04-06 23:31:49 +00:00
70ede5a370 Added alphanumeric section headers to addressbook 2015-04-06 23:31:14 +00:00
d1d06840fd Migrated tunnels list to RecyclerView 2015-04-06 03:25:05 +00:00
5f62418513 Moved state request to onResume() 2015-04-06 02:16:09 +00:00
5e6dab9bf1 Better handling of router state in AddressbookFragment 2015-04-06 00:49:28 +00:00
ef65a94e4c Migrated changes that merge didn't handle 2015-04-06 00:19:23 +00:00
c2e00ecf26 propagate from branch 'i2p.android.base' (head 83cce028d4603503d9530fcd828c4d9fa2a9ad7d)
to branch 'i2p.android.base.fragments' (head 049d93b11a6300da3b5b69212ba4f06d7720a080)
2015-04-06 00:11:03 +00:00
40f3d91ebb Tunnel logic bugfix 2015-04-05 13:12:14 +00:00
fae4b7e42d Bugfix in converting wizard data to TunnelConfig 2015-04-05 13:11:53 +00:00
eb700e34ba Migrated TunnelUtil.createConfigFromWizard() to use TunnelLogic 2015-04-05 12:32:56 +00:00
6828d985d2 Updated TODO 2015-04-05 05:00:06 +00:00
05a2132295 Updated translations 2015-04-05 04:58:43 +00:00
dbee390bba Updated changelog 2015-04-05 04:42:10 +00:00
0b5ae4edf8 Updated @since 2015-04-05 04:38:35 +00:00
bd741cd500 Use two buttons for graceful shutdown, restore notification title on cancel 2015-04-05 04:30:44 +00:00
4d7bc0f92b propagate from branch 'i2p.android.base' (head b76931f62977a8f15bd906d380795eddb0419d2a)
to branch 'i2p.android.base.zzz.graceful' (head 73baffc0c318d0c1b8c7ba05327ceefb2c84b341)
2015-04-05 02:41:52 +00:00
dac63d4401 NPE fix 2015-04-05 02:37:42 +00:00
8ed2ce3e3d Move AddressbookFragment to RecyclerView 2015-04-05 02:34:19 +00:00
c95f140fb4 NPE fix 2015-04-05 00:31:47 +00:00
4e21cc890f Better state handling for main UI fragments 2015-04-05 00:31:19 +00:00
cf3594962d NPE fix 2015-04-03 22:11:58 +00:00
9fa38c2840 Fixed addressbook search 2015-04-03 22:01:45 +00:00
2da8bbf214 Better descriptions for postman's tunnels 2015-04-03 12:03:55 +00:00
c984206f8e ActionBar up navigation 2015-04-03 12:03:42 +00:00
4a8b87d50c Reorder front UI tabs for better utility 2015-04-03 11:35:28 +00:00
a5a08a7282 Replace sub-toolbar with FAM for console menu 2015-04-03 11:33:08 +00:00
80f8469154 Some simple tests of the new tab UI 2015-04-03 00:12:41 +00:00
490137adc3 propagate from branch 'i2p.android.base' (head b76931f62977a8f15bd906d380795eddb0419d2a)
to branch 'i2p.android.base.fragments' (head 9af06a6f08e89e96c637b427e237538b600edc29)
2015-04-02 12:30:21 +00:00
d2959ddc3f Espresso testing support 2015-04-02 12:17:06 +00:00
6556156486 Fixed toolbar usage in activities 2015-04-01 12:40:15 +00:00
0095777a63 Replaced missing menu items 2015-04-01 12:24:58 +00:00
d8fc177b2d Better main tab locations for portrait and landscape 2015-04-01 11:36:22 +00:00
fcd5b2a503 Remove last of RouterContextProvider/RouterContextUser 2015-04-01 05:42:34 +00:00
0a5312e81b Missing from previous commit 2015-04-01 05:41:55 +00:00
7b67cf1581 Use Util.getRouterContext() for netDb list logic 2015-04-01 05:39:46 +00:00
2975b811d0 Use Util.getRouterContext() for tunnel list logic 2015-04-01 05:32:12 +00:00
ecb071ee88 Disable tunnel editing until ticket #815 is closed 2015-04-01 02:23:02 +00:00
624aa27e31 Updated README 2015-04-01 01:03:25 +00:00
a213ac51cd Finished diff after merge 2015-04-01 00:46:23 +00:00
db4a817ded propagate from branch 'i2p.android.base' (head 1b2db1a609968406ce50b5ab85bf3fe026d29d6f)
to branch 'i2p.android.base.fragments' (head d7c9088779c79670fb3be17fa039902345a5dc0e)
2015-04-01 00:40:08 +00:00
2407e9be46 Use LocalBroadcastManager to broadcast router state within the app 2015-03-31 23:51:18 +00:00
50973b5c06 Bugfix 2015-03-31 23:50:20 +00:00
8165e49300 Make handler static to prevent leaks 2015-03-31 22:43:59 +00:00
77749dd7f9 Lint removal 2015-03-31 13:57:21 +00:00
ef7e4cf610 Updated translations 2015-03-31 13:37:44 +00:00
a7b2bf148b Missing strings 2015-03-31 13:36:40 +00:00
3de78063f2 Missed changes 2015-03-31 12:36:38 +00:00
601d3c0ee3 Propagate visibility hints to TunnelListFragments too 2015-03-31 12:35:54 +00:00
3bcbd8c876 Store AddressbookFragment references, use to propagate visibility hints 2015-03-31 12:16:52 +00:00
e33be52b97 Only show "Reload subscriptions" for router addressbook 2015-03-31 12:15:20 +00:00
f513580525 Use Util.getRouterContext() in addressbook logic 2015-03-31 11:28:21 +00:00
ca2fde0b57 Changes missing from 1d97c209bb5a1634973da11e3dda3e96dad904e5 2015-03-31 11:27:51 +00:00
b442552146 NPE fix 2015-03-31 11:22:34 +00:00
9aee319607 Put tabs inside toolbar so action bar features can be used 2015-03-31 11:20:46 +00:00
d112e1a415 Listen for naming service changes 2015-03-31 03:20:03 +00:00
9cd6ab51ac Reorganize menus 2015-03-31 02:56:23 +00:00
6477f7d43f Common add button for tunnel views 2015-03-31 02:14:57 +00:00
65d1e6e089 NPE fix 2015-03-31 02:12:30 +00:00
6aff527456 Extracted FragmentPagerAdapter fragment recall into separate class 2015-03-30 22:42:31 +00:00
f32b896bb1 Fragment transaction bugfixes 2015-03-27 12:48:06 +00:00
58624ebf9d Add tabs using classes from Google IO sample code 2015-03-27 12:35:18 +00:00
db8355c477 Replaced navigation drawer and spinner with ViewPagers
First pass. Runs, but broken in many places.
2015-03-27 12:22:12 +00:00
a2278179f9 Missing file 2015-03-27 01:49:59 +00:00
3b3bcb30da Save tunnel config in onStop() if possible 2015-03-26 23:59:10 +00:00
d78b68d285 Tunnel preference bugfixes 2015-03-26 21:52:58 +00:00
00de9e98d2 Revert change accidentally checked into f4375e1bcf14aed1c7a94628599bead3bf866844 2015-03-26 13:49:57 +00:00
a543280a56 Updated translations 2015-03-26 13:23:27 +00:00
f036544744 Support numeric values for ListPreferences 2015-03-23 00:45:14 +00:00
8aa9ce9303 Bugfixes 2015-03-23 00:44:38 +00:00
1c605c16cf Edit tunnel UI 2015-03-20 03:58:23 +00:00
fc7f703658 Missing new widget from previous commit 2015-03-19 21:37:11 +00:00
163ef0512b Preferences XML for tunnel properties 2015-03-19 21:36:49 +00:00
6709bebc6f EditTextPreference that updates its summary (from Bote) 2015-03-12 23:01:11 +00:00
c7fad6940a IntEditTextPreference: default summary, use default value 2015-03-12 23:00:08 +00:00
4b1ee639b7 Tweaks after upstream changes 2015-03-12 00:07:35 +00:00
d2fa17fa66 Updates for upstream changes 2015-03-11 04:07:40 +00:00
87e12846b3 i2ptunnel.jar doesn't depend on I2PTunnelGUI anymore 2015-03-11 01:10:24 +00:00
97d1367180 Use TunnelConfig now in i2ptunnel.jar 2015-03-10 20:52:59 +00:00
a0419c9eb7 Add support-v4-preferencefragment as a dependency 2015-03-09 01:56:40 +00:00
5191118b87 Updated CHANGELOG 2015-03-05 22:24:39 +00:00
f5214e4b99 Include priority for logged strings (per upstream) 2015-03-04 19:07:57 +00:00
9564855cce Rewrite LogWriter to use LogWriterBase from upstream 2015-03-04 12:15:22 +00:00
17ab043a4b 0.9.18
i2p.i2p tag: i2p-0.9.18
2015-03-04 12:13:45 +00:00
32b2b0ce75 Updated TODO with Silent Store checklist (useful reference) 2015-03-04 12:12:44 +00:00
b77e2ebbe5 Updated translations 2015-03-04 01:11:48 +00:00
9eeab68cdb String translation fix 2015-03-04 01:11:44 +00:00
96257015a9 Language cleanups 2015-03-03 23:37:56 +00:00
d7f6e3688c UDP and NTCP ports, part 4 2015-03-03 22:50:26 +00:00
5ef434e29f Updated translations 2015-03-03 13:23:16 +00:00
852d695dac UDP and NTCP ports, part 3 2015-03-03 13:21:32 +00:00
96cb8ab410 Bugfix 2015-03-03 00:19:36 +00:00
cd158cca84 Updated translations 2015-03-02 22:57:37 +00:00
b71a0a27d3 Fixed help Activity back and up nav 2015-03-02 22:57:03 +00:00
64268c7af8 Activity title fixes 2015-03-02 21:45:13 +00:00
95749f032e I2PTunnel -> Tunnels / Hidden Services Manager; string tweaks 2015-03-02 21:29:34 +00:00
0ac1ae56b0 Dropped unnecessary part of tunnels guide 2015-03-02 21:17:43 +00:00
c52bc45910 Client library 0.5.1
i2p.i2p tag: i2p-0.9.18
2015-03-02 21:16:57 +00:00
064ebc6857 Moved missing class into client library 2015-03-02 11:03:02 +00:00
6352cd9412 Client library 0.5
i2p.i2p tag: i2p-0.9.18
2015-03-02 00:51:30 +00:00
db6c74b4b8 Updated translations 2015-03-02 00:02:40 +00:00
a8d699bea2 (Hopefully) prevent NPE 2015-03-01 23:49:13 +00:00
5d9cb0029f Fixed style API bug 2015-03-01 23:28:11 +00:00
51f7fca1ea Updated translations 2015-03-01 11:08:55 +00:00
c61ccd32ba UDP and NTCP ports, part 2 2015-02-28 12:36:59 +00:00
1debd64bc3 Pull property definitions into one location 2015-02-28 10:19:42 +00:00
561bcfe3fa New translations 2015-02-28 04:59:15 +00:00
1c1f77f5c5 Updated translations 2015-02-28 04:58:27 +00:00
420526a7c4 Updated changelog 2015-02-28 04:57:10 +00:00
99496be412 Settings options for UDP and NTCP ports 2015-02-28 04:49:18 +00:00
b6f1cdc769 Enable Java 1.7 features 2015-02-28 00:46:49 +00:00
75e4153f4e Fix stringOptionsRequiringRestart handling; add NTCP and SSU port parsing 2015-02-27 23:28:01 +00:00
eefa5b8064 Prep work for supporting removal of router.config properties 2015-02-27 22:52:39 +00:00
bae8c7ec00 propagate from branch 'i2p.android.base' (head 2cc736f12cfa9d56a7df3ab4be399cb256cbfc2c)
to branch 'i2p.android.base.zzz.graceful' (head deb95d5a40b64c460483f1e5af1a5624ff95fa6f)
2015-02-27 11:04:12 +00:00
9d32e44547 Logger: Configurable flush interval
From i2p.i2p rev 2f451e3579eb5df2d316c1b507950d119d59a8da
2015-02-27 11:04:03 +00:00
80c8069769 propagate from branch 'i2p.android.base' (head 473e458dab49137f8211dcad60554cd90078807d)
to branch 'i2p.android.base.zzz.graceful' (head 57a30f761ea3d230301347dbb8b79bd3540f97a2)
2015-02-27 10:49:50 +00:00
42a0d552c7 Fixed potential leak 2015-02-27 10:45:42 +00:00
65848dd22b Fix NPE in AddressEntryLoader 2015-02-27 10:20:00 +00:00
610de188a4 Downgrade to Gradle tools 1.0.1
1.1.* cause "Cannot resolve symbol" errors in Android Studio, even though Gradle
can build the app.
2015-02-27 09:50:34 +00:00
f1cd3032c5 Updated FAB library 2015-02-27 01:54:29 +00:00
1a922ba04a Updated build tools 2015-02-27 01:54:17 +00:00
bdd59734ec Updated Android support libraries 2015-02-26 23:34:49 +00:00
fe162e4f5c Updated Android Gradle build tools 2015-02-26 23:34:31 +00:00
69e30e97b8 Updated TODO 2015-02-26 23:33:53 +00:00
zzz
5b4b151079 Preliminary support for graceful shutdown.
New buttons not yet implemented.
Untested.
2015-02-08 00:02:56 +00:00
513fbe0c9f Updated translations 2015-01-15 10:34:13 +00:00
de23a76e6b Option to start I2P on boot 2015-01-15 10:31:25 +00:00
c9936894d8 Updated TODO 2015-01-15 05:47:01 +00:00
cb6efd9ed8 Updated translations 2015-01-01 23:18:19 +00:00
ad245003bf Updated browser config instructions for Firefox and Orfox 2014-12-29 11:40:04 +00:00
9f27aedc49 Added postman's tunnels to default i2ptunnel.config 2014-12-27 21:43:00 +00:00
d8f883dce8 Feedback from zzz 2014-12-25 09:48:26 +00:00
7db1fbac94 Updated translations 2014-12-23 23:39:13 +00:00
19464124d6 Fixed NPE on browser refresh 2014-12-23 22:30:04 +00:00
5ba616facc Updated TODO (thx for testing zzz) 2014-12-22 00:22:54 +00:00
590a8183aa Fix settings menu Intents in debug build 2014-12-17 02:42:13 +00:00
9a45bbd18c 0.9.17.1
i2p.i2p tag: i2p-0.9.17
2014-12-14 05:15:16 +00:00
c5eedc0a5e Updated translations 2014-12-14 04:28:50 +00:00
715302c813 Upgraded floatingactionbutton to 1.3.0, dropped unused cardview-v7 2014-12-14 04:26:38 +00:00
3327ed722a I2PTunnel: Ask to install app for tunnel, if none are installed when opening 2014-12-12 13:59:02 +00:00
40afd69a54 Enable debug versions to be installed alongside release versions 2014-12-12 13:55:31 +00:00
241381c7fa Fix copy tasks to run every time 2014-12-12 13:17:48 +00:00
7a7ba093db Added CHANGELOG 2014-12-12 06:03:41 +00:00
f0e6744760 Prevent NPE 2014-12-10 12:03:34 +00:00
99002c1c5c Updated translations 2014-12-10 11:51:41 +00:00
605a6c1cf4 Bumped support-v4 dependency in client library to 21.0.2 2014-12-09 21:43:26 +00:00
954a9cc46b Bumped gradle plugin to 1.0.0 2014-12-09 11:56:19 +00:00
1ef838b966 Fixed NPE 2014-12-04 06:56:52 +00:00
c672ca05f5 0.9.17
i2p.i2p tag: i2p-0.9.17
2014-12-02 00:40:17 +00:00
c493e73889 Client library 0.4
i2p.i2p tag: i2p-0.9.17
2014-12-01 08:40:48 +00:00
2b7c280f5b Tunnel details 2014-12-01 08:39:25 +00:00
23eab8a90a FloatingActionButton for I2PTunnel and addressbook 2014-12-01 03:57:21 +00:00
c59103eb76 Comments 2014-12-01 03:14:55 +00:00
f00a35ee09 Move versionCode and versionName definitions to build.gradle 2014-11-30 21:24:47 +00:00
af93725c01 Binding for Services 2014-11-30 11:35:15 +00:00
3953301c57 Fix intent generation 2014-11-30 10:55:34 +00:00
2dab9d5d4f Upgraded support libraries to 21.0.2 2014-11-27 11:42:48 +00:00
b77666fa26 New client library translations for ro 2014-11-25 11:44:46 +00:00
eca931c1b5 Updated translations 2014-11-25 11:44:22 +00:00
86ae77701f 0.9.16-rc1
i2p.i2p: cb66382d9716f7d9cd9441830face910705253e0
2014-11-25 04:48:48 +00:00
c1ee0c4d9e Updated Gradle Witness
Source: https://github.com/WhisperSystems/gradle-witness
Git commit: 10f1269c0aafdc1d478efc005ed48f3a47d44278
2014-11-25 03:51:52 +00:00
e632b35862 Bind to IRouterState using explicit intents (required for API 21 and up) 2014-11-16 18:49:11 +00:00
20d2dcd891 Updated translations 2014-11-16 03:06:29 +00:00
61d5ba5a7c Toolbar back navigation 2014-11-10 11:59:54 +00:00
339f688b7c I2PTunnel help 2014-11-10 11:55:33 +00:00
fed11e703a Don't start new activity if we are already there 2014-11-10 11:33:36 +00:00
438df8142a Settings back navigation 2014-11-10 11:27:11 +00:00
7b3730be24 Updated i2ptunnel.config, dropped Telecomix and Nameless 2014-11-10 10:43:11 +00:00
d6c20bafb3 Material design: one-line text lists 2014-11-10 10:42:05 +00:00
b8998db3a3 Revert to general Intent for selected addressbook entries 2014-11-10 05:39:48 +00:00
9ab1c84878 Material design: settings 2014-11-10 03:41:49 +00:00
2f3335d361 Material design: list items 2014-11-10 02:30:00 +00:00
0e8d900ed4 I2PTunnel secondary action to open linkable tunnels 2014-11-10 01:56:35 +00:00
2c7ce0b7c6 News fragment margins 2014-11-09 12:24:59 +00:00
3e2bdacf89 Material design: I2PTunnel list 2014-11-09 12:13:32 +00:00
64c32076a1 Show correct browser config activity 2014-11-08 07:50:50 +00:00
4d75ce7de1 Missing files 2014-11-08 07:50:30 +00:00
269ae2f569 Help details back nav in toolbar 2014-11-08 06:46:04 +00:00
a42a4b2c99 Reworked help navigation 2014-11-08 03:41:14 +00:00
96f5c2b488 Change property names to match original script (better interop with other repos) 2014-11-08 03:40:48 +00:00
09ab9779aa Addressbook doesn't use two columns yet 2014-11-05 00:50:55 +00:00
97ed0a3a8f NPE fix 2014-11-04 12:18:56 +00:00
ec6d225dc6 Icons for uninstalled supported browsers 2014-11-04 12:07:41 +00:00
800a332691 Swap Orfox with Firefox in supported browsers (no official Orfox release yet) 2014-11-04 12:02:02 +00:00
45eae17561 Simplify browser list UX 2014-11-04 11:54:22 +00:00
092365cab2 Help twopane view 2014-11-04 03:06:03 +00:00
c98c2f101d Updated TODO 2014-11-04 02:46:20 +00:00
8e86634a41 Recommended browsers, Orfox config, link to app store from browser list 2014-11-04 02:43:34 +00:00
7424e5b707 Browser configuration guides for embedded, Orweb, unknown and unsupported 2014-11-04 01:03:59 +00:00
5175c937a9 Help: List browsers, detect ones we know can (not) be configured for I2P 2014-11-03 12:26:58 +00:00
2692a567ab BetterAsyncTaskLoader from Bote 2014-11-03 12:23:24 +00:00
2de971fb52 New translations 2014-11-03 11:46:17 +00:00
403b2e8cd9 Material design: toolbar for help screen 2014-11-03 03:22:29 +00:00
22141e723a Fix back button when drawer indicator disabled 2014-11-02 23:20:13 +00:00
419758125e Updated translations 2014-11-02 12:42:44 +00:00
6db307c681 Client library 0.3
i2p.i2p tag: i2p-0.9.16
2014-11-02 01:46:33 +00:00
cdec6d2f98 Updated README 2014-11-02 01:36:11 +00:00
18a6dc9719 Use mavenLocal() repository instead of a local file repo 2014-11-02 01:35:55 +00:00
fb92d7858a Upgraded build tools to 21.0.2 2014-10-30 23:10:36 +00:00
b8e005bdd5 Copy tasks can only have one destination directory 2014-10-30 23:10:00 +00:00
6568489b27 Upgraded gradle wrapper and build tools 2014-10-30 12:15:49 +00:00
3ff3e14fc2 New Gradle Witness build
Includes a fix for Gradle 2.+ that is not yet pulled in:
https://github.com/WhisperSystems/gradle-witness/pull/3
2014-10-30 12:15:04 +00:00
092591f4ec Material theme: toolbar
Navigation tabs have all been replaced with spinners, because there are no nice
tab libraries for API 9+.
2014-10-29 11:47:53 +00:00
895a3a1dcc Fix deprecation 2014-10-27 21:37:52 +00:00
dc4ce3f8c7 Updated translations 2014-10-27 07:31:36 +00:00
7e3b9d5065 Updated translations 2014-10-22 21:15:55 +00:00
e58ffc9fd4 Material theme: nav drawer 2014-10-19 06:48:33 +00:00
0d029988c3 Material theme color definitions 2014-10-19 06:05:08 +00:00
6f01989a4b Nav drawer icon changed 2014-10-19 06:04:07 +00:00
19aeaec406 New material theme menu icons 2014-10-19 06:03:14 +00:00
b4d1241a9e Implement material styles properly with appcompat 2014-10-18 21:08:33 +00:00
fef4aa0e86 Initial migration to API 21 2014-10-18 06:11:39 +00:00
766266b147 Updated translations 2014-10-18 02:36:53 +00:00
93410c07bb Updated ignores 2014-10-17 08:02:24 +00:00
dc27a782b0 Fixed NPE in client library with State unparceling
This only fixes the symptom, but the crash log on Google Play doesn't shed light
on what the problem is.
2014-10-17 06:54:26 +00:00
zzz
b633df73c0 Update imports for move of router data structures 2014-10-16 23:10:32 +00:00
41d1200df7 0.9.15.1 2014-10-16 10:47:27 +00:00
c9a62fba9a Drop interface that isn't in source yet 2014-10-16 10:25:12 +00:00
c9598fa831 Update default subscriptions 2014-10-16 10:16:06 +00:00
9965c31b2d Pass dir and file to Util.mergeResourceToFile() in the correct order 2014-10-16 10:15:13 +00:00
43de6425b2 New translations for client library 2014-10-16 10:13:56 +00:00
b98cdf3e0b 0.9.15 2014-10-16 04:32:52 +00:00
26c11ebaed Updated translations 2014-10-16 04:30:49 +00:00
c9c3de1d04 Updated Androidplot to 0.6.1 2014-10-16 04:30:25 +00:00
9b29b56982 Upgrade support libraries to v20.0.0 2014-10-15 22:19:58 +00:00
8956fd7ce0 Updated translation strings 2014-10-15 21:52:46 +00:00
f1f94ea3e0 New translations 2014-10-15 21:49:32 +00:00
94b433aead Padding fix 2014-10-15 21:31:27 +00:00
5623d54114 Basic help page with HTML content 2014-10-15 21:21:11 +00:00
9133a2f848 Prepare for material theme 2014-10-15 10:36:55 +00:00
70324c3ecc Missing class 2014-10-15 02:50:37 +00:00
5613d21324 Replace first start warning dialog with browser config dialog 2014-10-14 11:15:14 +00:00
9036bf3f6b Re-enable (blank) help activity 2014-10-14 11:14:28 +00:00
94991d2df3 New type and status styles for tunnel list 2014-10-07 06:22:09 +00:00
76f23946f0 Don't show dialog on new version until we have something new to tell them 2014-10-05 04:12:29 +00:00
862e856913 Fixed graphs settings page notice when router not running 2014-10-05 03:38:17 +00:00
cf3de34cb6 Removed "participating" option from settings UI
Temporarily hidden because of problems with changing defaults. We don't want to
cause network instability because we have thousands of new unstable routers
churning the network, and can't change their default settings.

In future, we should look at the user's network and settings, and try to have 
"smart" defaults based on a user-chosen profile, or based on net type - see
Connectivity.isConnectionFast().
2014-10-05 02:59:18 +00:00
81de79c725 Remove "enable I2CP" from settings UI
Android apps should use the client library to connect to I2P Android. The TCP    
interface would only be useful if using the Android device as a gateway or 
dedicated router, but it would need to listen globally, not locally. If someone
asks for that in future, we can add this back and improve the configuration.
2014-10-05 02:53:09 +00:00
228b6f1baa Comment out disabling UPnP until other changes are finished 2014-10-05 01:17:31 +00:00
8e395cfd4e Detect more config options requiring restart 2014-10-05 01:16:17 +00:00
6d6123df9b Inform user that changing uPnP setting will require a router restart 2014-10-03 01:09:32 +00:00
321a49156c Display news in TextView instead of WebView 2014-10-03 01:04:26 +00:00
e8a47e17fb Developer note in default router.config 2014-10-02 11:02:06 +00:00
9df27ea168 Move property file writing methods to Util 2014-10-02 04:06:17 +00:00
cb6b7c4f48 getRouterContext() helper function 2014-10-02 03:55:24 +00:00
ca623e6b18 New class for connectivity checks
Source: https://gist.github.com/str4d/22cac7a3f70bc227cdca
License: http://opensource.org/licenses/MIT
2014-10-02 02:02:26 +00:00
8b6e02136e Fix TextResourceDialog scrolling 2014-10-01 21:06:07 +00:00
6a0493a578 Updated release notes 2014-10-01 20:58:22 +00:00
bf2a437a82 Initial news space fixes 2014-10-01 20:47:02 +00:00
ac949e3f5e Don't use wide view for news webview 2014-10-01 10:50:09 +00:00
7483251393 Copy log entries to clipboard, tweak copy text 2014-10-01 10:31:28 +00:00
d690b7d861 Copy logs to clipboard 2014-10-01 10:23:36 +00:00
829695d690 Move licenses menu option to about dialog button 2014-10-01 03:31:18 +00:00
05c2dbd388 Javadoc improvements
This is the client library 0.2 commit
2014-09-29 23:54:28 +00:00
c8e1643326 New client library translations for ru 2014-09-29 23:53:48 +00:00
d72c936a0e Fix addressbook settings header Intent bug 2014-09-29 23:52:59 +00:00
06d4d7d10d New client lib translations for fr 2014-09-29 04:08:30 +00:00
b506b5e740 New translations for client library 2014-09-26 23:19:38 +00:00
2d65bd373c Configure Transifex for client library strings 2014-09-26 12:28:15 +00:00
7c869adf58 Client library helper class
Based on OrbotHelper from libnetcipher, with logic from i2p.i2p-bote.android
2014-09-26 12:27:51 +00:00
61a7566007 Client library 0.2
i2p.i2p tag: i2p-0.9.15
2014-09-25 05:00:28 +00:00
9d42901079 Updated translations 2014-09-25 04:57:47 +00:00
fb31818a3c 0.9.14.1-rc3 2014-08-23 01:24:52 +00:00
6355214b5f Updated translations 2014-08-23 01:01:37 +00:00
d5c0704477 Updated TODO 2014-08-23 00:45:18 +00:00
411131b8a6 Updated translations 2014-08-23 00:45:04 +00:00
10ed266d2c Clarify property inversion 2014-08-23 00:25:40 +00:00
bccfe03b5d Sync settings XML defaults with router.config defaults 2014-08-22 23:30:35 +00:00
a44ac8a45c Another domain name fix 2014-08-22 14:02:23 +00:00
5610752c6d Updated old domain names 2014-08-22 14:01:19 +00:00
7047913b45 Updated translations 2014-08-22 13:57:33 +00:00
a41aa79920 Explain to users that graphs need to be configured 2014-08-22 13:22:38 +00:00
4fcc1121b7 Padding tweak 2014-08-22 12:09:55 +00:00
514aa51224 Fixed images in peers WebView 2014-08-22 11:50:53 +00:00
0c46dc9bd0 Display auto-start setting in I2PTunnel details 2014-08-22 11:27:11 +00:00
4b7f951e32 0.9.14.1-rc2 2014-08-21 14:37:40 +00:00
a58a9d7540 Fixed "called on wrong thread" issue in browser 2014-08-21 14:33:39 +00:00
d3eaebd324 Temporary fix for a settings bug 2014-08-21 13:40:59 +00:00
37c366a528 Client library 0.1.1 2014-08-21 10:55:32 +00:00
8f6289984b 0.9.14.1-rc1 2014-08-20 11:19:33 +00:00
7629bb54ce Feature graphic for Google Play 2014-08-20 06:41:41 +00:00
ee7d227990 Fixed sq translation 2014-08-20 04:34:44 +00:00
4cc940c995 Updated TODO 2014-08-20 04:28:19 +00:00
2336eebdd0 New translations: sq U id 2014-08-20 04:02:50 +00:00
62035050c5 Padding tweak, prevent status headings flicker when opening app 2014-08-20 03:37:20 +00:00
6775d57c22 Rearranged nav drawer, only show graphs peers and netdb for advanced users 2014-08-20 03:02:29 +00:00
d3a1910b2e Return null on unknown State in Parcel 2014-08-20 02:37:27 +00:00
aa43d960dc Revert AndroidManifest.xml package name change
Changing this requires changing the import path of the generated R file, which
will unnecessarily affect most of the code. R is built in a package based on
the AndroidManifest.xml package name, whereas the final app package name is
overridden in app/build.gradle for free and donate versions.
2014-08-18 14:50:54 +00:00
2e3047274e Added legacy flavor with old app ID, fixed package names in manifests 2014-08-18 13:11:47 +00:00
a3cef11e08 Updated ignores 2014-08-17 23:13:23 +00:00
543fb51d76 Simplify adding client library to a local flatDir repo 2014-08-15 01:41:16 +00:00
4328db1908 Fixed source and javadoc jar creation 2014-08-07 13:25:02 +00:00
69fbb5dc92 Updated translations 2014-08-07 06:57:43 +00:00
0c5d8f8e9e Moved jbigi to client library, so clients get benefit 2014-08-06 22:45:06 +00:00
b88e150803 Final changes, x86 and MIPS libjbigi.so now build
Untested, we need to find x86 and MIPS devices to test with.
2014-08-06 10:52:22 +00:00
35fe44fc59 Initial x86 and MIPS support (not enabled, missing --host parameters) 2014-08-06 00:08:03 +00:00
464adb9e71 More non-ABI-specific script 2014-08-05 23:31:01 +00:00
66d370abeb Reorganized to run non-ABI-specific parts of script first 2014-08-05 23:25:10 +00:00
11aded07ca Refactored to pull out ABI-specific settings 2014-08-04 01:29:04 +00:00
5d0861e22e Only allow numbers in I2PTunnel wizard port fields (ticket #1331) 2014-08-03 21:18:05 +00:00
5778eb9d1c Updated translations 2014-07-26 02:44:45 +00:00
0e47bc5042 Updated translations 2014-07-19 23:26:55 +00:00
8f9a6922ad Bugfixes 2014-07-17 06:40:17 +00:00
05cc0634b7 Updated README 2014-07-17 06:31:04 +00:00
583666695c Improved Maven upload code, collected parameters in gradle.properties
maven-push.gradle source:
https://github.com/chrisbanes/gradle-mvn-push
2014-07-17 06:29:40 +00:00
e67ba59e51 Uploading to the Central Repository 2014-07-17 05:41:57 +00:00
ab619f904d Reverted to Enum for State, make it Parcelable
Talked with zzz and did more research, the overhead of Enum is minimal compared
to the benefits it provides.
2014-07-17 00:56:04 +00:00
f2f7418c8b Ignore old Enum state 2014-07-16 05:26:44 +00:00
23c55d50fb Remove I2CP port starting, clients can use domain sockets now 2014-07-16 04:20:40 +00:00
e0acb322a5 Lint 2014-07-16 03:47:17 +00:00
2a1427054d Use static int constants for State instead of Enums
Enums often require more than twice as much memory as static constants, and
should be strictly avoided on Android.
https://developer.android.com/training/articles/memory.html#Overhead

The advantage of this change is that client library users can directly compare
the status values they get from IRouterState to the constants, instead of
parsing a string representation of an Enum.
2014-07-16 01:28:49 +00:00
d878d2d8a4 Moved AIDL interfaces to client library 2014-07-16 01:25:19 +00:00
5386829edf Implemented I2CP connections over Android Local[Server]Sockets 2014-07-15 13:03:33 +00:00
5d74e7ffef Comments 2014-07-15 11:13:55 +00:00
332ec1e0ad Corrected client library package group 2014-07-15 11:08:39 +00:00
060262ee52 Separated client library version 2014-07-15 10:16:07 +00:00
c75fe55e56 Updated client library package 2014-07-15 08:56:41 +00:00
bccf5e0965 Bundle I2P libs in client AAR 2014-07-15 06:19:31 +00:00
6bd905a027 Fixed client building (thanks alkemist from Freenode#gradle) 2014-07-15 03:40:47 +00:00
fc0b393b14 Markdown fix 2014-07-15 01:52:59 +00:00
f2acde73fe Specify full version for Android Gradle plugin so script compiles when offline 2014-07-14 12:39:32 +00:00
77a7f5f603 Client library AndroidManifest.xml 2014-07-13 21:56:26 +00:00
d235da093f Build script for client library 2014-07-11 05:18:46 +00:00
795d3ab314 Updated translations 2014-07-07 02:58:49 +00:00
dd40931a23 Correct version code for current release
If we move to increment-by-one instead of calculating the version code, we need
to keep the code above the current highest generated code, so that F-Droid will
order new builds correctly above old builds.

If we decide to go back to calculating version codes later, it is possible - we
can increment the version code 2047 times before it will clash with the one for
0.9.14.
2014-07-07 02:43:16 +00:00
8b71e4fc2e Fixed CacheProvider authorities clash 2014-07-07 02:38:51 +00:00
ed61f0414e Padding tweak 2014-07-07 01:24:57 +00:00
06ef95c7ac Better layout padding for main view 2014-07-07 01:14:58 +00:00
2936bfc2b7 wrap long lines 2014-07-04 00:41:33 +00:00
9c655ffebf move from cat|grep|sed to awk 2014-07-04 00:41:17 +00:00
9d8fb684d2 Fixed building armeabi libjbigi.so 2014-07-03 22:36:20 +00:00
0d744e269c Static verification of remote dependencies using Gradle Witness
https://github.com/WhisperSystems/gradle-witness
2014-07-01 05:06:48 +00:00
36ffb6eda4 Default to ../i2p.i2p for copying I2P resources 2014-07-01 04:54:19 +00:00
df7ee4bd05 Updated README 2014-06-29 02:58:32 +00:00
d98d6abff3 Updated android gradle plugin version 2014-06-29 02:33:47 +00:00
260cc8a5a2 Updated gradle specified in wrapper to 1.12 2014-06-28 23:42:13 +00:00
zzz
a0a1df8093 Remove local copies of I2P Secure* utilities since we are
now on Java 6 (API 9).
2014-06-28 15:37:59 +00:00
e4110eb894 Signing instructions 2014-06-28 04:21:45 +00:00
d0264bf475 Addressbook license is copied over, should not be checked in 2014-06-28 02:04:12 +00:00
7ec8b0a592 Copy I2P resources 2014-06-28 02:03:39 +00:00
e3ecac8fec Rquirement: Android Support Repository 2014-06-28 00:40:02 +00:00
4fdc7940dd Version 2014-06-27 17:26:04 +00:00
9920ad34cd Renamed package to net.i2p.android, added free and donate flavors 2014-06-27 17:08:44 +00:00
8a7025038a New translations 2014-06-27 16:40:17 +00:00
a47c80df8c Updated Transifex config 2014-06-27 16:40:10 +00:00
a1a5aeaf6c Don't abort on lint errors 2014-06-27 16:34:01 +00:00
3a8eeabe3e Improved handling of signing keys 2014-06-27 16:29:43 +00:00
3e34bac295 Updated README 2014-06-27 16:19:36 +00:00
66d0dce40c Dropped Eclipse files 2014-06-27 15:55:20 +00:00
c8d3ee7aac Updated ignores 2014-06-27 15:51:55 +00:00
959537adc2 Reflowed AndroidManifest.xml, added missing parent meta-data for below API 16 2014-06-27 15:46:34 +00:00
7ca050fdf5 Cleaned up routerjars 2014-06-27 15:20:58 +00:00
07130abf23 Update min API to 9 (Gingerbread) 2014-06-27 15:15:15 +00:00
ba82d59b89 merge of '3a37cc3435714b0ed267c4f01159b77e1e59cd87'
and 'b1d84ce6fa493115c9ddc12b5a5a5a62c4dadee6'
2014-06-27 15:13:02 +00:00
8819dc5f30 Build scripts 2014-06-27 15:11:49 +00:00
zzz
a034b78dfd Update min API to 9 (Gingerbread).
API 8 (Froyo) is now less than 1% of active devices, and
these devices are generally too low-powered to run I2P effectively.
This allows us to move the remaining I2P jars to Java 6.
2014-06-27 13:52:29 +00:00
2dc56d57d4 Reorganized files 2014-06-27 11:42:20 +00:00
3aff1c4f75 Added gradle wrapper 2014-06-27 06:56:12 +00:00
55509adda6 Ask user to enable I2CP if app requests start with I2CP disabled 2014-06-20 02:33:22 +00:00
zzz
19def413c1 Make shared clients (IRC) delay-open since the HTTP proxy
is not a shared client any more.
2014-06-14 11:31:27 +00:00
63a0e2117f Copy i2ptunnel.config from resource for new installs 2014-06-12 23:17:05 +00:00
21e0b2a667 Listen for START_I2P action 2014-06-03 23:49:10 +00:00
6ce15e27de Updated translations 2014-06-02 22:08:00 +00:00
7a0a56373d Fixed remote usage of IRouterStatus 2014-06-02 21:40:23 +00:00
37da05ca98 Pull in changes to defaults while maintaining user settings 2014-06-01 02:50:15 +00:00
f003bbbfa4 Fixed settings parsing 2014-05-31 23:56:30 +00:00
zzz
a6978bb161 fix net status text 2014-04-27 18:59:34 +00:00
b1ec76de5a Missing change in landscape layout 2014-04-18 11:28:36 +00:00
dc58796c97 Updated TODO 2014-04-09 02:03:38 +00:00
c7075c3fc4 Pull API level from routerjars/AndroidManifest.xml.in 2014-04-09 02:03:25 +00:00
8d4f1b174d Check routerjars/local.properties for NDK dir (ticket #1032) 2014-04-09 01:52:39 +00:00
6f29991829 Updated translations 2014-04-08 12:38:39 +00:00
a414b10ce8 Long press to start/stop router (prevents accidental presses) 2014-04-08 01:12:52 +00:00
030fc60445 Updated i2ptunnel.config from upstream 2014-04-08 00:47:52 +00:00
9d215353e8 Updated release notes 2014-04-08 00:27:29 +00:00
f0a2166ae0 Correct Android forum URL 2014-04-08 00:27:17 +00:00
af097474de Padding 2014-04-08 00:25:43 +00:00
5a1fc32da4 All logging is conditional 2014-04-07 23:53:52 +00:00
7218b79643 Hide Help page until it is finished 2014-04-07 22:48:40 +00:00
ccd5ae45df Removed old translations that have no default string 2014-04-07 22:47:47 +00:00
3584890277 HTTP client tunnel bug disappeared...? 2014-04-07 22:27:47 +00:00
4e17010f59 New translations for nb 2014-04-07 21:22:50 +00:00
aa8009cb70 Updated translations 2014-04-07 21:22:03 +00:00
30d1816c43 Updated translations 2014-03-31 21:25:04 +00:00
02c25ba174 Updated translations 2014-03-16 21:50:14 +00:00
8f8bbcb19f Show "router not ready" message on graph settings page 2014-03-16 10:50:00 +00:00
696ae2bfc0 Prevent graph settings being wiped just after router start 2014-03-15 21:33:31 +00:00
0ea468ea71 Updated TODO 2014-03-15 12:37:40 +00:00
a2d9adb071 Implement required API 19 method override 2014-03-09 09:36:36 +00:00
b8cc64d4ea Updated translations 2014-03-07 21:48:14 +00:00
6e3e99c62f Fixed unzipping resources 2014-03-04 03:28:05 +00:00
84a63cc911 Updated TODO 2014-03-04 03:14:43 +00:00
b8c3b7e3df merge of '1af98386e3efe227cfa78be17a8c4a7785aeea8a'
and '87e720357989c67de7752f3616a85c09b5975eda'
2014-03-04 03:07:32 +00:00
04e190d2d0 Updated translations 2014-03-04 03:07:23 +00:00
ce2a762db2 Temporarily enable inbuilt browser until an alternative is ready 2014-03-04 03:00:13 +00:00
76014f2081 Move hardcoded strings to strings.xml 2014-03-03 22:01:26 +00:00
6d570646f1 Build addressbook.jar instead of addressbook.war (no Jetty dependency) 2014-03-03 03:50:23 +00:00
104c17cb9c Dropped unnecessary drawables 2014-03-01 21:32:49 +00:00
0860ee83b0 propagate from branch 'i2p.android.base' (head 76695da8c3e4ec8e9a3034baa1d60babbef279ac)
to branch 'i2p.android.base.fragments' (head 912c186827c29b8237045712fb25b7500a994fb3)
2014-03-01 21:29:51 +00:00
zzz
707c0e9aa8 url updates 2014-03-01 16:19:02 +00:00
163bc2ce58 only build router once 2014-02-27 02:58:59 +00:00
cec1f8fe52 propagate from branch 'i2p.android.base' (head 13ee72756c9d5407dafed769cda7c7dd5bd66cce)
to branch 'i2p.android.base.fragments' (head 29d48eb27592b749718622a683371d10f07431b2)
2014-02-27 01:57:16 +00:00
97f52f8139 remove res/raw/license_fatcowicons_txt in the clean target 2014-02-27 01:45:00 +00:00
0094cc5637 Only build the router.....when building (ticket #1214) 2014-02-27 01:31:52 +00:00
01c994e7b2 fix tag 2014-02-27 01:30:07 +00:00
b60ae00fd7 19 isn't a valid target anymore; it's now android-19 2014-02-26 23:50:28 +00:00
2340500083 Updated Irc2P servers 2014-02-24 01:14:11 +00:00
zzz
a91261f5ca JNI Build:
- Update JNI build script to use GCC 4.6, required for
   NDK r9b and higher (ticket #1202)
 - Add more checks in build script, to fail quicker on problems
 - Move default NDK build location up one directory level
 - Fix setting JAVA_HOME
 - Fixes for running script in the directory

 I did not replace the checked-in 4.4.3 libjbigi.so with
 the new 4.6 version, as there's no need.
 The 4.6 version will be tested by nextloop in the F-Droid build.
2014-02-23 16:40:47 +00:00
a145729353 Updated .mtn-ignore 2014-02-21 06:32:00 +00:00
0270444a94 Added missing drawables 2014-02-21 06:12:11 +00:00
01e22f4fb5 Updated TODO 2014-02-21 00:14:21 +00:00
2e892841cb Display text from initial news when router is first started 2014-02-21 00:14:07 +00:00
e271dc90ae Removed License button from VersionDialog 2014-02-21 00:13:03 +00:00
77ced0bd1f Revert to RouterLaunch.main(null) (upstream fixed) 2014-02-20 23:06:42 +00:00
ac67533ef2 Moved classes around 2014-02-20 21:42:25 +00:00
305c834aa1 Updated TODO 2014-02-20 11:18:02 +00:00
cbb2973b36 Linkify .i2p URLs 2014-02-20 10:35:22 +00:00
f360ab4d5d Updated RouterService with changes to RouterLaunch.main() 2014-02-20 06:38:51 +00:00
296d21d1d0 Added notifications for clients; notify on news update 2014-02-20 06:36:57 +00:00
a5dd751227 Register shutdown hook in NewsFetcher 2014-02-19 07:16:01 +00:00
d47bdf85d2 New translations 2014-02-07 04:30:04 +00:00
c2a33541b3 Updated translations 2014-02-07 04:28:55 +00:00
3e46d98481 Use the tunnel type ImageView to show tunnel status 2014-01-27 06:18:11 +00:00
124b1499b4 Show list of running tunnels 2014-01-27 06:02:12 +00:00
2d8529e691 Show full router stats as advanced option 2014-01-27 03:37:57 +00:00
4a135023b9 Layout id renaming 2014-01-27 02:51:48 +00:00
e9fbe8c2ef Removed website and FAQ links from nav drawer, added website link to about 2014-01-27 02:31:10 +00:00
228d0204fc Updated TODO 2014-01-26 06:47:32 +00:00
0ebecd9b64 Changed navbar first-use mechanics to match Android design pattern 2014-01-26 06:38:34 +00:00
c062a0f803 Missing change in layout-land 2014-01-26 05:35:46 +00:00
4f24517de9 Hide status ScrollView if router not running 2014-01-26 05:12:45 +00:00
d8636ff563 Added About dialog 2014-01-26 04:59:16 +00:00
4e57f78931 Disable WebActivity from receiving URL Intents 2014-01-26 00:19:17 +00:00
ccbbc3c368 Added link from Log Activity to Logging settings
TODO: Fix link for Preference headers
2014-01-25 20:21:11 +00:00
b9374b5ead Manually set state to WAITING 2014-01-22 15:18:14 +00:00
ceaff935d6 New status image for "no internet" 2014-01-21 07:00:01 +00:00
255702b6bb Updated TODO 2014-01-21 06:52:31 +00:00
2e68aa900b Change to RI tab when viewing RI from LS 2014-01-17 14:57:47 +00:00
67eddba621 Display current default log level in settings 2014-01-17 00:17:54 +00:00
29fb1f0689 Added missing file 2014-01-16 23:56:59 +00:00
de605a1d5b Removed unused import 2014-01-16 23:48:31 +00:00
41b49b7bc8 Call onRouterBind() of detail fragment in two-pane mode 2014-01-16 23:47:49 +00:00
c691a11c3d Added scrolling to RI and LS detail fragments 2014-01-16 19:29:02 +00:00
2f6b1189ae Hide edit action in I2PTunnel 2014-01-16 19:10:33 +00:00
a7a328238b Added TODO list 2014-01-16 18:15:46 +00:00
c9c31ccb76 Stubbed out code for log-level overrides 2014-01-16 18:05:01 +00:00
8457f279f2 Moved debug log entries to Util.d() 2014-01-16 17:40:14 +00:00
fbf353858e Added settings page for logging, config option for default log level 2014-01-15 17:45:40 +00:00
99ef07d1fc Added action to manually reload subscriptions 2014-01-15 02:40:20 +00:00
a5f5e97e37 Use new ClientApp interface to start/stop BOB 2014-01-15 02:04:36 +00:00
165bcc1c9d Removed temp changes 2014-01-11 23:41:02 +00:00
45efd6670f Adjusted labels 2014-01-11 23:40:07 +00:00
b601722b31 Removed temp changes 2014-01-11 23:39:48 +00:00
14e1a2dca1 Notify user if router not running when opening graph settings 2014-01-11 22:40:10 +00:00
d2385166cb Fixed race between router binding and onCreateOptionsMenu() 2014-01-11 22:30:12 +00:00
ed17d59896 Fix WebActivity handling of indirect Intents 2014-01-11 22:06:38 +00:00
55cfd455ca Use indirect Intents to open URLs 2014-01-11 22:06:09 +00:00
f207cf3116 Removed unneeded import 2014-01-11 21:07:42 +00:00
5825d1d2a5 Fetch router state in onResume() 2014-01-11 21:07:22 +00:00
zzz
077f9902a9 update to API 19 2014-01-11 17:36:45 +00:00
d77cbde3b3 Updated target API to 19 2014-01-05 06:00:57 +00:00
62ff63665f Fixed check for state on shutdown 2014-01-04 07:34:02 +00:00
1377aceb18 Use images derived from I2P logo for status 2014-01-04 07:31:59 +00:00
c7617ba856 Ensure state image is correct when router has shut down 2013-12-30 00:08:29 +00:00
08c6018483 Added State.ACTIVE to indicate when router is ready for use 2013-12-30 00:03:08 +00:00
f9f283409d Fixed out-by-one error in logs 2013-12-29 23:34:04 +00:00
4ef42cb462 Scrolling for log entries 2013-12-29 23:30:04 +00:00
65428dda8e Fix IRouterState Service connection leak properly 2013-12-29 23:29:49 +00:00
6311ab4b67 Comment to explain dual-pane criterion for preference headers 2013-12-29 19:22:31 +00:00
0c20a45207 Don't update filter list if content not loaded 2013-12-29 19:18:48 +00:00
6712148010 Fixed potential leak of IRouterState Service connector 2013-12-29 19:07:09 +00:00
07e6e293bc AIDL interface for getting router status, used for MainFragment status images
Other apps can use this interface by copying the AIDL files into their source
tree.
2013-12-29 18:04:39 +00:00
2dd1655e1e Type argument changes caused by i2p.i2p cleanup 2013-12-18 05:26:58 +00:00
97037fe1d8 New translations 2013-12-06 12:20:31 +00:00
d79f797558 Reorganized source files by section instead of by type 2013-12-06 07:56:09 +00:00
42649e02ea Replaced logo with status images, combined start and stop buttons 2013-12-06 02:20:32 +00:00
c6aeb79944 Created some status indication images for the main page based on I2P logo dots 2013-12-06 02:16:48 +00:00
fb66ec62d6 Improved IRC tunnel names/descs 2013-12-05 00:49:50 +00:00
15f1e18da1 Added Nameless IRC to default tunnels 2013-12-05 00:47:32 +00:00
15caf8a97c Reorder main fragment 2013-12-05 00:36:38 +00:00
44989a42f2 Remove bigText when replacing status 2013-11-25 20:29:44 +00:00
3867eb6fda Fixed positional substitution 2013-11-25 20:24:43 +00:00
0755e79b1a Status bar: Show status details as bigText, mirror router status in title 2013-11-25 20:23:31 +00:00
3a1e43b322 Use NotificationCompat.Builder 2013-11-25 11:33:39 +00:00
6a2d494921 Show full Log entry in a detail page 2013-11-19 11:39:55 +00:00
be14d65899 Renamed Log listitem layout, limit list to max 3 lines 2013-11-19 10:50:58 +00:00
c42dc725d6 Migrated LogFragment to use loader 2013-11-19 02:34:58 +00:00
83ab1d09ae Don't crash if RI or LS lookup returns null
Todo: determine why some lookups of OBEPs can be null, and handle the null case
in the UI.
2013-11-18 06:29:07 +00:00
af30dc8e24 Fixed addressbook crash 2013-11-18 06:10:35 +00:00
0268ce13ad Missing change to strings 2013-11-17 20:11:31 +00:00
5b897bc993 Show number of search results in addressbook 2013-11-17 20:09:16 +00:00
1fbf6b1b72 State that File Manager is needed 2013-11-17 12:13:40 +00:00
8095eed241 Added wizard page to read B64 from text file 2013-11-17 12:05:59 +00:00
8916c123ef Hide actions when router not running 2013-11-17 10:40:48 +00:00
b742dd8ee8 Use callback for TunnelListFragment 2013-11-17 10:27:05 +00:00
b02b446e46 Fixed addressbook crash when router not running 2013-11-17 06:26:32 +00:00
01b07fed5b Simplified callback system 2013-11-17 06:19:50 +00:00
2fa205daec Router-down fixes 2013-11-17 05:58:32 +00:00
3644d738ee Cleanups 2013-11-16 22:29:21 +00:00
c044c4de4d Use new callbacks for NetDbDetailFragment 2013-11-16 22:18:04 +00:00
c705527113 Handle corner case where onRouterBind() not called but RouterContext available 2013-11-16 22:13:39 +00:00
8b79af434e Use new callbacks for NetDB 2013-11-16 22:07:32 +00:00
2c8e9d62be Use new callbacks in AddressbookFragment 2013-11-16 21:57:33 +00:00
9832779a50 New callback system to make getRouterContext() reliable 2013-11-16 21:56:10 +00:00
9f535a3260 Save data from add wizard in private book
This does nothing. getRouterContext() is always null when onActivityResult() is
called. Todo: implement callback that fires when the Router has bound and the
Fragment has an Activity.
2013-11-16 10:10:22 +00:00
0beaec366f Use ns.getEntries() to get both name and Dest, and for filtering 2013-11-15 20:30:57 +00:00
8c288ad559 Basic add-to-private-book wizard, does nothing 2013-11-15 10:04:49 +00:00
df5d5ad38e Abstracted most of TunnelWizardActivity 2013-11-13 09:55:53 +00:00
8b1648c37b Only allow adding to private book 2013-11-13 07:57:58 +00:00
cea42e9ec4 Enable privatehosts.txt 2013-11-12 09:54:36 +00:00
64c44838a8 Hide list when loading, remove Toast notification from onLoadFinished()
Addressbook Loader works (from previous commit). Todo: put name count
in list header.
2013-11-12 05:35:08 +00:00
76f9259ee7 Filter addressbook in the Loader 2013-11-12 02:42:46 +00:00
d437f45132 Use TreeSet to sort Addressbook names 2013-11-12 02:33:19 +00:00
fc618ad9e5 Disabled country lookup, no GeoIP file 2013-11-12 02:20:39 +00:00
15275680e8 First pass at migrating Addressbook to use Loaders
Broken, addresses do not load into mAdapter after a tab change.
2013-11-12 01:10:29 +00:00
7848a81110 Added tabs to Addressbook 2013-11-12 01:01:34 +00:00
207f9837d0 Don't duplicate RouterContextProvider interface 2013-11-12 00:42:14 +00:00
cda09ea4f5 Suppress "unchecked" warnings 2013-11-11 21:41:26 +00:00
2a15994a76 Load real stats into NetDb ViewPager
getRouterContext() returns null in onActivityCreated(), there is a race
condition to fix somewhere, use refresh action to load.
2013-11-11 20:23:07 +00:00
e954953130 Reconnect to existing loader when screen rotated 2013-11-11 19:57:58 +00:00
8b51c26a6b Expanded NetDB detail pages to match /netdb 2013-11-11 10:02:52 +00:00
d40f806be6 Use Util.e() 2013-11-11 04:06:04 +00:00
bf5b29da76 Fixed NetDB detail filling 2013-11-11 04:03:08 +00:00
18c4276ba0 Fixed id 2013-11-11 04:01:39 +00:00
a4107e974a First pass at NetDB details, runs but View is not filled 2013-11-11 03:26:32 +00:00
8dd35f6c0f New translations 2013-11-11 03:23:40 +00:00
5a4be4ae86 Added missing file 2013-11-11 03:17:12 +00:00
9527725760 Process RI/LS in NetDbEntry, use DatabaseEntry when possible 2013-11-11 03:15:34 +00:00
b6a8fc02f5 Removed unused import 2013-11-11 01:25:21 +00:00
7794a7db5b Use manual action to refresh NetDB list instead of timer 2013-11-11 01:22:52 +00:00
c03debf332 Implemented Entry/Loader/Adapter for NetDbListFragment 2013-11-10 22:30:52 +00:00
fbc56d4eb9 Only use ViewPager for NetDb stats 2013-11-09 12:25:03 +00:00
2a050b3ca1 Updated AndroidManifest for renamed class 2013-11-09 12:20:28 +00:00
48c8d84d2f Fixed new version dialog text 2013-11-08 20:56:52 +00:00
b6d6258e95 Renamed Rate graph code 2013-11-08 19:41:17 +00:00
47215495ed add patch from ticket #1103, consistency fixes, remove some unneeded bashisms, set proper JAVA_HOME on OSX 2013-11-01 02:01:15 +00:00
9e45f1998b remove executable bit 2013-11-01 01:59:40 +00:00
788445f6ce New translations 2013-10-15 19:52:39 +00:00
a057e4a512 Show dialog if graphs are not ready 2013-09-28 13:36:31 +00:00
7a09670097 Removed unused import 2013-09-28 12:15:58 +00:00
c92d881a51 Dynamically fetch current list of graphs 2013-09-28 12:11:30 +00:00
8c2ba03880 Added settings for which graphs to plot
The onPause() method in SettingsFragment was removed as it is unnecessary. The
parent SettingsActivity onPause() is sufficient to save config changes.
2013-09-28 11:34:54 +00:00
9c9f871667 Fixed some warnings 2013-09-28 02:39:41 +00:00
7f9758197d Missing changes from previous commit 2013-09-28 02:18:11 +00:00
f6d1c093e4 Migrated SettingsActivity to preference headers 2013-09-28 02:17:35 +00:00
5e045bc23b Show current value in exploratory tunnel settings menu
TODO: Refresh summary when a setting is changed.
2013-09-26 21:23:30 +00:00
f667a81c6d Stop TunnelDetailFragment crashing if mTunnel is null
TODO: determine why mTunnel is not being set.
2013-09-25 03:52:27 +00:00
a13a405b49 Created white itoopie SVG, exported new notification icons 2013-09-25 03:38:36 +00:00
383ece497f Pulled in (and cleaned) SVG from i2p.itoopie, exported cleaner launcher icons 2013-09-25 02:16:30 +00:00
075c7c09d7 First draft of NetDB page: nav drawer w/ ViewPager, tabbed categories 2013-09-20 05:28:18 +00:00
7cec48e55f Combined error log and log views into a drop-down list 2013-09-08 06:48:58 +00:00
7ddd3c69c8 Save and restore selected rate graph 2013-09-07 13:49:16 +00:00
9d965a5504 Removed hard-coded title from graph (drop-down is more informative) 2013-09-07 13:44:55 +00:00
abd4a99654 Moved hard-coded list of graphs from nav drawer to actionbar drop-down 2013-09-07 13:42:27 +00:00
92c734624d Save and restore selected tunnel tab 2013-09-07 13:15:40 +00:00
81d0441d2b Implemented stat graphing
StatSummarizer and SummaryListener are based on the same-named classes from the
routerconsole. Data is stored in memory using an AndroidPlot SimpleXYSeries.
Only the last 30 points are currently stored.
2013-09-07 08:07:15 +00:00
9c7b2142cf AndroidPlot library version 0.6.0 from http://androidplot.com/download/
License: Apache 2.0
2013-09-07 08:05:33 +00:00
3da41888b7 Don't delete libs/ 2013-09-07 07:58:16 +00:00
bf47b901b7 Restored reload action (needed to update webpage if cached), fixed back nav 2013-09-06 00:53:03 +00:00
54a446ebdb Fixed Addressbook domain opening in left column of two-pane mode 2013-09-05 23:45:55 +00:00
0eb0c67616 Moved remaining links on main page to nav drawer
A WebActivity has been added back to encapsulate the web browser functionality,
allow the nav drawer items to be launched and enable other fixes.
2013-09-05 23:43:44 +00:00
409d823dec propagate from branch 'i2p.android.base' (head 673745663d325fbda1918746084110decd77634e)
to branch 'i2p.android.base.fragments' (head 9a651bea924de2d108bd743e4cb20958d281a4ff)
2013-09-05 23:02:46 +00:00
0208e58a3b Fixed previous commit
Refreshing is now disabled in PeersFragment and WebFragment, but both of them
will eventually be removed.
2013-09-05 12:25:32 +00:00
6d18e50a3a Removed start/stop and reload buttons from main menu 2013-09-05 11:48:08 +00:00
c748610280 Added PeersActivity; moved peers link to nav drawer for now 2013-09-05 11:43:41 +00:00
7768c624f9 New I2PFragmentBase so Fragments can access RouterContext, migration changes
All page logic is in the Fragments. Activities don't need the convenience
methods.
2013-09-05 06:07:34 +00:00
72ed6bd170 Migrated nav drawer code into I2PActivityBase 2013-09-05 03:54:09 +00:00
3d5b9938fd Migrated I2PFragmentBase back to I2PActivityBase
zzz and sponge pointed out that the router needs to be managed by whatever
Activity happens to be active (in case an automatic start is required). This
commit reverses the initial migration of I2PActivityBase to a Fragment (code is
broken now).
2013-09-05 03:39:15 +00:00
03b5927447 Updated refresh icon, removed old icons 2013-08-28 06:47:01 +00:00
b7a6b4acd5 Manifest change missing from previous commit 2013-08-28 06:02:51 +00:00
e27e1e55bd Implemented an Addressbook picker for Destination in tunnel wizard 2013-08-28 05:26:24 +00:00
0b0511dbce Added verification of Destination in tunnel wizard 2013-08-28 03:14:30 +00:00
02c370a04a Added input validation support to SingleTextFieldPage 2013-08-28 02:48:05 +00:00
4810c9e990 Implemented starting and stopping tunnels 2013-08-28 00:42:29 +00:00
cc801de79d More indent changes 2013-08-27 23:58:58 +00:00
93fd4f7e0c Fixed indent 2013-08-27 23:56:45 +00:00
abd9908a21 Moved tunnel list help handler to correct class, removed unused imports 2013-08-27 23:54:34 +00:00
52d278134c Added help link to tunnel list overflow menu 2013-08-27 23:51:57 +00:00
c60e4f6b3e Set up action buttons for starting and stopping tunnels 2013-08-27 23:47:18 +00:00
5b7452ff90 Fixed two-pane tunnel deletion 2013-08-27 11:12:47 +00:00
014fc9b79b Added edit and delete actions to tunnel detail fragment, implemented deletion 2013-08-27 10:11:01 +00:00
9ca0ce3192 Moved TunnelWizardModel parameter descriptions into resources 2013-08-27 04:01:20 +00:00
99d720c685 Implemented tunnel creation backend
The methods in TunnelConfig and TunnelUtil are taken almost verbatim from
IndexBean (modified to be static in TunnelUtil). The tunnel creation wizard
works now, and the new tunnel will start if auto start is enabled.
2013-08-27 03:53:07 +00:00
c46ba4f24b Moved tunnel wizard model key strings into resource, dismiss submit dialog 2013-08-27 03:36:27 +00:00
522178598b Pass tunnel wizard data back to TunnelListFragment 2013-08-26 11:50:12 +00:00
5b6658531e Readability, documentation of TunnelWizardModel 2013-08-26 08:59:36 +00:00
333455b738 Bugfixes 2013-08-26 08:21:05 +00:00
5ebdeedb2b Another required parameter 2013-08-26 06:44:13 +00:00
0af8d2145f Set more tunnel parameters as required 2013-08-26 04:26:55 +00:00
5ac6d51289 Added support to SingleTextFieldPage for setting a default string 2013-08-26 04:18:02 +00:00
238ab91092 Implement full tunnel wizard model 2013-08-26 02:32:44 +00:00
0af8ed90f7 Added NotEqual and EqualAny, removed show-on-null assumption 2013-08-26 02:31:08 +00:00
c761287a8a Added support for complex branching with Conditionals 2013-08-26 01:23:00 +00:00
a77674603a Restore checked status 2013-08-26 01:07:21 +00:00
9a2382d886 PagerAdapter -> MyPagerAdapter 2013-08-26 01:04:03 +00:00
0d58d81bce Added OnClickListener to tunnel wizard dialog, does nothing yet 2013-08-25 13:15:28 +00:00
1e4300cb83 Stretch or shrink the StepPagerStrip to fit the width by default
This is better for smaller devices. Larger devices will be customized later.
2013-08-25 13:14:20 +00:00
28b0950990 Added SimpleTextFieldPages for the main tunnel parameters needed 2013-08-25 13:13:10 +00:00
536102658a TextField* -> SingleTextField* for accuracy 2013-08-25 12:49:46 +00:00
6754f6b5b1 Tweaks to text field page, added a single boolean page for auto start option 2013-08-25 06:26:12 +00:00
06d1903184 Dummy tunnel creation wizard - most structure in place, does nothing 2013-08-25 01:39:37 +00:00
4d13e8adfd Added a TextFieldPage to WizardPager 2013-08-25 01:12:59 +00:00
145b249394 Added WizardPager code from https://github.com/romannurik/android-wizardpager 2013-08-25 01:06:06 +00:00
a00c08bb49 Moved I2PTunnel code into separate package 2013-08-24 06:26:51 +00:00
449627be3d Started expansion of I2PTunnel detail Fragment
Most of the getters in TunnelEntry are almost verbatim from
net.i2p.i2ptunnel.web.IndexBean and net.i2p.i2ptunnel.web.EditBean
2013-08-24 04:30:55 +00:00
27be4aacb2 Adjusted weighting of two-pane layout, set AddressbookActivity to use it 2013-08-22 22:12:41 +00:00
f4f849182d Added detail page for tunnels and a two-pane layout for large screens
There are a lot of changes here:
- The main_content FrameLayout is now main_fragment (more logical name).
- TunnelEntry now stores a Context instead of a TunnelEntryLoader (so
  it can be instantiated inside the detail Fragment).
- The activity_navdrawer layout is now an alias to a one-pane or two-pane
  layout depending on screen size.
- Subclasses of I2PActivityBase can now override canUseTwoPanes() to enable
  and use the two-pane layout (for devices that support it).
2013-08-22 14:52:00 +00:00
32d8a7112c Added missing I2PTunnel status stars 2013-08-22 14:37:45 +00:00
4dbfff292b Missing AndroidManifest update, prep code for help content 2013-08-22 01:48:50 +00:00
228d27d82b Moved licenses and release notes into menu of new HelpActivity 2013-08-22 01:46:42 +00:00
9d0858ad17 Override method for when nav drawer opens/closes to hide/show action bar items 2013-08-22 01:05:55 +00:00
480dacb7f2 Fixed warnings in SeekBarPreferences 2013-08-21 11:39:42 +00:00
84edc743f5 Fixed SeekBarPreferences to check resource strings 2013-08-21 11:34:31 +00:00
b7dfc45b1e Prep for I2PTunnel details fragment 2013-08-21 11:03:39 +00:00
bd0ebc8852 Removed Addressbook from menu (it is in the nav drawer) 2013-08-21 10:14:35 +00:00
8c0e2228a5 Communicate between Fragments via the container Activity, not directly 2013-08-21 09:57:14 +00:00
4dafc3e5af Import VersionDialog, not just the listener 2013-08-21 09:54:08 +00:00
291294435a Removed unused imports 2013-08-21 09:53:13 +00:00
99588c3cb1 Filled tunnel row layout with tunnel data 2013-08-19 00:15:00 +00:00
f7904e0c7e Added TunnelEntry to format TunnelController data, expanded tunnel row layout 2013-08-18 14:27:17 +00:00
ae2fa4dce7 Fill I2PTunnel list with a Loader
Until changes to the list of TunnelControllers can be monitored, the Loader
refreshes the view every 10 seconds.
2013-08-18 12:46:13 +00:00
bdbc777a52 Added TunnelControllerAdapter, filled tunnel lists with names
Router must be started and client tunnels built before loading the I2PTunnel
Activity, or it hangs when switching tabs.
2013-08-18 00:13:05 +00:00
320e8d5153 Added client and server tabs 2013-08-17 11:53:12 +00:00
c53b98d2b9 Changed LicenseFragment to a ListFragment 2013-08-17 11:21:54 +00:00
e1236d2824 Replaced list header with Toast in Addressbook 2013-08-17 09:37:29 +00:00
d7ac916eeb Changed AddressbookFragment to a ListFragment
Previous commit was not broken, a clean build fixed the problem.
2013-08-17 05:41:42 +00:00
5b9203f77d File framework for I2PTunnel interface
Broken: cannot find net.i2p.i2ptunnel.I2PTunnel
(but it can when launching the router)
2013-08-16 21:19:08 +00:00
9757d6e396 Added missing search icon for action bar 2013-08-16 21:17:21 +00:00
c2ff90af91 Fixed activity parents 2013-08-14 05:12:31 +00:00
c1e8719d0e Fixed bug in manifests 2013-08-14 04:46:04 +00:00
56198bf771 Moved logs and error logs into nav drawer 2013-08-14 04:40:19 +00:00
73286f43f6 Moved licenses button into nav drawer
Temporary; will eventually be in an about menu in settings
2013-08-14 04:22:58 +00:00
cd3157038c Fragmented LicenseActivity, turned TextResourceFragment into a DialogFragment 2013-08-14 04:11:37 +00:00
9359c7a726 Implemented Addressbook filtering via SearchView in action bar 2013-08-14 01:47:10 +00:00
058f41ec73 Set up SearchView in Addressbook action bar in preparation for searching
The navigation drawer has been (mostly) migrated to link to Activities instead
of Fragments. Only Activities can be searched via the inbuild Android search
function, which uses Intents.
2013-08-13 13:54:39 +00:00
e4c9095626 merge of '73d2724826ecdabe3e124af9e485c44fe7188117'
and '977f74485a75e34e7488c13e06849f6dfb5d2d2a'
2013-08-12 01:44:37 +00:00
dd90ea9874 Put full strings in android:dialogMessage for SeekBarPreference
The SeekBarPreference class needs fixing to follow resource references.
2013-08-12 01:44:31 +00:00
zzz
53c7770e4e - Handle 4-digit core version
- Set API in version string to min version
2013-08-11 14:50:01 +00:00
21274f0335 Added es translation 2013-08-11 13:58:21 +00:00
4ccf3e713d tr-rTR -> tr to support other regions as well 2013-08-11 13:58:05 +00:00
2ef4d71cdb Renamed navigation drawer layout 2013-08-10 10:20:31 +00:00
c2bc999847 Turned navigation drawer code into base activity to subclass 2013-08-10 10:17:41 +00:00
d3f37a21a5 Show navigation drawer on first run 2013-08-10 09:16:19 +00:00
658d2a68e2 Removed unused imports 2013-08-10 05:43:41 +00:00
490148cb5b Migrated old Dialog to DialogFragment 2013-08-10 05:38:28 +00:00
430d56b681 Set choice mode for navigation drawer
This should have enabled the current navigation drawer entry to be highlighted
by the call to setItemChecked() in selectItem(), but it still doesn't work.
2013-08-10 03:43:34 +00:00
405bb3317e Show some menu items in action bar 2013-08-10 03:40:13 +00:00
bbb41c9c54 Use dp instead of px, added content description for logo 2013-08-10 03:29:58 +00:00
5c9c438e28 Moved Addressbook button to navigation drawer 2013-08-10 01:40:22 +00:00
27239cf09d Renamed menu1.xml 2013-08-10 01:26:12 +00:00
b853c3af39 Only call onBackPressed for I2PFragmentBase subclasses 2013-08-10 01:20:59 +00:00
48f84f1a1b Added tr_TR translations 2013-08-10 01:19:45 +00:00
eb4ae2c66d Set minimum percentage, add language code mapping for tr_TR 2013-08-10 01:06:37 +00:00
17be8fb3f7 Load WebFragment properly from AddressbookFragment 2013-08-10 00:50:10 +00:00
bf5accb121 Converted AddressbookActivity to Fragment 2013-08-10 00:44:55 +00:00
4749e470b5 Fixed static reference 2013-08-09 23:35:32 +00:00
0553815777 Removed unused imports 2013-08-09 23:30:58 +00:00
57d81fb14d Migrated home buttons to use Fragment transactions 2013-08-09 23:30:37 +00:00
ee97af6e4f Fix labels in navigation drawer 2013-08-09 12:31:45 +00:00
6397a93cac Enable app icon for navigation drawer opening 2013-08-09 11:59:16 +00:00
03465185f9 Moved Fragments to net.i2p.android.router.fragment
Side-effect: some constant strings are now public
2013-08-09 11:52:33 +00:00
ddd9a195e6 Removed "I2P Home" from action bar (linked in navigation drawer) 2013-08-09 11:14:11 +00:00
664985461a Initial migration to navigation drawer and Fragment
- Migrated I2PActivityBase and subclasses to Fragment
- Added new MainActivity with navigation drawer to handle Fragments
- Added MainFragment to navigation drawer

Code compiles, installs and runs. Known bugs created:
- Some buttons now fail (can't use an Intent with a Fragment)
  -> Migrate usage of Intents to Fragment transactions
- New install/upgrade dialogs are commented out
  -> Migrate old Dialogs to DialogFragments
2013-08-09 11:11:37 +00:00
6d340dc056 Added Transifex config 2013-08-09 06:22:47 +00:00
f312b7c6f1 Extracted more strings 2013-08-09 03:24:15 +00:00
a42bd73de3 Comment out add button in AddressbookActivity 2013-08-08 14:24:59 +00:00
4424392bdc Comment out add button until it does something 2013-08-08 14:17:11 +00:00
bfe71213f8 Extracted more strings 2013-08-08 14:07:34 +00:00
cd2a12c8ed Use dp instead of px, removed invalid property (for LinearLayout) 2013-08-08 13:45:50 +00:00
4ca2ed756f Updated README.txt 2013-08-08 13:30:54 +00:00
a4abfd8fb8 Updated support library path to match README.txt 2013-08-08 13:30:41 +00:00
9d754c29ae Moved ic_content_new.png to proper folder 2013-08-08 13:05:17 +00:00
0101e63bce Updated .mtn-ignore 2013-08-08 03:33:40 +00:00
75fe8bfbe0 Removed another old import 2013-08-08 03:23:16 +00:00
806f6edbf1 Removed old import 2013-08-08 03:07:16 +00:00
767ff4f3d2 Merged methods 2013-08-08 02:55:52 +00:00
07fafb03b6 Added ActionBar to Addressbook, placeholder add action 2013-08-08 02:52:02 +00:00
e98f86b29a Updated .mtn-ignore 2013-08-08 02:33:07 +00:00
18bc4f141d Setup for ActionBar using appcompat support library
The path in project.properties will require local overriding. I tried directly
referencing the SDK with ${sdk.dir} but the build fails with an absolute path
to a library.
2013-08-07 13:07:49 +00:00
a3792bad7a Set target SDK to 18 2013-08-07 12:37:34 +00:00
745bd3fa94 Set target SDK to 18 2013-08-07 12:00:15 +00:00
97692a4635 Use color style instead of explicit color 2013-08-07 03:35:06 +00:00
3fe7575dab Removed FrameLayout 2013-08-06 05:41:23 +00:00
a7fc5090f3 Simplified settings layout, pulled strings into resource file 2013-08-05 14:41:08 +00:00
6154f64120 Set text resource color to stop color-change on touch 2013-08-05 12:52:13 +00:00
0e5ca23732 Fixed bug in main.xml 2013-08-04 04:34:17 +00:00
c47e7dab31 Added Eclipse project files
To satisfy dependencies, import the following other projects from i2p.i2p into
the same Eclipse workspace as i2p.android.base:
i2p_sdk       - core/java/
i2p_router    - router/java/
i2ptunnel     - apps/i2ptunnel/java/
BOB           - apps/BOB/
addressbook   - apps/addressbook/
jetty         - apps/jetty/
ministreaming - apps/ministreaming/java/
2013-08-04 04:33:56 +00:00
zzz
472fa6d49e - Adjust default configs, esp. ones on the settings page
- Update release notes
- Lower log levels
- Spelling fixes on settings page
2013-07-30 19:52:25 +00:00
60ece9d4d2 fix honeycomb notification annoyance 2012-12-14 02:07:22 +00:00
afd656c6b4 Fixes to peers webviewer 2012-10-04 16:46:03 +00:00
78e250a207 Small stats cleanup 2012-09-20 02:15:32 +00:00
134db2ecd3 Allow _fast_ quit v.s. graceful when user hits stop and then back button. 2012-09-11 13:10:11 +00:00
53caad9f2a Fix state recognition on restart. 2012-09-11 12:44:00 +00:00
742df967e2 Clean up poorly formed code (lint), fix close on rotate. 2012-09-11 09:14:46 +00:00
5d0c5c30eb Fix stale notification icon + refactoring 2012-09-11 06:32:53 +00:00
cb9924a0bf (Security fix) Fully kill the app and remove it from memory if not running. 2012-09-11 02:32:44 +00:00
3ceed9a6b3 Remove checks for properties, as-per zzz 2012-09-10 21:14:47 +00:00
c3d95a608d fix numaric typo 2012-09-06 13:00:31 +00:00
1b004a628e Fix bad router config for ports. This really belongs in the core... 2012-09-05 06:09:03 +00:00
b080bd387a If no participating tunnles, blank that status line out. 2012-09-04 12:19:24 +00:00
7a429674a7 Add missing colon 2012-09-04 06:52:12 +00:00
45a1511cab Add 10pixel border, adjust scrollbars 2012-09-04 06:46:28 +00:00
6c7be97ed5 FatCowIcons license was not copied from i2p.i2p, so I added it to custom_rules.xml
(for copying on build) and changed LicenseActivity to show it.
2012-09-03 22:58:10 +00:00
3244509cab Added icons to the UI. Used fatcow icons since the license is allready in place.
Screenshots could be found at: http://meeh.i2p/android/ui/2/
2012-09-03 22:19:08 +00:00
43a20d18c5 last adjustment to i2ptunnel config 2012-08-31 13:57:26 +00:00
e2332543ec Fix kytv's irc server settings, oops 2012-08-31 04:26:05 +00:00
4d68da45b4 Seperate out kytv's irc server 2012-08-31 04:17:24 +00:00
084ed85467 no more bouncy castle, wrapper.log fix 2012-08-28 13:17:46 +00:00
1d060fd419 Revert UPnP now that it was fixed. 2012-08-18 00:00:03 +00:00
a95ca82a3e Make service foreground, so droid does not stop us 2012-08-17 22:42:00 +00:00
c13101d535 More sensable defaults, especially dangerous 1 hop tunnels. 2012-08-13 00:07:15 +00:00
7dc7697c14 fix mysterious file name, force routerjars 2012-08-12 22:50:39 +00:00
91fb0a2248 Adding res/menu/activity_addressbook_settings.xml 2012-08-12 19:40:32 +00:00
2663cc7d57 Forgot a resource file. 2012-08-12 18:48:52 +00:00
f9fce317d3 Added support for ndk building in osx. (Hope i did't breake it.. worked on osx 10.8 / ubuntu 12.04)
Also did some changes in AddressbookSettingsActivity; changed the way subscriptions.txt is readed and removed tabs. also changed some handlings in save function.
2012-08-12 16:29:25 +00:00
f87a3eb03c Cleaned up a bug I made making it unavailable on ubntu and most surely other linux distros.
I've think I have fixed it, but it would be perfect if someone with good shell skills could check.
2012-08-12 14:41:20 +00:00
zzz
36a0f2c678 - Enable SSL reseed
- Update README.txt and release notes
- Add irc.killyourtv.i2p to IRC list
- Use new buildI2PTunnelJar target
- LogWriter cleanup
2012-08-12 11:25:06 +00:00
f8fe3f082a Added support for building jni in osx. Also forgot to add new source files from last commit. 2012-08-12 04:02:24 +00:00
6e130185de Added AddressbookSettingsActivity, and a link via settings. It's now possible to update subscriptions.txt on android. 2012-08-12 03:55:13 +00:00
006fc1dc51 Moving i2plogo to top and fixed a typo. 2012-08-11 21:05:21 +00:00
87836ddab6 Some UI changes to the main activity.
* Rearanged views
* Bigger buttons
* Removed wallpaper
* Added topic labels
2012-08-11 20:49:12 +00:00
ff7154b525 oops, forgot to add arrays.xml 2012-08-11 15:59:11 +00:00
7a829236b9 Add data usage stat 2012-08-08 03:31:41 +00:00
d3edd31155 test commit 2012-08-04 12:57:08 +00:00
455726f05a merge of '28e40eada54b4ffaffbdedb720514e9c75bde890'
and 'ed5a9580c190b1f53ebc6c46fe936b6c80114779'
2012-08-03 03:55:49 +00:00
5dc9d729f4 Fix buildnumber js, add more settings 2012-08-03 03:53:20 +00:00
6d42b93de4 merge of 'a6013429f41dd5ea107ee5e56da100592f7ede0c'
and 'eddaa1f2aaa94d303db9952dc8a04e7f10a19bf3'
2012-08-03 02:38:24 +00:00
39b54c41ab Remove duplicate Debug, move wrapper.log delete to a better place. 2012-08-03 02:37:40 +00:00
f8920298ee merge of 'b8271f21729bb5732b5383ee78febb68bde639af'
and 'c300165977b04a83f75252de61018f9122d0b2fc'
2012-08-03 01:08:33 +00:00
cc3b37c4c0 change install location to auto 2012-08-03 01:08:21 +00:00
0cdd5a5d88 merge of '382962c8f01043a3d3b75c95bf3d469b5aabc799'
and 'bc7602f413292ff3e11f3c9dbeb513075f10af14'
2012-08-03 00:58:00 +00:00
b61bc8f5ef move manifest files, change install location to auto, additional ant file tweaks 2012-08-03 00:57:44 +00:00
2a6a2ef7a7 merge of '96f925faf1d190d7b7d71c043d3b73853cc7a9f7'
and 'a081d5b6c58932415d009872ca843b36587fc455'
2012-08-01 14:59:49 +00:00
245f69f2d3 Fix build problems for the routerjars libs stuff... Should build fine now. 2012-08-01 14:59:29 +00:00
4c43b6f5d5 merge of 'cd63013f274d56bce70efcc4b1f0004411f9013a'
and 'eea8516ab4cd7b29f403d17fff0272a38d3cba7c'
2012-08-01 13:37:50 +00:00
28230c914d finish sync 2012-08-01 13:36:30 +00:00
f7e1acdb68 merge of '6a29ded18e13ec9d52d9af1abc2cbc21d2cc80d0'
and '8b6ea99d1c37c57f25c94df8231ae4a6e765db8c'
2012-08-01 13:32:13 +00:00
995cd7f327 javascript all the buildnumber stuff, new target incrementBuild, use when i2p.i2p source has not changed, but android source has changed. 2012-08-01 13:29:14 +00:00
zzz
1e024c22da fixup after merge 2012-07-31 23:11:22 +00:00
zzz
4e853a753f merge of '099d95534fe893da4acef3a0b5ab0ea8d74b2d79'
and 'aec2af21d2c3fe9b04ec51cb63fa8ef1188a3eb6'
2012-07-31 23:07:18 +00:00
01547e9a20 Add missing file 2012-07-31 20:01:59 +00:00
zzz
09b2af14fd merge of '9bda005612c09e3581b62178a01594526384c36b'
and 'f5cf8336fa20e64d9ff7dc28776621fb88ccef5c'
2012-07-31 19:52:23 +00:00
f5d06470e4 incrementBuild target, be sure to execute it manually from ant to increment build number 2012-07-31 19:42:49 +00:00
zzz
abe20c95d0 - Enable NTP based on SDK version
- Disable SSL reseed (temp until merge)
- Update release notes
- Restrict addressbook to only hosts.txt file
2012-07-30 21:59:15 +00:00
c9abfa80f0 Make SeekBar away from edges and away from value view 2012-07-29 21:36:16 +00:00
f34ef46dbf Make SeekBar width expand in a way that actually makes sense for the value range 2012-07-29 21:18:16 +00:00
0c30296888 Huge refactor, fixes, settings, put jbigi.so back in too. 2012-07-28 00:34:05 +00:00
3fd373ad8c less transparent icons, they were too dark, and difficult to see 2012-07-25 14:03:15 +00:00
41091dce25 BOB 2012-07-24 19:21:17 +00:00
0fbaeb0ea4 Don't ask for signing passphrase on the lib build 2012-07-24 05:59:45 +00:00
19791a5965 builds fine now 2012-07-24 05:25:49 +00:00
9d4c0aa839 Reorganize router to own sub-project to avoid build errors 2012-07-24 05:16:21 +00:00
0b12a952cb update README.txt 2012-07-23 23:47:16 +00:00
a95aa6e89b Janitorial work, imports and some warnings 2012-07-23 09:33:42 +00:00
f13c772509 install certificates 2012-07-22 02:17:04 +00:00
0f28c4d807 archive certificates 2012-07-21 19:54:08 +00:00
a649d434c7 Finish fixing ant issues, needs work yet. 2012-07-15 08:42:47 +00:00
23c5710d42 Move to newer ASDK and ant, does not compile 2012-06-30 16:31:56 +00:00
zzz
52a60b37e2 handle core versions without the 3rd digit 2012-06-29 12:43:09 +00:00
zzz
adb5c56f26 disable upnp again 2011-07-10 13:45:25 +00:00
zzz
177ac2e3a1 - Addressbook message tweak
- Tweak log levels
2011-07-05 13:07:03 +00:00
zzz
1219725e6a - Notification icon rotations
- Clean up debug text on main screen
- Move most logging from System.err.println to Util
- Stub out HTTP auth handler
- Don't restart Peers page on orientation change
- Add inbound/outbound arrows, not loaded yet
- Tweak log levels
2011-07-04 16:15:45 +00:00
zzz
db1932a908 android-0.8.7-4_b1-API8 2011-07-03 18:44:22 +00:00
zzz
9ff31a1872 fix spacing 2011-07-03 18:40:06 +00:00
zzz
0326783442 fix 2011-07-03 18:27:48 +00:00
zzz
e1b07f45fa - Delete dup license files
- More build cleanups
- Don't start router by default at first install
- Initial news cleanups
2011-07-03 18:25:16 +00:00
zzz
4d4eb2c48b - Build, versioning, and release note cleanups in preparation for release 2011-07-03 16:36:32 +00:00
zzz
6c48f042f9 - Hook up start and stop router menu items
- More updates to release notes
2011-07-03 14:28:00 +00:00
zzz
9869d08295 fix dumb NPE 2011-06-30 23:25:08 +00:00
zzz
0a5e6007da - Proxy error pages and CSS. Needs a little help still. 2011-06-30 23:10:08 +00:00
zzz
dbc6c22156 more progress dialog fixups 2011-06-30 19:36:56 +00:00
zzz
e62ce19a49 dialog cleanup 2011-06-30 18:35:45 +00:00
zzz
6c803935c7 - Top-level uri fixup part 3: Set base uri when loading from cache
- More debugging in WVC
2011-06-30 17:51:58 +00:00
zzz
a88edb8ea8 - Top-level uri fixup part 2: Remember base uri in CacheProvider;
do the rectification in CacheProvider too
2011-06-30 16:59:44 +00:00
zzz
57f3c95d72 - Doc updates
- Force hosts.txt naming service
2011-06-30 13:39:55 +00:00
zzz
3021c0bc91 top-level uri fixup part 1 2011-06-30 02:36:26 +00:00
zzz
293e51c175 - Reverse content URI back to I2P URI in WVC so we can load it
there instead of via the provider
- Several reload fixes
2011-06-30 01:38:17 +00:00
zzz
448d74e172 - Load clicked i2p sites via EepGetFetcher output stream and resource cache
- Toast on cache load
- Don't lose current page on orientation or keyboard hidden events
- Implement reload
- Quit is the new stop
2011-06-29 23:39:00 +00:00
zzz
92d47564dd - Handle resource URIs in the WV Client
- Switch from URI to Uri in the WV Client
- Canonicalize resource URIs if necessary
- Switch from HashMap to SharedPrefs in CacheProvider
- Use cache when going forward too
- CacheProvider remove old entries in onCreate()
- CacheProvider cleanup
- gc on router stop
- Add reload menu item
- Don't return to welcome page on activity restart
- Notification on client tunnels up/down
2011-06-29 20:05:57 +00:00
zzz
d51126cab4 - Add OutputStream variant of EepGetFetcher
- EepGet from the CacheProvider
2011-06-28 02:28:35 +00:00
zzz
752ac44930 - Use new eepget features to pass error page through 2011-06-28 00:05:03 +00:00
zzz
8833020455 - Use Uri for cache key instead of String
- Cache inserts and deletes to provider
- Still need to untangle the AppCache and CacheProvider
- Fix clean of class files before build
- Wrap main page in a ScrollView
2011-06-27 20:37:06 +00:00
zzz
e489c8d937 stub out a cache ContentProvider 2011-06-26 00:27:38 +00:00
zzz
9c4e661e53 - Implement LRU file cache with max size and file count
- Use cache for going back in webview...
  Sadly you can't go forward after going back
- Start brand new notification when starting or stopping router
- Add uncaught exception handler to remove notification but not sure if it works
2011-06-25 21:56:12 +00:00
zzz
a4215cf76e add intent filter 2011-06-24 21:44:35 +00:00
zzz
15afd309b3 license tweaks 2011-06-24 19:06:54 +00:00
zzz
a3aa64654f - Add Peers activity
- Save service state
- Start router after stopped by system
2011-06-24 17:39:26 +00:00
zzz
87cd67f498 - Add more IRC tunnels and more hosts
- LogActivity tweaks
- Welcome and release note tweaks
2011-06-24 13:23:33 +00:00
zzz
b5b2692cee log update handler 2011-06-24 04:21:19 +00:00
zzz
cadb6e8c1e - Set android log tag to "I2P"
- Log to console buffer too
- New log activity
- Debug status output when router not running
- More logging utility methods
2011-06-24 03:23:19 +00:00
zzz
1aa08d8341 show memory usage 2011-06-23 21:46:11 +00:00
zzz
628bae2497 fix version 2011-06-23 21:24:07 +00:00
zzz
4b5420f51a - Toast if no network
- Update status faster
- Update release notes
2011-06-23 21:05:33 +00:00
zzz
e86e69f437 - Move network waiter from a thread to the service handler
- Allow quitting while waiting
- Move connected detection to utility class
- Use connected info for displaying buttons
2011-06-23 19:39:01 +00:00
zzz
29b9ca6359 libjbigi.so for GMP 4.3.2 compiled with NDK r5b,
SDK Tools Version 11, SDK Platform-tools Version 5, API 8.
LGPLv3.
2011-06-23 18:43:29 +00:00
zzz
b337f0f651 convert license page to a ListActivity 2011-06-23 17:29:59 +00:00
zzz
8b41459c5d fix context dirs if started before the router 2011-06-23 17:12:19 +00:00
zzz
d4769c7c5a - Move new version detection from the service to the activity,
and from a system property to shared preferences
- Strip libjbigi.so
2011-06-23 16:58:56 +00:00
zzz
a04a224b4a - Add addressbook to menu
- Addressbook header not selectable
2011-06-22 21:48:21 +00:00
zzz
f1ea9dde51 - SusiDNS in 20 lines of code
- Show the toast
- First web page can be i2p
2011-06-22 21:04:51 +00:00
zzz
95fd006143 - Add background img
- Add missing resources
- More work on start/stop buttons and binding
2011-06-22 18:03:21 +00:00
zzz
eb04fb3335 add addressbook client 2011-06-22 14:47:19 +00:00
zzz
f045191c82 - Change to startActivity()
- Hide start/stop in menu as appropriate
- Prep for actually stopping and releasing service
- Stop service when stopping router
- Switch from singleTask to SingleTop
- Use SharedPrefs to remember whether to start router
2011-06-22 01:03:16 +00:00
zzz
097883c1ee - Delete old temp files on startup
- Catch loadUrl() exception
- Stub out settings and menus
- Enable double-tap to zoom in webview on Droid
2011-06-21 20:48:20 +00:00
zzz
d71ead3f53 Bump to API 8 for setBlockNetworkLoads()
More welcome file updates
2011-06-21 01:56:01 +00:00
zzz
77180cea17 - Fix crash on screen rotation
- Handle cancels better
- Start clients faster
2011-06-21 00:59:25 +00:00
zzz
0aa325ada8 - Add toast for some errors
- Fix eepsite loads by adding xml header
- Use loadDataWithBaseURL() but block network loads, requires API 8
- Turn zoom controls on for local pages too
2011-06-20 22:08:14 +00:00
zzz
ae8cadde95 - Support eepsites in web viewer
- Async task for web/eep loads
- Progress dialog for web/eep loads
- Cancel loads with back button
2011-06-20 20:23:46 +00:00
zzz
14464772f9 - Add browser activity
- Add welcome page
- Add EepGetFetcher app
- Add warnings
2011-06-20 14:16:29 +00:00
zzz
5305b39ee4 - More release notes
- Add the rest of the licenses
2011-06-19 20:25:13 +00:00
zzz
8e2ec53e94 - Tunnels 1+1 hops for now
- Split out WebViewClient to own class
- Clean up status a little
- Check for new install or new version at startup
- Popup dialog on new install or version
- Only merge config files on new version
- Add release notes and licenses screens
2011-06-19 17:37:24 +00:00
zzz
e80dcee65a back to shared clients 2011-06-18 19:40:26 +00:00
zzz
a2ae1ccab2 - Build script fixups for setting i2p source location
- Don't require GMP source to build
- Hook new router final shutdown hook, tweak state machine
  to not declare router done until final shutdown
2011-06-18 17:05:18 +00:00
zzz
05cdb11c55 - Add status to main page in the Handler
- Convert service status bar updater from a thread to a Handler
- Clean up status bar
- Null out router context on shutdown
- Switch back to shared clients
2011-06-17 22:05:20 +00:00
zzz
3a7f4331f0 - Enable UPnP
- Increase max NTCP connections
- Delete old wrapper.log at startup
- Spoof network status on emulator
- Increase client start delay
- Disable shared clients
- Stop LogWriter from starting a new App context at shutdown
- LogWriter tweaks
- Logging tweaks
2011-06-17 20:15:26 +00:00
zzz
2ee5d5f02f - Really change to SDK 7
- Start and stop buttons
- Handler for screen updates
- Make service not sticky
- Log tweaks
- Fix version script
2011-06-12 21:49:36 +00:00
zzz
cf5454d43e rcvr tweaks 2011-06-12 18:40:29 +00:00
zzz
e94c332ed6 - Stop router if network lost
- Only bind to service briefly from receiver to
  prevent shutdown hangs
2011-06-12 18:29:27 +00:00
zzz
735da1408b - Hook in news fetcher
- Move temp dir setting from config to code
- Stub out methods to stop the router
2011-06-12 16:53:32 +00:00
zzz
0e6cecce7b news fetcher app, not hooked in yet 2011-06-12 03:30:04 +00:00
zzz
0d97d92c64 - Beginnings of a local Binder
- Change min API to 7 (2.1), to make things a little easier.
  This covers 95% of active devices and older ones are likely
  too crappy to run I2P anyway.
2011-06-12 03:02:51 +00:00
zzz
3f62eded02 simple wait for network thread. still need to hook up the binder 2011-06-11 21:02:39 +00:00
zzz
a9a3fbd5da - Start clients directly (hard coded) instead of using clients.config
and LoadClientAppsJob, due to ClassLoader issues and the need to
  register shutdown hooks anyway.
- Status bar tweaks
- Fix NPE when stopping
- Instantiate broadcast receiver
- apk config has preference over installed config for now
2011-06-11 20:08:53 +00:00
zzz
6597847682 - i2ptunnel link fix
- Set class loader, although that causes other problems
- Fix temp dir for now, but needs to be set in app not in config file
2011-06-10 21:57:46 +00:00
zzz
8fb166b61b - Add news button, news page, initialNews.xml
- Add clients.config, i2ptunnel.config, hosts.txt, i2ptunnel.jar,
  streaiming.jar, ministreaming.jar
  Clients won't load yet, have to fight the class loader.
- More BroadcastReceiver work (still not hooked in)
- enums
2011-06-10 18:12:24 +00:00
zzz
7cc1e37cc2 - Switch to GMP 5.0.2
- Beginnings of a BroadcastReceiver
- ant target for signing key
- Status thread
- Status in status bar for now
2011-06-10 03:09:35 +00:00
zzz
84419904ad update paths in scripts and readme 2011-06-07 14:45:02 +00:00
zzz
ac30407eb2 Start an android-only branch without any code from i2p.i2p.
Next step: Update the scripts and docs to point to
../i2p.i2p/ for everything.
2011-06-07 14:00:36 +00:00
zzz
95189c8f53 Android:
- Move the classes around
  - Split into Activity and Service
  - Add status bar notification
  - More config changes
2011-06-06 13:47:47 +00:00
zzz
7e84451ac3 Android:
- Import the main_rules file and remove the copied rules
  - Set the version code and name in the apk badging
  - Build target is 8 to allow SD install, MIN-SDK is still 3
  - Fix NPE on new install
  - Remove some debug code from NBigI
2011-06-05 22:38:35 +00:00
15b9615a1c Debian: update path of installed javadocs 2011-06-05 20:02:48 +00:00
4dc9cfb457 Debian: re-work patch to compensate for recent runplain.sh & wrapper.config changes 2011-06-05 20:02:13 +00:00
1250617d6c Make runplain.sh even more shell agnostic 2011-06-05 19:54:21 +00:00
ca5f35aea9 merge of '7f219c63dd48ba4ae26ad87603df4cb41ada2c59'
and 'afa8f9152e731dd11cd6a3649d45caaeb65b1b82'
2011-06-05 15:03:05 +00:00
3dfa982b39 Missing swedish translation and fix of html tags by digitalmannen 2011-06-05 15:02:20 +00:00
zzz
b2a5a94ce0 -18 2011-06-05 14:01:12 +00:00
zzz
d834c8063c merge of '90dce8fafc543f94a2aefe704bf4b3e63b24eab9'
and '9d726cbaf7d1591c47b4dd7e6aed864d2c09e25d'
2011-06-05 13:58:14 +00:00
zzz
d28f4bd24b * JBigI:
- Replace old non-PIC 62-bit linux libs (GMP 4.1.4 built in 2005)
        with PIC libs built with GMP 5.0.2. License is LGPLv3.
        Built by sponge with GCC 4.4.4, downloaded from
        http://sponge.i2p/files/jbigi/gmp-5.0.2/
        For 64-bit processors, both performance testing and
        the GMP changelog led us to use 5.0.2 for both the 32- and 64-bit versions,
        even though the files are twice as big.
        See http://zzz.i2p/topics/306 for discussion and test results.
        libjbigi-linux-athlon64.so was a 64 bit file; by the new naming standard
        supported by NativeBigInteger, it is now a 32-bit file and the
        64-bit one is libjbigi-linux-athlon64_64.so.
        All new 64-bit libs will have _64 appended.
      - Update build docs
2011-06-05 13:52:43 +00:00
zzz
48f4c7286d - Remove libjbigi-windows-athlon64.dll which was a duplicate of libjbigi-windows-athlon.dll;
NBI now tries athlon as a fallback for all 64-bit processors.
2011-06-05 13:31:26 +00:00
zzz
d9f80e9de6 GMP is not in core lib 2011-06-05 12:50:04 +00:00
zzz
d1e42233a8 * DSAEngine: Add code for alternate implementation using Java libs;
disabled by default. Add test code to verify identical results
                 and compare speed.
2011-06-05 12:40:59 +00:00
6110957921 Fix html tags in swedish translation 2011-06-05 11:59:38 +00:00
zzz
d308d7da97 remove unnecessary zeroing code, javadoc 2011-06-05 11:19:32 +00:00
zzz
4d34078678 * Data: Remove duplicate signature verification code
in RouterInfo and LeaseSet
2011-06-05 11:18:35 +00:00
zzz
8d42ebc2f0 * Console: Tag stat descriptions at declaration rather than in Strings.java 2011-06-05 11:16:57 +00:00
zzz
87cad7eaee * JBigI: Replace old non-PIC 32-bit linux libs (GMP 4.1.3 built in 2004)
with PIC libs built with GMP 4.3.2. License is LGPLv3.
             Built by sponge with GCC 4.4.4, downloaded from
             http://sponge.i2p/files/jbigi/gmp-4.3.2/
             The 4.3.2 files are half the size of those built with GMP 5.0.2, and there was
             little or no performance difference between the two versions for 32 bit processors.
             See http://zzz.i2p/topics/306 for discussion and test results.
2011-06-05 11:06:56 +00:00
b1f1c28c5c Swedish translations (thanks 123hund123, hottuna and digitalmannen) 2011-06-05 10:15:05 +00:00
b612e925df merge of 'b87fbef6393383ccfe6d24286dbbf9ffc79fdd29'
and 'c0bbd3c3725889c45887d4cdce900908d8918df8'
2011-06-05 08:51:48 +00:00
af629d2442 minor change to i2psnark l10n es 'n pt 2011-06-05 08:48:58 +00:00
zzz
e232a641a3 android: fix gmp configure args 2011-06-05 02:09:12 +00:00
zzz
35495e4d5a Android:
- Add a version update script
  - Disable NTP
  - Disable external I2CP
2011-06-04 19:31:45 +00:00
zzz
5974160805 * Router:
- Add a lock for reading/writing the router.info file
      - Check our RouterInfo validity after reading and before saving,
        to catch fatal errors sooner
2011-06-04 12:05:48 +00:00
zzz
4e16ef35a2 * KeyGenerator: Restore old return type to not break ABI (thx kytv) 2011-06-04 12:04:18 +00:00
zzz
885d549e84 * NBigI: Recognize Android 2011-06-04 12:03:35 +00:00
zzz
173343e049 Android:
- More efficient build of i2p.jar and crypto.jar
  - More build fixes
  - Merge package configuration resource with configuration file on device if it exists
  - Add launcher icon, resized from installer/resources/eepsite.help/help/lib/itoopie.png
  - Start of a libjbigi build script
  - Increase min API to 3 so we can use JNI
2011-06-04 00:29:02 +00:00
zzz
c3bcb8d020 fix misspelled file causing build dependency problems 2011-06-03 13:20:50 +00:00
zzz
d7de8ae630 Android:
- Fix up build.xml to work with tools version 11
  - Get rid of dot at front of project name
  - README.txt updates
  - logger_config additions
2011-06-03 12:14:54 +00:00
d5f529819f merge of '6ad44c8ad61fa5a65207491cab744ddfa8f0f3ca'
and 'db7c4479731f94687d64bea76eafeb4c62e14f1a'
2011-06-03 01:31:31 +00:00
d2093444a6 update i2psnark pt 2011-06-02 21:34:50 +00:00
3f15c4324b update i2psnark one string in es and de 2011-06-02 20:32:49 +00:00
zzz
219d7fd8c3 fix ElGamalTest compile; fix jbigi.jar path to speed up the test 2011-06-02 20:29:15 +00:00
c5c6a9fa17 update routerconsole Deutsch 2011-06-02 20:23:36 +00:00
78779fe92f update Castillian 2011-06-02 19:36:53 +00:00
b37a64905b fix/merge 2011-06-02 19:07:38 +00:00
675ac79443 merge of '65af54c284a3e8def1740b26114d3ed42ccae172'
and 'd805aad2dab23264b9c386c8ffabea464fece871'
2011-06-02 19:02:29 +00:00
14ea9c2928 fix/merge 2011-06-02 19:02:12 +00:00
ec6084cd37 merge of '468d5271753b5b44fff6890ecd33d03b684d8e18'
and 'cd4b79fe5aae3f17a3def305c7a3494a8db5dc74'
2011-06-02 18:57:06 +00:00
b65cbb0f78 Remove txt file in BOB.jar as per zzz's request. 2011-06-02 18:53:45 +00:00
zzz
fe15db51d8 - Logging tweaks inspired by Android
- Disable reusing Deflater on Android
2011-06-02 18:29:06 +00:00
zzz
761ad38bcc * HMAC:
- Javadocs and cleanups
      - Use SimpleByteCache
      - Comments and speculation
2011-06-02 13:37:35 +00:00
zzz
2a5ed938bb update generateKeyPair() return type to make it easier 2011-06-02 13:34:26 +00:00
zzz
c5c4e3c7ce * ElGamalAESEngine: Fixups required after SessionKey enforcement
* SessionKey: Enforce data size and prevent reuse like the other SimpleDataStructures
2011-06-02 13:33:03 +00:00
zzz
94af6550fa HMAC256 is used by Syndie 2011-06-02 13:30:33 +00:00
zzz
c767644c8f typo 2011-06-02 13:29:27 +00:00
zzz
a3ee593d0b give up on a reseed host after 90% errors 2011-06-02 13:27:03 +00:00
zzz
733d6db56e one more illegal character 2011-06-02 13:25:23 +00:00
zzz
6d938a12f6 android build fixes 2011-06-02 13:24:47 +00:00
8a56531c90 Don't prefer IPv4 but add the option commented out to wrapper.config. Make the option configurable in runplain.sh 2011-06-01 14:42:18 +00:00
zzz
43332bb6d0 * Crypto:
- Use java.security.MessageDigest instead of bundled GNU SHA-256 code
        if available, which it should always be.
        5 to 20% faster on Oracle JVM; 40 to 60% on Harmony;
        5 to 15% on JamVM; 20x (!) on GIJ.
      - Use java.security.MessageDigest instead of bundled Bitzi SHA-1 code
        if available on non-Oracle JVMs, which it should always be.
        Not faster on Oracle JVM; 30 to 60% faster on Harmony;
        15 to 20% on JamVM; 10-15x (!) on GIJ.
2011-06-01 11:44:10 +00:00
5990dd5879 add description for debian-clean target 2011-06-01 10:24:07 +00:00
030a95cdd1 reference debianhowto 2011-06-01 09:54:32 +00:00
18d3536ffe ConfigClients stopClient stubbed out. 2011-06-01 03:59:12 +00:00
3b80f53b8e There is more than one way to peel a pineapple... 2011-06-01 02:49:14 +00:00
5912c60692 Remove the one little html file that ends up in BOB.jar. The file is NOT a javadoc file, it is a package file. Still, it is zapped. 2011-06-01 02:32:00 +00:00
f8dc8a298e Debian: refactor patch 2011-06-01 00:11:03 +00:00
a3dd538afb typo fix 2011-06-01 00:09:53 +00:00
a90b8aa03a Prefer IPv4 connections
In some distributions (such as Debian, for example) net.ipv6.bindv6only=1 is
set by default. In some configurations, networking in java applications will be
broken. Someone recently came into #i2p experiencing this very problem.

This change closes #464.
2011-06-01 00:04:23 +00:00
313ee79bae hide syndie from "all" target and disable syndie target 2011-05-31 23:32:27 +00:00
97f97448d5 Clean up debian options in build.xml 2011-05-31 23:29:06 +00:00
zzz
3677cadcca * jbigi: Add support for solaris 2011-05-31 20:21:51 +00:00
455b5529b4 jbigi: Add support for SunOS/Nexenta/Solaris to the build*.sh scripts 2011-05-31 19:37:29 +00:00
60204fef24 Debian: initscript: Don't spew warnings when chown'ing files that don't yet exist 2011-05-31 18:50:54 +00:00
45064ec37e libjcpuid for Solaris x86
Compiled using
gcc (GCC) 4.2.3 (Ubuntu 4.2.3-2nexenta7) on Nexenta 3.0.1
2011-05-31 18:20:32 +00:00
zzz
4ecacc7607 * HTTP Proxy: Don't send redirect for POST (thx kytv) 2011-05-31 15:57:39 +00:00
43ba27126c Debian: Refactor jcpuid & jbigi patches to deal with SunOS support 2011-05-31 11:32:07 +00:00
527c9ba5dd Add support to jbigi/jcpuid for Solaris/SunOS 2011-05-31 11:30:10 +00:00
zzz
d4bf2523a6 * I2CP:
- Append I2CP Version information to the Get/Set Date Messages,
        so that both the router and client are aware of the other side's version,
        and future protocol changes will be easier to implement.
        Previously, router version information was not available to the client,
        so when router and client were in different JVMs,
        old clients would work with new routers
        but new clients would not work with old routers.
        After this change, we can design future changes so that new clients
        will work with old routers.
        This is an enhancement to the old protocol version byte sent by the client,
        which we have never changed and probably never will.
      - Prevent a client from setting the router's clock
      - Javadocs
2011-05-30 16:31:09 +00:00
zzz
acb4bac5e6 * netDb: Don't refetch expiring router infos if we have enough 2011-05-30 16:29:33 +00:00
zzz
cbef38ac11 * i2psnark: Restrict swarm size for small torrents 2011-05-30 16:25:24 +00:00
f9ffab62f4 Debian: Refactor jcpuid patch
Changes made to patch b/c of  kFreeBSD changes to build.sh I recently checked
in.
2011-05-29 15:12:46 +00:00
656292e1b1 Debian: Since jetty-i2psnark.xml has been disabled, there are no xml files dumped to pkg-temp. 2011-05-28 21:36:17 +00:00
ed8a065da9 Debian: Rework patch to work with the updated runplain.sh 2011-05-28 20:21:45 +00:00
9834a36787 merge of '5b0e335af7a9ce35cb7e40cd550b7e65af923218'
and 'd25f86bdd190afae59745e22e4fd0c2d8911a8ac'
2011-05-28 20:17:09 +00:00
33b9a5c2ce Make runplain shell agnostic
Braces were put around variable names so that router will run in kFreeBSD.
runplain.sh should now be shell agnostic (it runs in dash. it even runs in
*posh*, a ridiculously picky shell).
2011-05-28 20:14:36 +00:00
zzz
1eb58a84df * i2psnark: Fix bug preventing Robert from connecting to snark (thx sponge) 2011-05-28 20:11:52 +00:00
c9c35a3e5a jcpuid: minor edits so that compilation will work with Debian kFreeBSD 2011-05-28 17:26:24 +00:00
e0dd52a4dc build.xml: Don't copy jetty-i2psnark.xml to pkg-temp 2011-05-28 12:52:23 +00:00
zzz
393d813d05 Don't re-append the query string to the redirect URL,
which caused eepget to repeatedly retry the new redirect
of an i2paddresshelper query by the HTTP proxy.

This was clearly non-compliant (the Location: header requires
an absolute URI including any query string).

This was part of the original redirect handling added by
jrandom to eepget back when it was in syndie;
appending that changelog just in case this hackery was
required by Freenet USKs, which I doubt.

Also, reset the redirect counter when retrying.

==============

	Revision: 62a8cac8565958d111d0a47a443c964918d2e3ef
	Parent:   277fe109ea4416f7d8a6dba6e09cd4f605a8ce1a
	Author:   jrandom@i2p.net
	Date:     10/22/2006 15:06:30
	Branch:   i2p.syndie

	Changelog: 
	    ...
	    - add support for HTTP 301 redirects to EepGet (so freenet USKs work as
	      intended)
2011-05-27 21:41:49 +00:00
0000e4f28d Debian: Ship custom router.config to disable updates via the I2P router. Updates, to keep with Debian policy, must be done via the package manager. 2011-05-27 17:43:05 +00:00
zzz
e3a3a99317 add cpuid 2011-05-27 16:18:38 +00:00
zzz
6a9f73bd61 quick jbigi test script 2011-05-27 16:12:10 +00:00
zzz
2c3be29016 * JBigI:
- Refactor to handle 64 bit libs and a list of fallback libs
      - Logging tweaks
      - Only check for one file name in library path
2011-05-27 15:04:40 +00:00
zzz
8eb10872b8 * CPUID:
- Recognize amd64 as x86
      - Only check for one file name in library path
      - Log tweaks
2011-05-27 15:02:03 +00:00
zzz
d5fd682985 * Console: Fix router.updateThroughProxy being set to false after saving
change on /configupdate when install dir is read-only.
               (ticket #466)
2011-05-27 14:58:57 +00:00
zzz
8f861f7ba2 javadoc 2011-05-27 14:57:36 +00:00
efe53c831d Debian: Since browser launch is disabled within the I2P codebase for the i2psvc user, removing patch to disable it 2011-05-27 13:35:36 +00:00
0dba0a1d6f typo fix 2011-05-27 09:45:42 +00:00
89c01696cc Debian: Remove cruft that remained in debian/rules from the times in which cpuid couldn't be build for i386. 2011-05-27 09:35:17 +00:00
164f060a40 Debian: Creating a new fourth package by splitting the i2p package in two
This commit splits the i2p package into a second package, i2p-router.
   * The new 'i2p-router' package does not depend on the java-wrapper nor jbigi.
     Jbigi is recommended. This package can be installed on the ports or 
     distributions that the java-wrapper is not available for.
   * The new 'i2p' package depends on i2p-router, libjbigi-jni, and the java-wrapper. 
     This package will add the i2psvc system user and the initscript. Existing
     users of the i2p package will have the i2p-router package pulled in
     automatically and for them there will be no usability changes.

 Executive summary: No functionality changes will take place for either those
		    that installed the i2p package in the past or those that
		    install the newly split i2p package. For them, "The Song
                    Remains the Same."
2011-05-27 09:33:20 +00:00
e347ee5880 Debian: debian/README.Debian updates to reflect packaging changes 2011-05-26 21:56:42 +00:00
a4ea70b33b Debian: Move scripts/ to doc/i2p/examples 2011-05-26 21:40:31 +00:00
4433a3db06 Debian: Install runplain.sh as /usr/bin/i2prouter-nowrapper 2011-05-26 21:38:50 +00:00
e019d3b8d7 Debian: create symlinks in doc/licenses that point to existing licenses in /usr/share/common-licenses 2011-05-26 21:33:05 +00:00
1f497e171a Debian: Add certificates directory to $I2P 2011-05-26 19:12:32 +00:00
cd8c954513 Debian: Drop junit from Build-Depends-Indep 2011-05-26 18:53:22 +00:00
d08d5ffd64 Debian: add debian/copyright to ant clean target 2011-05-26 18:51:36 +00:00
8744eab46d Debian: drop dynamically created copyright file 2011-05-26 18:46:41 +00:00
5d7e936aed Remove legacy standalone i2psnark from package 2011-05-26 15:49:43 +00:00
e786da2605 Remove information from debian/README.Debian that is no longer applicable 2011-05-26 14:45:10 +00:00
b6fab829cc Debian packaging fixes 2011-05-25 23:09:58 +00:00
zzz
150cb30339 minor NBI tweaks and comments 2011-05-25 22:13:18 +00:00
zzz
724d8de9ae call the 64 bit cpuid, even if we dont use it yet 2011-05-25 21:35:21 +00:00
zzz
ddcd8cbb10 prep for new 32 bit cpus 2011-05-25 21:23:40 +00:00
zzz
f5f4f14b7e Drop libjbigi-linux-k63.so and libjbigi-freebsd-k63.so that were identical
to k62 versions; add mapping in NativeBigInteger.
2011-05-25 21:14:16 +00:00
zzz
6616ccd3b4 cleanup in prep for more changes 2011-05-25 21:05:20 +00:00
075f89f43c Update jetty version number--we use version 5.1.15. 2011-05-25 18:11:15 +00:00
9a836ed072 merge of '0ab9435836f60e748b89344771eea555219e6262'
and '13180c845a0d2cce619be3b9b139295f2ff49ece'
2011-05-25 17:09:29 +00:00
zzz
552608744d * CPUID: If the 64 bit extract worked but the load failed, try 32 bit 2011-05-25 16:54:25 +00:00
2accbdcf05 Operation close #354 part one of ??: Make the router console's help pages valid html. We *LOVE* valid HTML. 2011-05-25 16:52:52 +00:00
ab17bd3150 Built using gcc (Debian 4.4.5-8) 4.4.5 in Debian Squeeze within clean chroot jails.
-fPIC and stripped.
2011-05-25 16:00:11 +00:00
zzz
d201a29d03 * HTTP Proxy: Address helper refactoring, address book add form 2011-05-25 13:52:18 +00:00
zzz
c4bbcc4617 * CPUID: Load 64-bit libcpuid if available 2011-05-25 13:48:45 +00:00
zzz
82a0ac16f1 increase min floodfills again 2011-05-25 13:36:17 +00:00
zzz
27b48034c5 b32 cleanups 2011-05-25 13:34:32 +00:00
641e71c141 close tags in eepsite help files 2011-05-24 23:16:15 +00:00
4fd8da8041 Fix errors that tests/scripts/checkxml.sh found 2011-05-24 22:33:28 +00:00
zzz
68dccdfe2f try to fix RrdGraph GIF exception 2011-05-23 23:24:54 +00:00
zzz
592361b1a4 * Console:
- Disable zh translation in graphs on windows due to font issues
      - Fix NPE at startup
      - Graph tweaks
2011-05-23 19:22:33 +00:00
zzz
6e4df8830a - Force news refetch after URL change 2011-05-23 19:19:07 +00:00
zzz
7ab95d0144 javadoc 2011-05-23 19:16:33 +00:00
4ea5622842 mbuild.sh fixups : add new jcpuid/mbuild.sh, edit jbigi/mbuild-all.sh -- pedantic naming 2011-05-23 04:52:29 +00:00
zzz
606300a042 * GeoIP: Read countries.txt in UTF-8 2011-05-22 18:36:08 +00:00
zzz
96cf598691 javadoc 2011-05-22 18:34:41 +00:00
zzz
6b923c7251 Fix build error that omitted local jetty patches from org.mortbay.jetty.jar;
affected 0.8.4 and 0.8.6 installers. Include jar in the updater for the next release.
        Thx KYTV.
2011-05-22 18:33:51 +00:00
zzz
18e57d19db doc update 2011-05-22 14:31:56 +00:00
45f3020924 mbuild.sh document and fixes, mbuild-all.sh add cpu types 2011-05-21 18:26:10 +00:00
zzz
d8a3cb0d58 change build script to GMP 4.3.2 2011-05-21 17:09:30 +00:00
b5dc9b6f5a Update geoip database and country list 2011-05-21 01:07:03 +00:00
zzz
38a6e6b212 restore old cpuid assembly for x64 2011-05-20 16:26:40 +00:00
zzz
627519e69c disable debug 2011-05-20 16:25:46 +00:00
zzz
2f2e0e539a history for props, -1 2011-05-20 14:23:31 +00:00
zzz
e42b78e177 propagate from branch 'i2p.i2p.zzz.naming' (head 9626e0df682c8d5f706d2c814158ba451f3ebeb5)
to branch 'i2p.i2p' (head a3969e6c9c4fd5bfd69cd716ce0df191ad2af634)
2011-05-20 14:12:07 +00:00
zzz
4b19801cdb try to prevent out-of-order logging at shutdown 2011-05-20 14:09:36 +00:00
zzz
3d76354cbb fixup after prop 2011-05-20 13:55:13 +00:00
zzz
e2c98ac134 propagate from branch 'i2p.i2p.zzz.jrobin159' (head 08df645290d8e156d88930ddaf71b3f3d8af419d)
to branch 'i2p.i2p' (head 69c9e6bd0c6894c335f7d9892aa28ac7d6389907)
2011-05-20 13:52:35 +00:00
zzz
d4fe76afee hide graph link in summary bar when disabled 2011-05-20 13:47:09 +00:00
zzz
3352c45517 - Rewrite cpuid.c so it builds with PIC (source only, binary not updated yet) 2011-05-20 13:25:19 +00:00
zzz
0e719b8eb0 fixup after prop 2011-05-20 13:17:04 +00:00
zzz
ff520b74dc propagate from branch 'i2p.i2p.libgmp' (head 41a57954f7e78e57f8eb5e30e8ebde7fd75b15dc)
to branch 'i2p.i2p' (head d174e772ebd4f3e3eac5c9b5abd7f736c2527eb2)
2011-05-20 13:13:26 +00:00
zzz
48bf618ae5 final 2011-05-20 12:49:29 +00:00
zzz
d6c1202e4b summary bar tweak 2011-05-20 12:48:58 +00:00
zzz
20452c9387 * Certificate: Fix creation bug; improve router cert generation 2011-05-20 12:46:50 +00:00
zzz
64a753116b * i2ptunnel: Fix server-side stripping of X-Accept-encoding 2011-05-20 12:43:50 +00:00
5ce439ffc4 merge of '97f5690455a3a74e68056739ea7145c8059454c6'
and 'e01e159c9825a36e8e640bb3cf8d0f1200b1be2f'
2011-05-19 05:47:02 +00:00
00f2721640 upd 2011-05-19 05:44:13 +00:00
454a310bbe make translation more castillian 2011-05-18 21:40:11 +00:00
18952f5109 upd routerconsole messages_fr.po 2011-05-18 11:37:39 +00:00
zzz
7377086aae 0.8.6 2011-05-16 19:58:19 +00:00
zzz
9f7cc9d887 add update host 2011-05-13 21:04:58 +00:00
zzz
ffa9ea9cd2 Increase min floodfills; decrease min routerinfo expiration 2011-05-13 20:13:56 +00:00
zzz
f9654661bb * Use partitions of fast tier for various hops of client tunnels; minor cleanups 2011-05-11 14:40:55 +00:00
zzz
5ce06d02b4 the rest of -2 2011-05-06 12:35:19 +00:00
zzz
c356792d02 * Tunnels and profiles:
- Increase max fast and high-cap tier sizes
      - Slow profile eval cycle after sufficient uptime
      - Fix bug which started a new build after a successful build
      - Misc. cleanups
2011-05-06 01:10:28 +00:00
90642a8ab5 warning 2011-05-05 01:59:20 +00:00
zzz
6199e7b74c oops fix path to newly tagged files 2011-05-03 13:15:13 +00:00
1e9ac05b63 merge of '83e7567c0dbdabe57c21a0bfdc9d70acbbc71463'
and 'f783d7f664254691074c1542a6d8937731e2b503'
2011-05-02 16:24:54 +00:00
ed338d9cfa minor tweak to es 2011-05-02 16:24:48 +00:00
a84e6f7854 typos 2011-05-02 11:23:01 +00:00
zzz
fe21748b2d -1 2011-04-28 18:46:09 +00:00
zzz
8b184f8c03 one more zero-length torrent check 2011-04-28 18:05:03 +00:00
zzz
5ed22d5c16 cleanups 2011-04-28 18:04:31 +00:00
zzz
525e0b4518 tag peers.jsp UPnP text 2011-04-28 18:03:18 +00:00
zzz
e8d94982e4 * Console: Try to prevent cascaded IllegalStateExceptions in .jsp code;
add logging for original error
2011-04-28 18:01:48 +00:00
zzz
38db0b0ff3 * UPnP: Strip trailing nulls from incoming XML to prevent
"content not allowed in trailing section" exceptions
      from stupid routers
2011-04-28 17:57:30 +00:00
e4a8b9621d site (plugin) 2011-04-25 06:29:20 +00:00
66ea1c060a merge of 'aee566a8e2250d2461203b83c7a3434b29f771f9'
and 'f6410ea071e6b154e0c14deea8ef6eaa35cb7faa'
2011-04-24 07:38:51 +00:00
50dabfec8c typo typo 2011-04-24 07:37:20 +00:00
a8722e033c tweaks es 2011-04-20 00:28:02 +00:00
1cec98d180 tweaks es 2011-04-20 00:24:37 +00:00
zzz
e62d9dfa48 more cleanups, clickable logo 2011-03-30 00:56:15 +00:00
zzz
6dd7431ccd message cleanup 2011-03-30 00:42:08 +00:00
zzz
7020bfd521 display cleanups 2011-03-30 00:19:28 +00:00
zzz
0fcf13ef73 * susidns:
- IDN toASCII improvements (old bean)
- Add 'other' filter
- Fix jsp 500s
2011-03-29 23:17:14 +00:00
zzz
9e37a5a4af * susidns:
- Enforce basic rules on host name additions
- Split up form
- IDN toASCII improvements
- Log message improvements
2011-03-29 22:46:59 +00:00
zzz
172541a368 implement delete on details page 2011-03-29 03:29:23 +00:00
zzz
9f475c03cb fix details for published book 2011-03-29 03:02:17 +00:00
zzz
fbfffa9987 - SusiDNS cleanups
- Logging cleanups
2011-03-29 02:16:42 +00:00
zzz
8ae398d786 - Isolate span read failures to that span
- Don't keep separate count of spans and levels, use BSL HashMap sizes
- Fix SkipList counts when read in
2011-03-28 20:33:57 +00:00
zzz
a818e84dcf - Cleanups, logging, checks and javadocs 2011-03-28 17:15:46 +00:00
zzz
33780ef359 - Fix FLB full check
- Cache FLB
- FLB logging, cleanups, checks
2011-03-28 14:27:19 +00:00
zzz
9fcb20a7bd - Free unused span continuation pages (big space savings)
- Less data copying during on-disk searches
2011-03-28 04:57:16 +00:00
zzz
991acd3917 fix level count init 2011-03-27 22:42:36 +00:00
zzz
f4905d2742 - Use new UTF8StringBytes
- Track number of SkipLevels in a SkipList
- More double-checks
- Caching cleanups
- Cleanups, logging, generics
2011-03-27 22:36:45 +00:00
zzz
b7b7283ff9 - Use new UTF8StringBytes
- Track number of SkipLevels in a SkipList
- More double-checks
- Cleanups, logging, generics
2011-03-27 22:19:50 +00:00
zzz
22d50dd150 require router.activePeers stat (ticket #450) 2011-03-27 19:19:41 +00:00
zzz
bc231b51b5 - Fix several bugs in removal of first or second span
- Fix bugs in flushes
- Add magic numbers for free pages and free list
- More bounds checking
- Lots of checks for double-kill / double-free
- Make some freelist errors non-fatal
- Cleanups, logging, javadocs, test code
2011-03-27 18:55:51 +00:00
zzz
a7fceb644f javadoc 2011-03-26 05:50:13 +00:00
zzz
312534b635 - Change disk format to add magic number to all pages
- Change blockfile magic number to reflect new format
- Cleanups and javadocs
2011-03-26 05:27:34 +00:00
zzz
8f9f102baf - Fix several bugs with BSkipLevels persistence
- Logging and debug code
- New serializers
- Cleanups and javadocs
2011-03-26 02:40:17 +00:00
zzz
078056f163 implement last-modified 2011-03-24 22:07:19 +00:00
zzz
1adb3d19c7 - Better serializer error handling and logging
- Automatic corruption repair in blockfile
- Automatic removal of bad entries in BFNS
- Use unsigned shorts to extend max lengths to 65535
- Check max length
- Throw IOE on negative ints
- Tweak fromProperties() exceptions
- Fix DataHelper encoding issues (ticket #436)
- CSS tweaks
2011-03-24 21:51:20 +00:00
zzz
7751661f3d basic IDN support 2011-03-24 05:30:33 +00:00
zzz
ca5484a984 - Add details page in susidns
- Add source in Daemon
- Honor list property in BFNS.lookup()
2011-03-24 03:00:47 +00:00
zzz
d6999a3327 * DataHelper:
- Undeprecate fromProperties() and toProperties()
      - Undeprecate BOOLEAN_FALSE and BOOLEAN_TRUE
      - Fix fromProperties() and toProperties() to correctly throw DataFormatExceptions
      - Add sort option
      - Efficiency improvements in writeProperties(), toProperties(), storeProps(), and toString()
2011-03-23 21:44:38 +00:00
zzz
c85931cbc5 log tweaks 2011-03-23 02:22:19 +00:00
zzz
7e0d0e2b01 - Implement getNames()
- Use getNames() for merging to hosts.txt naming services to avoid O(n**2)
- Fix naming service selection
- Don't merge from master book unless publishing
- Add naming service and direct config options
2011-03-22 22:10:15 +00:00
zzz
5dc9214296 - Iterate through eepgetted subscription file instead of loading the whole thing into memory 2011-03-22 18:20:44 +00:00
zzz
311bb7a4b6 propagate from branch 'i2p.i2p' (head 6467dc867b03e6be51ac21be14d7f8cbdadc2bd2)
to branch 'i2p.i2p.zzz.naming' (head ed37752523387104764b68a1deaaedb5e707e827)
2011-03-22 14:28:16 +00:00
zzz
c7a574fe01 final 2011-03-22 02:08:03 +00:00
zzz
1b2519cfb8 - Improved error handling
- Disable graphs on JVMs that crash
2011-03-22 01:59:52 +00:00
zzz
9c02aab4fb oops remove newline 2011-03-21 18:37:26 +00:00
zzz
40fd4ccd15 Stats:
- Refactor handling of required stats
    - Shorten description of required stats
    - Improve save messages on configstats.jsp
    - Change bw.sendBps and bw.receiveBps stats to bytes, not Kbytes
    - Expires directive for graphs
2011-03-21 18:14:58 +00:00
zzz
ddddc686fe propagate from branch 'i2p.i2p' (head 60c5cb17c0406b6e6e547489f9ea8ef3c290e262)
to branch 'i2p.i2p.zzz.jrobin159' (head 330a4f9652fe5f67e6e9998f5c0a87c7ef163764)
2011-03-21 14:29:03 +00:00
zzz
cf0d2197b8 - Persistent option on GUI
- Fix HTML errors
- Refresh improvements
- Fix Rate.equals() bug
- More cleanups
2011-03-18 15:49:58 +00:00
zzz
79358f4271 notes and tweaks 2011-03-18 00:47:14 +00:00
zzz
12f3634f96 more rows when persistent 2011-03-17 23:25:38 +00:00
zzz
033dee0216 - Persistent RRD
- Restart line in graphs
- Restore zh fonts in graphs
2011-03-17 21:13:52 +00:00
zzz
1324eaf056 cleanups and javadoc 2011-03-17 17:16:28 +00:00
zzz
2e5e3b9d40 better error messages, fix NPE, comment out template handling 2011-03-17 16:16:50 +00:00
zzz
ef26accde0 jrobin 1.5.9.1
sha1sum 7d76f5cdec625fd1ce21acc0e46d286fbd6d307f
Released 2008-09-05
Downloaded from http://sourceforge.net/projects/jrobin/files/jrobin/1.5.9/
License: LGPL 2.1

It appears that the only difference from 1.5.9 is it was compiled with Java 5
instead of Java 6. The 1.5.9 jars out there also contain the large font .ttf files,
which are not in 1.5.9.1.

The only announcement I could find about 1.5.9.1 is here:
http://opennms.530661.n2.nabble.com/Am-I-missing-something-td841945.html

The following directories are dropped from the jar during the build process:
org/jrobin/cmd/
org/jrobin/convertor/
org/jrobin/inspector/
2011-03-17 16:03:27 +00:00
zzz
8461beba1c 1st cut 2011-03-17 02:07:08 +00:00
zzz
b93e3dfb55 cleanups and permissions 2011-03-16 18:33:56 +00:00
zzz
5ef1dd87a5 javadoc fix 2011-03-16 18:14:51 +00:00
zzz
07860d018c add b32 links to susidns; add source property for additions via susidns 2011-03-16 17:28:10 +00:00
zzz
ce5ce12e3b * Naming services:
- Refactor caching
    - Logging, caching, shutdown cleanup and fixes
2011-03-16 16:11:54 +00:00
zzz
02c4bbfc58 fix filtering 2011-03-16 03:01:32 +00:00
zzz
bf613448d7 susidns/hoststxtNS compatibility fixes 2011-03-16 01:50:22 +00:00
zzz
5095e8a1d6 naming service shutdown stuff 2011-03-16 00:37:54 +00:00
zzz
0352ca3ef6 * Naming service, addressbook, susidns:
- Replace img hack for susidns requesting addressbook update
      with registration and request through the NamingService
2011-03-15 23:16:44 +00:00
zzz
12c5b9c21c * Naming services, addressbook, susidns:
- Fix search capability
    - Fix result count and view within results
    - Fix published address book
    - Fix ngettext
    - Cache size
    - Fix 0-9 filter
    - Addressbook updates via API, except for published
2011-03-15 21:52:48 +00:00
zzz
8b737b4adb static 2011-03-11 02:31:10 +00:00
zzz
f4e92572eb more generics 2011-03-11 02:18:15 +00:00
zzz
b048b016ad generics 2011-03-11 02:01:20 +00:00
zzz
41fc9cf4ca reverseLookup improvements 2011-03-11 01:11:18 +00:00
zzz
7edbd3ad0a * HostsTxtNamingService:
- Add getEntries() and size() support
2011-03-11 00:29:34 +00:00
zzz
de815e271c * Blockfile:
- More query options
    - More exception logging
    - Fix lookup infinite loop
    - Fix lookup NPE
  * SusiDNS:
    - Refactoring for new NamingService API
    - Initial conversion to new NamingService API
      (still needs work)
    - Fix lots of HTML warnings
    - Some Java 5 cleanup
2011-03-10 23:06:13 +00:00
zzz
ad24f1438f propagate from branch 'i2p.i2p' (head ca5b19055e887994435b0eb35978484f2489bb6e)
to branch 'i2p.i2p.zzz.naming' (head e71d7dc813c07bb2b6798ab74099efdfc1754f47)
2011-03-10 17:59:35 +00:00
zzz
a3fb49adcb add missing files; new API in blockfile NS 2011-02-27 14:49:04 +00:00
zzz
c269546c08 stub out new API, needs testing 2011-02-22 23:39:51 +00:00
zzz
258c260601 fix SkipIterator 2011-02-21 21:35:01 +00:00
zzz
ad3342aefb exception cleanup 2011-02-08 14:26:46 +00:00
zzz
54fdfd823b - Drop deprecated NamingServices
- Add caching and b32 support to DummyNamingService
    - BlockfileNamingService Cleanups
2011-02-08 03:29:18 +00:00
zzz
ba9c7015fe blockfile naming service 2011-02-08 00:46:47 +00:00
zzz
208db9a673 initial blockfile mods 2011-02-08 00:45:23 +00:00
zzz
7f10a67804 BlockFile as downloaded 2011-02-08 00:41:33 +00:00
zzz
08d24b059a remove nativeDoubleValue(), update jbigi README 2011-01-18 14:05:26 +00:00
zzz
1811989089 unbundle jbigi.jar, create at build time 2011-01-11 00:44:36 +00:00
2828 changed files with 144692 additions and 452239 deletions

View File

@ -22,3 +22,31 @@ _jsp\.java$
~$
/build/
/classes/
# Android-specific ignores
^routerjars/libs
local.properties
signing.properties
#IntelliJ IDEA
^.idea
.*.iml
.*.ipr
.*.iws
#Gradle
^.gradle
build
# I2P-specific ignores
^app/src/main/res/drawable/i2plogo.png
^app/src/main/res/raw/blocklist_txt
^app/src/main/res/raw/hosts_txt
^app/src/main/res/raw/.*_ht
^app/src/main/res/raw/license_
^app/src/main/res/raw/certificates_zip
^app/src/main/assets/themes/console/images
^app/src/main/assets/themes/console/light/console.css
^app/src/main/assets/themes/console/light/images/header.png
^scripts/build.number
^scripts/version.properties

View File

@ -1,67 +1,18 @@
[I2P.i2ptunnel]
source_file = apps/i2ptunnel/locale/messages_en.po
source_lang = en
trans.ar = apps/i2ptunnel/locale/messages_ar.po
trans.de = apps/i2ptunnel/locale/messages_de.po
trans.es = apps/i2ptunnel/locale/messages_es.po
trans.fr = apps/i2ptunnel/locale/messages_fr.po
trans.nl = apps/i2ptunnel/locale/messages_nl.po
trans.ru = apps/i2ptunnel/locale/messages_ru.po
trans.zh_CN = apps/i2ptunnel/locale/messages_zh.po
[I2P.routerconsole]
source_file = apps/routerconsole/locale/messages_en.po
source_lang = en
trans.ar = apps/routerconsole/locale/messages_ar.po
trans.de = apps/routerconsole/locale/messages_de.po
trans.es = apps/routerconsole/locale/messages_es.po
trans.fr = apps/routerconsole/locale/messages_fr.po
trans.nl = apps/routerconsole/locale/messages_nl.po
trans.ru = apps/routerconsole/locale/messages_ru.po
trans.zh_CN = apps/routerconsole/locale/messages_zh.po
[I2P.i2psnark]
source_file = apps/i2psnark/locale/messages_en.po
source_lang = en
trans.ar = apps/i2psnark/locale/messages_ar.po
trans.de = apps/i2psnark/locale/messages_de.po
trans.es = apps/i2psnark/locale/messages_es.po
trans.fr = apps/i2psnark/locale/messages_fr.po
trans.nl = apps/i2psnark/locale/messages_nl.po
trans.pt = apps/i2psnark/locale/messages_pt.po
trans.ru = apps/i2psnark/locale/messages_ru.po
trans.zh_CN = apps/i2psnark/locale/messages_zh.po
[I2P.susidns]
source_file = apps/susidns/locale/messages_en.po
source_lang = en
trans.ar = apps/susidns/locale/messages_ar.po
trans.de = apps/susidns/locale/messages_de.po
trans.es = apps/susidns/locale/messages_es.po
trans.fr = apps/susidns/locale/messages_fr.po
trans.nl = apps/susidns/locale/messages_nl.po
trans.ru = apps/susidns/locale/messages_ru.po
trans.zh_CN = apps/susidns/locale/messages_zh.po
[I2P.desktopgui]
source_file = apps/desktopgui/locale/messages_en.po
source_lang = en
trans.ar = apps/desktopgui/locale/messages_ar.po
trans.de = apps/desktopgui/locale/messages_de.po
trans.es = apps/desktopgui/locale/messages_es.po
trans.fr = apps/desktopgui/locale/messages_fr.po
trans.nl = apps/desktopgui/locale/messages_nl.po
trans.ru = apps/desktopgui/locale/messages_ru.po
trans.zh_CN = apps/desktopgui/locale/messages_zh.po
[I2P.susimail]
source_file = apps/susimail/locale/messages_en.po
source_lang = en
trans.de = apps/susimail/locale/messages_de.po
trans.es = apps/susimail/locale/messages_es.po
trans.fr = apps/susimail/locale/messages_fr.po
trans.nl = apps/susimail/locale/messages_nl.po
[main]
host = http://www.transifex.net
host = https://www.transifex.com
lang_map = he: iw, id: in, pt_BR: pt-rBR, ru_RU: ru, sv_SE: sv, tr_TR: tr, uk_UA: uk, yi: ji, zh_CN: zh
[I2P.android]
file_filter = app/src/main/res/values-<lang>/strings.xml
source_file = app/src/main/res/values/strings.xml
source_lang = en
type = ANDROID
minimum_perc = 50
[I2P.android_lib_client]
file_filter = client/src/main/res/values-<lang>/strings.xml
source_file = client/src/main/res/values/strings.xml
source_lang = en
type = ANDROID
minimum_perc = 50

47
CHANGELOG Normal file
View File

@ -0,0 +1,47 @@
0.9.20
* Simplified the main interface
* Language can be configured
* Tunnels can now be edited
* Material design improvements
* Better support for tablets
* Improved graph rendering
* Bug fixes and translation updates
0.9.19.1 / 2015-04-15 / ed86e7e85161dbe3f15932fd4d195c551f8e2c71
* Fixed crash when opening advanced settings
0.9.19 / 2015-04-13 / 3cfb748946a5876dc06d5f81d811b142a88846f7
* Made internal state handling more stable
* Added graceful shutdown support
* Updated libjbigi to use GMP 6.0.0
* New libjbigi binary for armeabi-v7a to speed up newer devices
* Improved logging
* Bug fixes and translation updates
0.9.18 / 2015-03-04 / c2f4831a1617f4ce716a08640446fdd992c751ff
* I2P can start automatically when phone boots (configure in Setting)
* Updated browser configuration guides for Orfox and Firefox
* Tunnels for postman's mail server added to defaults (for new installs)
* Settings options for configuring UDP and TCP ports
* Bug fixes and translation updates
0.9.17.1 / 2014-12-14 / cd8bb5e3ac4238efac12179c78c4fa517fcaabec
* Fixed crashes in addressbook and netDb status page
* Fixed crash when opening an IRC client tunnel
* Updated translations
0.9.17 / 2014-12-01 / bcf947f433876f643e0f6dff81aac88848b797d3
* Migrated to the new Material design from Android Lollipop
* Added a browser configuration guide
* Improved the help screen
* Upgraded the I2P router to 0.9.17
* Various bug fixes and translation updates
0.9.15.1 / 2014-10-16 / 9cc4e80134cf9becb3838ed3cc78e0bed1363165
* Fixed a configuration bug
0.9.15 / 2014-10-16 / 9b51f78b791c28a580d57f1a5019c94493de6231
* Upgraded the I2P router to 0.9.15
* Added a help screen with some basic information
* Logs can now be copied to the clipboard
* Various user interface improvements and fixes

View File

@ -1,45 +0,0 @@
Headless I2P installation instructions
1) java -jar i2pinstall.exe -console (you've already done this)
This will run the installer in text mode, including running the postinstall.sh
script. After that, you may run 'sh i2prouter start'
which will start the router and attempt to launch a browser.
If you do not have an X server running, the browser launch will probably fail, and
you may use:
lynx http://localhost:7657/index.jsp
to configure the router.
If you're having trouble, swing by http://forum.i2p2.de/, check the
website at http://www.i2p2.de/, or get on irc://irc.freenode.net/#i2p
I2P will create and store files and configuration data in the user directory
~/.i2p/ on Linux and %APPDATA%\I2P\ on Windows. This directory is created
when I2P is run for the first time. It also creates files in the system
temporary directory specified by the Java Virtual Machine.
To change the location of these directories, or to configure I2P to
put all files in this directory (the so-called "portable" configuration),
edit the files i2prouter (Linux) and wrapper.config (Linux and Windows)
where there are comments labeled "PORTABLE". Do this before you
run I2P for the first time.
To run I2P explicitly:
(*nix): sh i2prouter start
(win*): I2P.exe
(Platforms unsupported by the wrapper - PPC, ARM, etc): sh runplain.sh
To stop the router (gracefully):
lynx http://localhost:7657/configservice.jsp ("Shutdown gracefully")
To stop the router (immediately):
sh i2prouter stop
To uninstall I2P:
rm -rf $i2pInstallDir
Supported JVMs:
Windows: Latest available from http://java.sun.com/ (1.5+ supported)
Linux: Latest available from http://java.sun.com/ (1.5+ supported)
FreeBSD: Sun 1.5-compatible (NIO required)
various: http://www.kaffe.org/ Sun 1.5-compatible (NIO required)

View File

@ -1,33 +0,0 @@
I2P source installation instructions
Prerequisites to build from source:
Java SDK (preferably Sun) 1.5.0 or higher (1.6 recommended)
The SDK must have Pack200 support (java.util.jar.Pack200)
Apache Ant 1.7.0 or higher
Optional, For multilanguage support: The xgettext, msgfmt, and msgmerge tools installed
from the GNU gettext package http://www.gnu.org/software/gettext/
To build and install I2P from source, you must first build
and package up the appropriate installer by running:
ant pkg
This will produce a few key files:
* install.jar: the GUI and console installer
* i2pinstall.exe: the GUI and console installer wrapped for cross-platform execution
* i2pupdate.zip: the update package
From there, you can run the headless (console mode) installer:
java -jar i2pinstall.exe -console
Or run the GUI installer:
java -jar i2pinstall.exe
Or move the update file into an existing installation directory and restart.
Supported JVMs:
Windows: Latest available from http://java.sun.com/ (1.5+ supported)
Linux: Latest available from http://java.sun.com/ (1.5+ supported)
FreeBSD: Sun 1.5-compatible (NIO required)
various: http://www.kaffe.org/ Sun 1.5-compatible (NIO required)

View File

@ -25,222 +25,26 @@ PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
===================================
LICENSES
--------
License for the Android App:
Core:
Public domain except as listed below:
Copyright 2011 The I2P Project
ElGamal and DSA code:
Copyright (c) 2003, TheCrypto
See licenses/LICENSE-ElGamalDSA.txt
Licensed under the Apache License, Version 2.0 (the "License");
you may not use these files except in compliance with the License.
You may obtain a copy of the License at
SHA256 and HMAC-SHA256:
Copyright (c) 2000 - 2004 The Legion Of The Bouncy Castle
See licenses/LICENSE-SHA256.txt
http://www.apache.org/licenses/LICENSE-2.0
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 licenses/LICENSE-BSD.txt
SNTP code:
Copyright (c) 2004, Adam Buckley
See licenses/LICENSE-SNTP.txt
PRNG:
Copyright (C) 2001, 2002, Free Software Foundation, Inc.
See licenses/LICENSE-LGPLv2.1.txt
GMP 4.1.3:
Copyright 1991, 1996, 1999, 2000 Free Software Foundation, Inc.
See licenses/LICENSE-LGPLv2.1.txt
HashCash code:
Copyright 2006 Gregory Rubin grrubin@gmail.com
See licenses/LICENSE-HashCash.txt
GettextResource from gettext v0.18:
Copyright (C) 2001, 2007 Free Software Foundation, Inc.
See licenses/LICENSE-LGPLv2.1.txt
SSLEepGet:
Contains some code Copyright 2006 Sun Microsystems, Inc.
See licenses/LICENSE-InstallCert.txt
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Router:
Public domain except as listed below:
UPnP.java:
From freenet
See licenses/LICENSE-GPLv2.txt
UPnP subsystem 1.7:
Copyright (C) 2003-2006 Satoshi Konno
See licenses/LICENSE-UPnP.txt
GeoIP data free to use, courtesy http://ip-to-country.webhosting.info/
===================================
Installer:
Launch4j 3.0.1:
Copyright (c) 2004, 2008 Grzegorz Kowal
See licenses/LICENSE-Launch4j.txt (in binary packages)
See installer/lib/launch4j/LICENSE.txt (in source packages)
The following projects are used by Launch4j...
MinGW binutils (http://www.mingw.org/)
Commons BeanUtils (http://jakarta.apache.org/commons/beanutils/)
Commons Logging (http://jakarta.apache.org/commons/logging/)
See licenses/LICENSE-Apache1.1.txt
See licenses/NOTICE-Commons-Logging.txt
XStream (http://xstream.codehaus.org/)
Copyright (c) 2003-2004, Joe Walnes
See licenses/LICENSE-XStream.txt
JGoodies Forms (http://www.jgoodies.com/freeware/forms/)
Copyright (c) 2002-2004 JGoodies Karsten Lentzsch. All rights reserved.
See licenses/LICENSE-JGoodies-Forms.txt
JGoodies Looks (http://www.jgoodies.com/freeware/looks/)
Copyright (c) 2003 JGoodies Karsten Lentzsch. All rights reserved.
See licenses/LICENSE-JGoodies-Looks.txt
Foxtrot (http://foxtrot.sourceforge.net/)
Copyright (c) 2002, Simone Bordet & Marco Cravero. All rights reserved.
See licenses/LICENSE-Foxtrot.txt
Nuvola Icon Theme (http://www.icon-king.com)
See licenses/LICENSE-LGPLv2.1.txt
Forms were created using Abeille Forms Designer (https://abeille.dev.java.net/)
Izpack 4.3.0:
Copyright (c) 2001-2008 Julien Ponge
See licenses/LICENSE-Apache2.0.txt
Wrapper 3.1.1:
Copyright (c) 1999, 2004 Tanuki Software
See licenses/LICENSE-Wrapper.txt
Applications:
Addressbook:
Copyright (c) 2004 Ragnarok
See licenses/LICENSE-Addressbook.txt
BOB:
Copyright (C) sponge
DWTFYWTPL
I2PSnark:
Copyright (C) 2003 Mark J. Wielaard
See licenses/LICENSE-GPLv2.txt
Silk icons: See licenses/LICENSE-SilkIcons.txt
I2PTunnel:
(c) 2003 - 2004 mihi
GPLv2 with exception.
See licenses/LICENSE-I2PTunnel.txt
See licenses/LICENSE-GPLv2.txt
I2PTunnel SOCKS Proxy:
Copyright (c) 2004 by human
GPLv2 with exception.
See licenses/LICENSE-I2PTunnel.txt
See licenses/LICENSE-GPLv2.txt
I2PTunnel UDP and Streamr:
By welterde.
See licenses/LICENSE-GPLv2.txt
Jetty 5.1.12:
Copyright 2000-2004 Mort Bay Consulting Pty. Ltd.
See licenses/LICENSE-Apache1.1.txt
See licenses/LICENSE-Apache2.0.txt
See licenses/NOTICE-Commons-Logging.txt
JRobin 1.4.0:
See licenses/LICENSE-LGPLv2.1.txt
Ministreaming Lib:
By mihi.
See licenses/LICENSE-BSD.txt
Proxyscript:
By Cervantes.
Public domain.
Router console:
Public domain.
Flag icons: public domain, courtesy mjames@gmail.com http://www.famfamfam.com/
Silk icons: See licenses/LICENSE-SilkIcons.txt
GeoIP Data:
Copyright (c) 2003 Direct Information Pvt. Ltd. All Rights Reserved.
See licenses/LICENSE-GeoIP.txt
SAM:
Public domain.
Streaming Lib:
Public domain.
SusiDNS:
Copyright (C) 2005 <susi23@mail.i2p>
See licenses/LICENSE-GPLv2.txt
SusiMail:
Copyright (C) 2004-2005 <susi23@mail.i2p>
See licenses/LICENSE-GPLv2.txt
Systray:
Public domain.
Bundles systray4j code:
See licenses/LICENSE-GPLv2.txt
Other Applications and Libraries
--------------------------------
The following applications and libraries are not used or bundled in
binary packages, therefore the licenses are not included in binary
distributions. See the source package for the additional license information.
Admin Manager:
Public domain
Atalk:
Public domain
Desktopgui
Copyright (c) Mathias De Maré
See apps/desktopgui/LICENSE
SAM C Library:
Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
See apps/sam/c/doc/license.txt
SAM C# Library:
Public domain.
See apps/sam/csharp/README
SAM Perl Library:
See licenses/LICENSE-GPLv2.txt
SAM Python Library:
Public domain.
I2PSnark/Console themes:
"Man with hat over face" & related images licensed under a Creative Commons 2.0 license.
Original photos by Florian Kuhlmann. http://www.flickr.com/photos/floriankuhlmann/3117758155
See the file licenses/LICENSE-Apache2.0.txt

View File

@ -1,132 +0,0 @@
# Makefile for building native I2P binaries and libraries with GCJ
#
# WARNING: Do not use this yet, as it may explode (etc).
#
GCJ=gcj #/usr/local/gcc-4.0.2/bin/gcj
EXTRA_LD_PATH= #/usr/local/gcc-4.0.2/lib
ANT=ant #/opt/apache-ant-1.6.5/bin/ant
ANT_TARGET=build2
NATIVE_DIR=native
##
# Define what jar files get into libi2p.so. The current setup is
# *incredibly* lazy, throwing everything in the .so, rather than
# give each .jar file its own .so.
# i2p.jar: base SDK
# mstreaming.jar: streaming API
# streaming.jar: full streaming lib implementation
# i2ptunnel.jar: I2PTunnel proxy
# sam.jar: SAM bridge and API
# i2psnark.jar: bittorrent client
# router.jar: full I2P router
# jbigi.jar: collection of native optimized GMP routines for crypto
JAR_BASE=i2p.jar mstreaming.jar streaming.jar
JAR_CLIENTS=i2ptunnel.jar sam.jar
JAR_ROUTER=router.jar
JAR_JBIGI=jbigi.jar
JAR_CONSOLE=\
javax.servlet.jar \
commons-el.jar \
commons-logging.jar \
jasper-runtime.jar \
jasper-compiler.jar \
org.mortbay.jetty.jar \
routerconsole.jar
LIBI2P_JARS=${JAR_BASE} ${JAR_CLIENTS} ${JAR_ROUTER} ${JAR_JBIGI}
LIBSAM_JARS=${JAR_BASE} sam.jar
LIBROUTER_JARS=i2p.jar ${JAR_ROUTER} ${JAR_JBIGI}
LIBCONSOLE_JARS=${LIBROUTER_JARS} ${JAR_CONSOLE}
LIBSNARK_JARS=${LIBROUTER_JARS} i2psnark.jar
# update:
# similar error with gcj 4.3.3.
#
# unfortunately, its not quite ready for most end users, as the
# ${JAR_CONSOLE} fails to compile with:
# org/apache/commons/logging/impl/LogKitLogger.java: In class 'org.apache.commons.logging.impl.LogKitLogger':
# .../LogKitLogger.java: In constructor '(java.lang.String)':
# .../LogKitLogger.java:91: error: cannot find file for class org.apache.log.Hierarchy
# .../LogKitLogger.java:91: error: cannot find file for class org.apache.log.Hierarchy
# .../LogKitLogger.java:104: error: cannot find file for class org.apache.log.Hierarchy
# .../LogKitLogger.java:104: confused by earlier errors, bailing out
#${JAR_CONSOLE}\
#${JAR_XML} \
#${JAR_SUCKER}
#${JAR_CONSOLE}
SYSTEM_PROPS=-DloggerFilenameOverride=logs/log-router-@.txt \
-Dorg.mortbay.http.Version.paranoid=true \
-Dorg.mortbay.util.FileResource.checkAliases=false \
-Dorg.mortbay.xml.XmlParser.NotValidating=true
#SYSTEM_PROPS=-Di2p.weakPRNG=true
OPTIMIZE=-O2
#OPTIMIZE=-O3
LD_LIBRARY_PATH=${EXTRA_LD_PATH}:.
all: jars native
@echo "* Build complete"
jars:
@${ANT} ${ANT_TARGET}
clean: native_clean
native: native_clean native_shared
@echo "* Native code build in ${NATIVE}"
native_clean:
@rm -rf ${NATIVE_DIR}
@mkdir ${NATIVE_DIR}
native_shared: libi2p.so
@cd build ; ${GCJ} ${OPTIMIZE} -fjni -L../${NATIVE_DIR} -li2p ${SYSTEM_PROPS} -o ../${NATIVE_DIR}/i2p_dsa --main=net.i2p.crypto.DSAEngine
@echo "* i2p_dsa is a simple test app with the DSA engine and Fortuna PRNG to make sure crypto is working"
@cd build ; ${GCJ} ${OPTIMIZE} -fjni -L../${NATIVE_DIR} -li2p ${SYSTEM_PROPS} -o ../${NATIVE_DIR}/prng --main=gnu.crypto.prng.FortunaStandalone
@cd build ; ${GCJ} ${OPTIMIZE} -fjni -L../${NATIVE_DIR} -li2p ${SYSTEM_PROPS} -o ../${NATIVE_DIR}/i2ptunnel --main=net.i2p.i2ptunnel.I2PTunnel
@echo "* i2ptunnel is mihi's I2PTunnel CLI"
@echo " run it as ./i2ptunnel -cli to avoid awt complaints"
@cd build ; ${GCJ} ${OPTIMIZE} -fjni -L../${NATIVE_DIR} -li2p ${SYSTEM_PROPS} -o ../${NATIVE_DIR}/i2ptunnelctl --main=net.i2p.i2ptunnel.TunnelControllerGroup
@echo "* i2ptunnelctl is a controller for I2PTunnel, reading i2ptunnel.config"
@echo " and launching the appropriate proxies"
#@cd build ; ${GCJ} ${OPTIMIZE} -fjni -L../${NATIVE_DIR} -li2p ${SYSTEM_PROPS} -o ../${NATIVE_DIR}/i2psnark --main=org.klomp.snark.Snark
#@echo "* i2psnark is an anonymous bittorrent client"
@cd build ; ${GCJ} ${OPTIMIZE} -fjni -L../${NATIVE_DIR} -li2p ${SYSTEM_PROPS} -o ../${NATIVE_DIR}/i2prouter --main=net.i2p.router.Router
@echo "* i2prouter is the main I2P router"
@echo " it can be used, and while the router console won't load,"
@echo " i2ptunnel will, so it will start all the proxies defined in i2ptunnel.config"
libi2p.so:
@echo "* Building $@"
@(cd build ; time ${GCJ} ${OPTIMIZE} -fPIC -fjni -shared -o ../${NATIVE_DIR}/$@ ${LIBI2P_JARS} ; cd .. )
@ls -l ${NATIVE_DIR}/$@
@echo "* $@ built"
sam: jars libi2psam.so
libi2psam.so:
@echo "* Building $@"
@rm -f ${NATIVE_DIR}/$@
@(cd build ; time ${GCJ} ${OPTIMIZE} -fPIC -fjni -shared -o ../${NATIVE_DIR}/$@ ${LIBSAM_JARS} ; cd .. )
@ls -l ${NATIVE_DIR}/$@
@echo "* $@ built"
router: jars libi2prouter.so
libi2prouter.so:
@echo "* Building $@"
@rm -f ${NATIVE_DIR}/$@
@(cd build ; time ${GCJ} ${OPTIMIZE} -fPIC -fjni -shared -o ../${NATIVE_DIR}/$@ ${LIBROUTER_JARS} ; cd .. )
@ls -l ${NATIVE_DIR}/$@
@echo "* $@ built"
console: jars libi2pconsole.so
# doesn't work, see above
libi2pconsole.so:
@echo "* Building $@"
@rm -f ${NATIVE_DIR}/$@
@(cd build ; time ${GCJ} ${OPTIMIZE} -fPIC -fjni -shared -o ../${NATIVE_DIR}/$@ ${LIBCONSOLE_JARS} ; cd .. )
@ls -l ${NATIVE_DIR}/$@
@echo "* $@ built"

151
README.md Normal file
View File

@ -0,0 +1,151 @@
# I2P Android
## Build process
### Dependencies:
- Java SDK (preferably Oracle/Sun or OpenJDK) 1.6.0 or higher
- Apache Ant 1.8.0 or higher
- I2P source
- Android SDK for API 21
- Android Build Tools 21.1.2
- Android Support Repository
- Gradle 2.2.1
### Gradle
The build system is based on Gradle. There are several methods for setting Gradle up:
* It can be downloaded from [the Gradle website](http://www.gradle.org/downloads).
* Most distributions will have Gradle packages. Be careful to check the
provided version; Debian and Ubuntu have old versions in their main
repositories. There is a [PPA](https://launchpad.net/~cwchien/+archive/gradle)
for Ubuntu with the latest version of Gradle.
* A Gradle wrapper is provided in the codebase. It takes all the same commands
as the regular `gradle` command. The first time that any command is run, it
will automatically download, cache and use the correct version of Gradle.
This is the simplest way to get started with the codebase. To use it, replace
`gradle` with `./gradlew` (or `./gradlew.bat` on Windows) in the commands
below.
Gradle will pull dependencies over the clearnet by default. To send all Gradle
connections from your user over Tor, create a `gradle.properties` file in
`~/.gradle/` containing:
```
systemProp.socksProxyHost=localhost
systemProp.socksProxyPort=9150
```
### Preparation
1. Download the Android SDK. The simplest method is to download [Android Studio](https://developer.android.com/sdk/installing/studio.html).
* If you are using an existing Android SDK, install the Android Support
Repository via the SDK Manager.
2. Check out the [`i2p.i2p`](https://github.com/i2p/i2p.i2p) repository.
3. Create a `local.properties` file in `i2p.android.base/routerjars` containing:
```
i2psrc=/path/to/i2p.i2p
```
### Building from the command line
1. Create a `local.properties` file in `i2p.android.base` containing:
```
sdk.dir=/path/to/android-studio/sdk
```
2. `gradle assembleDebug`
3. The APK will be placed in `i2p.android.base/app/build/outputs/apk`.
### Building with Android Studio
1. Import `i2p.android.base` into Android Studio. (This creates the `local.properties` file automatically).
2. Build and run the app (`Shift+F10`).
### Signing release builds
1. Create a `signing.properties` file in `i2p.android.base` containing:
```
STORE_FILE=/path/to/android.keystore
STORE_PASSWORD=store.password
KEY_ALIAS=key.alias
KEY_PASSWORD=key.password
```
2. `gradle assembleRelease`
## Client library
### "Uploading" to the local Maven repository (to use a local build of the library in a project)
1. `gradle :client:installArchives`
2. Add the local Maven repository to your project. For Gradle projects, add the following above any existing repositories (so it is checked first):
```
repositories {
mavenLocal()
}
```
### Uploading to Maven Central via Sonatype OSSRH
1. Add the following lines to your `~/.gradle/gradle.properties` (filling in the blanks):
```
signing.keyId=
signing.password=
signing.secretKeyRingFile=/path/to/secring.gpg
ossrhUsername=
ossrhPassword=
```
2. `gradle :client:uploadArchives`
### Commands from the old build instructions that might be useful
```
# Create the android 4.4 (API 19) virtual device
# (don't make a custom hardware profile)
../android-sdk-linux/tools/android create avd --name i2p --target android-19
# then run the emulator:
# This may take a LONG time the first time (half an hour or more)...
# Run the debugger to ensure it is making progress
# -no-boot-anim for faster boot
# -dns-server 8.8.8.8 if the router can't reseed
# ../android-sdk-linux/tools/emulator -avd i2p -no-boot-anim -dns-server 8.8.8.8 &
../android-sdk-linux/tools/emulator -avd i2p &
# or to talk to a real device in debug mode:
# You have to do this if you get a permission error -
# Stop ddms, unplug the device, do the following,
# then plug in the device, then start ddms
adb kill-server
sudo adb start-server
adb devices
# Anyway, with I2P installed, click on the I2P icon on your device and enjoy!
#other helpful commands
../android-sdk-linux/platform-tools/adb shell
../android-sdk-linux/platform-tools/adb pull /some/file/on/emulator some-local-dir/
# copy the Dev Tools app from the emulator to your device
adb -e pull /system/app/Development.apk ./Development.apk
adb -d install Development.apk
# reinstall an existing apk onto the emulator
adb -e install -r bin/I2PAndroid-debug.apk
```

View File

@ -1,32 +0,0 @@
Prerequisites to build from source:
Java SDK (preferably Sun) 1.5.0 or higher (1.6 recommended)
The SDK must have Pack200 support (java.util.jar.Pack200)
Apache Ant 1.7.0 or higher
Optional, For multilanguage support: The xgettext, msgfmt, and msgmerge tools installed
from the GNU gettext package http://www.gnu.org/software/gettext/
To build:
ant pkg
Run 'ant' with no arguments to see other build options.
See INSTALL.txt or http://www.i2p2.de/download.html for installation instructions.
Documentation:
http://www.i2p2.de/
API: run 'ant javadoc' then start at build/javadoc/index.html
Latest release:
http://www.i2p2.de/download.html
To get development branch from source control:
http://www.i2p2.de/newdevelopers.html
FAQ:
http://www.i2p2.de/faq.html
Need help?
IRC irc.freenode.net #i2p
http://forum.i2p2.de/
Licenses:
See LICENSE.txt

View File

@ -1,30 +0,0 @@
ou will need atleast monotone > = 0.41 to get the most recent build source
and connect it to an already running i2p router.
OR:
You may download the actual "stable" source from
http://code.google.com/p/i2p/downloads/list
You will need to follwing tools to build the i2p and i2p-base packages:
bash >= 3.1.017
requiredbuilder >= 0.16.3 ( http://www.stabellini.net/requiredbuilder.html )
jre >= 6u11
jdk >= 6u11
apache-ant >= 1.7.1
perl >= 5.10.0
python >= 2.5.2
Reccomended:
monotone >= 0.41 ( http://pkgs.dr.ea.ms )
See also:
i2p/readme.txt
AND
i2p-base/readme.txt
for information and handy tips.

View File

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<project basedir="." default="slackpkg">
<target name="slackpkg">
<echo message="Building Slackware package." />
<exec executable="./i2p-base.SlackBuild">
</exec>
</target>
</project>

View File

@ -1,157 +0,0 @@
#!/bin/sh
#
#
# Now in the future we only need to look for '#I2P' and '#/I2P'
# for modifications to rc.local and rc.local_shutdown.
# I was a moron for not doing it this way in the first place :-) -- Sponge
#
#
touch /etc/rc.d/rc.local
touch /etc/rc.d/rc.local_shutdown
echo
echo -n "Check 1: /etc/rc.d/rc.local "
I2PRCA=`grep -c /etc/rc.d/rc.local -e '/etc/rc.d/rc.i2p'`
if [ $I2PRCA -eq 0 ] ; then
echo '#I2P' >> /etc/rc.d/rc.local
echo '( cd /tmp ; rm -Rf i2p-*.tmp )' >> /etc/rc.d/rc.local
echo "if [ -x /etc/rc.d/rc.i2p ] ; then" >> /etc/rc.d/rc.local
echo " sh /etc/rc.d/rc.i2p start" >> /etc/rc.d/rc.local
echo "fi" >> /etc/rc.d/rc.local
echo '#/I2P' >> /etc/rc.d/rc.local
echo "modified."
else
echo -n "looks OK so far,"
# Fix old installs, or where people have modified.
echo -n " Check 1A: "
I2PRCC=`grep -c /etc/rc.d/rc.local -e 'i2p-\*\.tmp'`
if [ $I2PRCC -eq 0 ] ; then
DATA=$(cat /etc/rc.d/rc.local | sed -re 's/if \[ -x \/etc\/rc\.d\/rc\.i2p \] ; then/#I2P\n\( cd \/tmp ; rm -Rf i2p-*.tmp \)\nif \[ -x \/etc\/rc.d\/rc.i2p \] ; then/')
echo "${DATA}" > /etc/rc.d/rc.local
echo -n "additional modifications applied,"
else
echo -n "looks OK so far,"
fi
echo -n " Check 1B: "
I2PRCE=`grep -c /etc/rc.d/rc.local -e 'i2p-\*\.tmp'`
if [ $I2PRCE -eq 0 ] ; then
DATATOP=$(cat /etc/rc.d/rc.local | sed -n '0,/i2p-\*\.tmp/p' | sed '$d' )
DATABOT=$(cat /etc/rc.d/rc.local | sed -n '/i2p-\*\.tmp/,$p' | sed -n '/^fi/,$p' | sed "1d")
echo "${DATATOP}" > /etc/rc.d/rc.local
echo '#I2P' >> /etc/rc.d/rc.local
echo '( cd /tmp ; rm -Rf i2p-*.tmp )' >> /etc/rc.d/rc.local
echo "if [ -x /etc/rc.d/rc.i2p ] ; then" >> /etc/rc.d/rc.local
echo " sh /etc/rc.d/rc.i2p start" >> /etc/rc.d/rc.local
echo "fi" >> /etc/rc.d/rc.local
echo '#/I2P' >> /etc/rc.d/rc.local
echo "${DATABOT}" >> /etc/rc.d/rc.local
echo -n "additional modifications applied,"
else
echo -n "looks ok so far,"
fi
echo -n " Check 1C: "
I2PRCF=`grep -c /etc/rc.d/rc.local -e '#/I2P'`
if [ $I2PRCF -eq 0 ] ; then
DATATOP=$(cat /etc/rc.d/rc.local | sed -n '0,/^#I2P/p' | sed '$d' )
DATABOT=$(cat /etc/rc.d/rc.local | sed -n '/^#I2P/,$p' | sed -n '/^fi/,$p' | sed "1d")
echo "${DATATOP}" > /etc/rc.d/rc.local
echo '#I2P' >> /etc/rc.d/rc.local
echo '( cd /tmp ; rm -Rf i2p-*.tmp )' >> /etc/rc.d/rc.local
echo "if [ -x /etc/rc.d/rc.i2p ] ; then" >> /etc/rc.d/rc.local
echo " sh /etc/rc.d/rc.i2p start" >> /etc/rc.d/rc.local
echo "fi" >> /etc/rc.d/rc.local
echo '#/I2P' >> /etc/rc.d/rc.local
echo "${DATABOT}" >> /etc/rc.d/rc.local
echo -n "additional modifications applied,"
else
echo -n "looks ok so far,"
fi
echo " Done."
fi
echo -n "Check 2: /etc/rc.d/rc.local_shutdown "
I2PRCB=`grep -c /etc/rc.d/rc.local_shutdown -e '/etc/rc.d/rc.i2p'`
if [ $I2PRCB -eq 0 ] ; then
echo "#I2P" >> /etc/rc.d/rc.local_shutdown
echo "if [ -x /etc/rc.d/rc.i2p ] ; then" >> /etc/rc.d/rc.local_shutdown
echo " sh /etc/rc.d/rc.i2p stop" >> /etc/rc.d/rc.local_shutdown
echo "fi" >> /etc/rc.d/rc.local_shutdown
echo "#/I2P" >> /etc/rc.d/rc.local_shutdown
echo "modified."
else
echo -n "looks OK so far,"
# Fix old installs
echo -n " Check 1A: "
I2PRCG=`grep -c /etc/rc.d/rc.local_shutdown -e '#I2P'`
if [ $I2PRCG -eq 0 ] ; then
DATATOP=$(cat /etc/rc.d/rc.local_shutdown | sed -n '0,/^if \[ -x \/etc\/rc\.d\/rc\.i2p \] ; then/p' | sed '$d' )
DATABOT=$(cat /etc/rc.d/rc.local_shutdown | sed -n '/^if \[ -x \/etc\/rc\.d\/rc\.i2p \] ; then/,$p' | sed -n '/^fi/,$p' | sed "1d")
echo "${DATATOP}" > /etc/rc.d/rc.local_shutdown
echo '#I2P' >> /etc/rc.d/rc.local_shutdown
echo "if [ -x /etc/rc.d/rc.i2p ] ; then" >> /etc/rc.d/rc.local_shutdown
echo " sh /etc/rc.d/rc.i2p stop" >> /etc/rc.d/rc.local_shutdown
echo "fi" >> /etc/rc.d/rc.local_shutdown
echo "#/I2P" >> /etc/rc.d/rc.local_shutdown
echo "${DATABOT}" >> /etc/rc.d/rc.local_shutdown
echo -n "additional modifications applied,"
else
echo -n "looks OK so far,"
fi
echo -n " Check 1B: "
I2PRCH=`grep -c /etc/rc.d/rc.local_shutdown -e '#/I2P'`
if [ $I2PRCH -eq 0 ] ; then
DATATOP=$(cat /etc/rc.d/rc.local_shutdown | sed -n '0,/^#I2P/p' | sed '$d' )
DATABOT=$(cat /etc/rc.d/rc.local_shutdown | sed -n '/^#I2P/,$p' | sed -n '/^fi/,$p' | sed "1d")
echo "${DATATOP}" > /etc/rc.d/rc.local_shutdown
echo '#I2P' >> /etc/rc.d/rc.local_shutdown
echo "if [ -x /etc/rc.d/rc.i2p ] ; then" >> /etc/rc.d/rc.local_shutdown
echo " sh /etc/rc.d/rc.i2p stop" >> /etc/rc.d/rc.local_shutdown
echo "fi" >> /etc/rc.d/rc.local_shutdown
echo "#/I2P" >> /etc/rc.d/rc.local_shutdown
echo "${DATABOT}" >> /etc/rc.d/rc.local_shutdown
echo -n "additional modifications applied,"
else
echo -n "looks OK so far,"
fi
echo " Done."
fi
if [ -f /etc/rc.d/rc.i2p ] ; then
if [ -x /etc/rc.d/rc.i2p ] ; then
chmod +x /etc/rc.d/rc.i2p.new
fi
# Hopefully get admin's attention.
echo -ne "\007" ; sleep 0.3
echo -ne "\007" ; sleep 0.3
echo -ne "\007" ; sleep 0.3
echo -ne "\007" ; sleep 0.3
echo -ne "\007" ; sleep 0.3
echo -ne "\007" ; sleep 0.3
echo -e "\007" ; sleep 0.3
echo "It apears that you already have /etc/rc.d/rc.i2p"
echo "You should replace it with /etc/rc.d/rc.i2p.new as soon as possible"
echo -ne "\007" ; sleep 0.3
echo -ne "\007" ; sleep 0.3
echo -ne "\007" ; sleep 0.3
echo -ne "\007" ; sleep 0.3
echo -ne "\007" ; sleep 0.3
echo -ne "\007" ; sleep 0.3
echo -e "\007" ; sleep 0.3
else
mv /etc/rc.d/rc.i2p.new /etc/rc.d/rc.i2p
echo
echo "Installation finished. The i2p start/stop script has been"
echo "installed in /etc/rc.d . You should chmod +x"
echo '/etc/rc.d/rc.i2p to start it on boot.'
echo
fi
exit

View File

@ -1,57 +0,0 @@
#!/bin/sh
#
# Heavily based on the Slackware 12.2 SlackBuild
# Slackware build script for I2P
#
# PLEASE READ THIS:
# How to start I2P:
# After installpkg command, doinst.sh will execute a post-installation script
# needed by I2P. After that you have to chmod +x /etc/rc.d/rc.i2p and start
# I2P service with /etc/rc.d/rc.i2p start.
#
# Now tell your browser to user this proxy: localhost on port 4444 and open
# this page: http://localhost:7657/index.jsp
#
# Here you can configure I2P, watch network status and navigate anonimously.
# It's suggested to subscribe to various dns host, like i2host.i2p
# For any additional information, visit i2host.i2p and forum.i2p
#
CWD=$(pwd)
TMP=/tmp
PKG=/$TMP/package-base-i2p
NAME=i2p-base
VERSION=0.0.4
BUILD=1sponge
ARCH=noarch
INSTALL_DIR=opt
# Less than slackware 13?
SLKPLT=$(cat /etc/slackware-version | sed -re "s/(Slackware )([0-9]*)(.*)/\2/")
if [ $SLKPLT -lt 13 ] ; then
EXT=tgz
else
EXT=txz
fi
rm -rf $PKG
mkdir -p $PKG
cd $PKG
chown -R root:root .
mkdir -p $PKG/etc/rc.d
mkdir -p $PKG/install
sed "s|directory|/$INSTALL_DIR/i2p/i2prouter|g" "$CWD/rc.i2p_def" > $PKG/etc/rc.d/rc.i2p.new
chmod 644 $PKG/etc/rc.d/rc.i2p.new
cat "$CWD/doinst.sh" > $PKG/install/doinst.sh
cat "$CWD/slack-desc" > $PKG/install/slack-desc
cd $PKG
#
# Not really that important to exec this
# as there aren't any deps we don't know.
#
# requiredbuilder -v -y -s $CWD $PKG
#
cat "$CWD/slack-required" > $PKG/install/slack-required
makepkg -l y -c n $CWD/${NAME}-$VERSION-$ARCH-$BUILD.$EXT

View File

@ -1,68 +0,0 @@
#!/bin/sh
# Start/stop i2p service.
i2p_start() {
# Check if router is up first!
/bin/su - -c "/bin/bash -l -c '( export PATH=\"$PATH:/usr/lib/java/bin:/usr/lib/java/jre/bin\" ; directory status )'" > /dev/null
if [ $? -eq 0 ] ; then {
# I2p is already running, so tell the user.
echo "I2P is already running..."
i2p_status
}
else
{
# Just in-case there are leftover junk in /tmp...
rm -Rf `grep /tmp/hsperfdata_root/* -le i2p` /tmp/i2p-*.tmp /tmp/router.ping
# Now that all junk is cleaned up, start.
/bin/su - -c "/bin/bash -l -c '( export PATH=\"$PATH:/usr/lib/java/bin:/usr/lib/java/jre/bin\" ; directory start )'"
}
fi
}
i2p_stop() {
/bin/su - -c "/bin/bash -l -c '( export PATH=\"$PATH:/usr/lib/java/bin:/usr/lib/java/jre/bin\" ; directory stop )'"
rm -Rf `grep /tmp/hsperfdata_root/* -le i2p` /tmp/i2p-*.tmp /tmp/router.ping
}
i2p_restart() {
# We want a FULL cycle here, not the wrappers idea of this!
i2p_stop
i2p_start
}
i2p_status() {
/bin/su - -c "/bin/bash -l -c '( export PATH=\"$PATH:/usr/lib/java/bin:/usr/lib/java/jre/bin\" ; directory status )'"
}
i2p_console() {
/bin/su - -c "/bin/bash -l -c '( export PATH=\"$PATH:/usr/lib/java/bin:/usr/lib/java/jre/bin\" ; directory console )'"
}
i2p_dump() {
/bin/su - -c "/bin/bash -l -c '( export PATH=\"$PATH:/usr/lib/java/bin:/usr/lib/java/jre/bin\" ; directory dump )'"
}
case "$1" in
'start')
i2p_start
;;
'stop')
i2p_stop
;;
'restart')
i2p_restart
;;
'status')
i2p_status
;;
'console')
i2p_console
;;
'dump')
i2p_dump
;;
*)
echo "usage $0 start|stop|restart|status|console|dump"
;;
esac

View File

@ -1,10 +0,0 @@
An rc file called rc.i2p has been placed into the /etc/rc.d directory.
If you want to change installation dir, change the variable INSTALL_DIR
on base-i2p.SlackBuild and rebuild the package. You also will need to do the
same for the i2p package.
The install script will insert everything needed into /etc/rc.d/rc.local and
into /etc/rc.d/rc.local_shutdown automatically.
If you want to start I2P at boot you have to chmod +x /etc/rc.d/rc.i2p

View File

@ -1,19 +0,0 @@
# HOW TO EDIT THIS FILE:
# The "handy ruler" below makes it easier to edit a package description. Line
# up the first '|' above the ':' following the base package name, and the '|' on
# the right side marks the last column you can put a character in. You must make
# exactly 11 lines for the formatting to be correct. It's also customary to
# leave one space after the ':'.
|-----handy-ruler------------------------------------------------------|
base-i2p: base-i2p (I2P anonymizing network base config files)
base-i2p:
base-i2p: I2P is an anonymizing network, offering a simple layer that
base-i2p: identity-sensitive applications can use to securely communicate. All
base-i2p: data is wrapped with several layers of encryption, and the network is
base-i2p: both distributed and dynamic, with no trusted parties.
base-i2p: Many applications are available that interface with I2P, including
base-i2p: mail, peer-peer file sharing, IRC chat, and others.
base-i2p:
base-i2p: This package provides the startup files.
base-i2p:

View File

@ -1 +0,0 @@
bash >= 3.1.017

View File

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<project basedir="." default="slackpkg">
<target name="slackpkg">
<echo message="Building Slackware package." />
<exec executable="./i2p.SlackBuild">
</exec>
</target>
</project>

View File

@ -1,72 +0,0 @@
#!/bin/sh
INST_DIR=directory
( cd install
echo
for i in *.config ; {
if [ -f $INST_DIR/$i ] ; then
echo "Please check ${INST_DIR}${i}, as there is a new version."
cp $i $INST_DIR/$i.new
else
cp $i $INST_DIR/$i
fi
}
)
( cd $INST_DIR
if [ -f blocklist.txt ] ; then
echo "Please check ${INST_DIR}blocklist.txt, as there is a new version."
else
mv blocklist.txt.new blocklist.txt
fi
)
( cd $INST_DIR/eepsite
if [ -f jetty.xml ] ; then
rm jetty.xml.new
else
mv jetty.xml.new jetty.xml
fi
)
( cd $INST_DIR/eepsite/docroot
if [ -f index.html ] ; then
rm index.html.new
else
mv index.html.new index.html
fi
if [ -f favicon.ico ] ; then
rm favicon.ico.new
else
mv favicon.ico.new favicon.ico
fi
)
echo
echo "FINISHING I2P INSTALLATION. PLEASE WAIT."
cd $INST_DIR
OS_ARCH=`uname -m`
X86_64=`echo "$OS_ARCH" | grep x86_64`
if [ "X$X86_64" = "X" ]; then
wrapperpath="./lib/wrapper/linux"
else
wrapperpath="./lib/wrapper/linux64"
fi
cp $wrapperpath/libwrapper.so ./lib/
cp $wrapperpath/wrapper.jar ./lib/
cp $wrapperpath/i2psvc .
rm -rf ./lib/wrapper
chmod 744 ./i2psvc
echo
echo "Installation finished."
echo
exit

View File

@ -1,133 +0,0 @@
#!/bin/sh
#
# Heavily based on the Slackware 12.2 SlackBuild
# Slackware build script for I2P
#
# PLEASE READ THIS:
# Probably you will never have to update I2P packages with upgradepkg,
# just because I2P has an auto-update function.
# Really you should not ever use any "upgrade" method.
#
# The correct way to upgrade is to:
# 1: install the upgrade
# 2: remove the old package
#
# It is a terrible shame that upgradepkg doesn't do this, infact,
# it would actually be the correct way for *any* package!
#
#
BUILD=1sponge
INSTALL_DIR=opt
NAME=i2p
ARCH=noarch
# Less than slackware 13?
SLKPLT=$(cat /etc/slackware-version | sed -re "s/(Slackware )([0-9]*)(.*)/\2/")
if [ $SLKPLT -lt 13 ] ; then
EXT=tgz
else
EXT=txz
fi
#
# This mess is here due to the totally moronic way i2p does versioning.
# We correct it here.
#
ROUTER=$(echo -ne "_")$(cat ../../router/java/src/net/i2p/router/RouterVersion.java | grep -e "public final static long BUILD" | cut -f2 -d"=" | cut -f1 -d";" | sed -re "s/ //g")
if [ "$ROUTER" == "_" ] ; then
ROUTER="_0"
fi
#
# That was the easy one, now for the tough one.
#
CORE=$(cat ../../core/java/src/net/i2p/CoreVersion.java | grep -e "public final static String VERSION" | cut -f2 -d'"' | sed -re "s/ //g")
CORE1=$(echo -n $CORE.x.x | sed -re "s/(.*)\.(.*)\.(.*)\.(.*)/\1/")
CORE2=$(echo -n $CORE.x | sed -re "s/(.*)\.(.*)\.(.*)\.(.*)/\1/")
if [ "$CORE.x.x" == "$CORE1" ] ; then
CORE=$(echo -ne $CORE".0.0")
fi
if [ "$CORE.x" == "$CORE2" ] ; then
CORE=$(echo -ne $CORE".0")
fi
VERSION=$(echo $CORE$ROUTER)
#
# Whew!
# OK, let's build i2p
#
CWD=$(pwd)
TMP=/tmp
PKG=$TMP/package-i2p
rm -rf $PKG
mkdir -p $PKG
cd $CWD/../../
ant distclean
#ant dist
ant tarball
tar xjvf i2p.tar.bz2 -C $TMP
cd $TMP/i2p
chown -R root:root .
mkdir -p $PKG/$INSTALL_DIR/
cp -a ../i2p $PKG/$INSTALL_DIR/
mkdir -p $PKG/install
#############################################################################
# Preconfigureation to make package smaller, and...
# we keep as much as reasonable in the installation directory.
# This makes the install map fairly well to the standard installation.
# It also makes it easier to find the log and pid files!
#############################################################################
cd $PKG/$INSTALL_DIR/i2p
# wrapper.config $INSTALL_PATH and $SYSTEM_java_io_tmpdir
sed "s|\$INSTALL_PATH|/$INSTALL_DIR/i2p|g" wrapper.config > a
sed "s|\$SYSTEM_java_io_tmpdir|/$INSTALL_DIR/i2p|g" a > wrapper.config
# eepget %INSTALL_PATH
sed "s|\$INSTALL_PATH|/$INSTALL_DIR/i2p|g" eepget > a
rm eepget
mv a eepget
# runplain.sh %INSTALL_PATH and %SYSTEM_java_io_tmpdir
sed "s|%INSTALL_PATH|/$INSTALL_DIR/i2p|g" runplain.sh > a
sed "s|%SYSTEM_java_io_tmpdir|/$INSTALL_DIR/i2p|g" a > runplain.sh
# i2prouter %INSTALL_PATH and %SYSTEM_java_io_tmpdir
sed "s|%INSTALL_PATH|/$INSTALL_DIR/i2p|g" i2prouter > a
sed "s|%SYSTEM_java_io_tmpdir|/$INSTALL_DIR/i2p|g" a > i2prouter
chmod 744 ./i2prouter
chmod 744 ./osid
chmod 744 ./runplain.sh
chmod 744 ./eepget
chmod 744 ./scripts/i2pbench.sh
chmod 744 ./scripts/i2ptest.sh
rm -Rf ./lib/*.dll ./*.bat ./*.exe ./installer ./icons ./a postinstall.sh
mv $PKG/$INSTALL_DIR/i2p/*.config $PKG/install
mv $PKG/$INSTALL_DIR/i2p/blocklist.txt $PKG/$INSTALL_DIR/i2p/blocklist.txt.new
mv $PKG/$INSTALL_DIR/i2p/eepsite/jetty.xml $PKG/$INSTALL_DIR/i2p/eepsite/jetty.xml.new
mv $PKG/$INSTALL_DIR/i2p/eepsite/docroot/index.html $PKG/$INSTALL_DIR/i2p/eepsite/docroot/index.html.new
mv $PKG/$INSTALL_DIR/i2p/eepsite/docroot/favicon.ico $PKG/$INSTALL_DIR/i2p/eepsite/docroot/favicon.ico.new
sed "s|directory|/$INSTALL_DIR/i2p/|g" $CWD/doinst.sh > $PKG/install/doinst.sh
cat $CWD/slack-desc > $PKG/install/slack-desc
cd $PKG
#
# requiredbuilder fucks up REALLY bad, and thinks java is perl?!
# It also did not catch the shell requirements! BOOOOOOOOOOO! HISSSSSSSS!
#
# requiredbuilder -v -y -s $CWD $PKG
#
cat $CWD/slack-required > $PKG/install/slack-required
makepkg -l y -c n $CWD/${NAME}-$VERSION-$ARCH-$BUILD.$EXT

View File

@ -1,47 +0,0 @@
Building:
The i2p package will be installed in /opt/i2p
If you want to change installation dir, change the variable INSTALL_DIR
on i2p.SlackBuild and rebuild the package. You will also need to do the same
in the base-i2p package.
Installation and Upgrade:
Probably you will never have to update i2p packages. However if you do,
be sure to installpkg first, then removepkg or custom config files can
be lost with upgradepkg. I2P has an auto-update function. However using
installpkg then removepkg lowers the demand on the I2P network as a
whole, and is by far faster.
After installpkg command, doinst.sh will execute a postinstallation script
needed by I2P. Be sure to also install the base-i2p package.
Optional:
chmod +x /etc/rc.d/rc.i2p only if you want it to start on boot and stop on
shutdown.
How to start I2P:
Start I2P service with-
sh /etc/rc.d/rc.i2p start
Now tell your browser to user this proxy: localhost on port 4444 and open
this page: http://localhost:7657/index.jsp
Here you can configure I2P, watch network status and navigate anonimously.
It's suggested to subscribe to various addressbook hosts so that you can
get to the many available eepsites and other service on I2P. These are not
set up by default for security reasons.
Please see the faqs on http://www.i2p2.i2p/ or http://www.i2p2.de/ on how
to subscribe to the various addressbook services.
To stop I2P:
/etc/rc.d/rc.i2p stop
For any additional information:
Within I2P- http://www.i2p2.i2p/, http://forum.i2p/, http://zzz.i2p
Internet (not reccomended!) - http://www.i2p2.de/, http://forum.i2p2.de/

View File

@ -1,19 +0,0 @@
# HOW TO EDIT THIS FILE:
# The "handy ruler" below makes it easier to edit a package description. Line
# up the first '|' above the ':' following the base package name, and the '|' on
# the right side marks the last column you can put a character in. You must make
# exactly 11 lines for the formatting to be correct. It's also customary to
# leave one space after the ':'.
|-----handy-ruler----------------------------------------------------------|
i2p: i2p (an anonymizing network)
i2p:
i2p: I2P is an anonymizing network, offering a simple layer that
i2p: identity-sensitive applications can use to securely communicate. All
i2p: data is wrapped with several layers of encryption, and the network is
i2p: both distributed and dynamic, with no trusted parties.
i2p: Many applications are available that interface with I2P, including
i2p: mail, peer-peer file sharing, IRC chat, and others.
i2p: WARNING: To upgrade installpkg FIRST _THEN_ removepkg.
i2p: For more information, see: http://www.i2p2.de/
i2p:

View File

@ -1,4 +0,0 @@
jre >= 5
i2p-base >= 0.0.1
bash >= 3.1.017

105
TODO Normal file
View File

@ -0,0 +1,105 @@
# Fixes
- Create tunnel wizard
<zzz> hmm would be nice if they could be shared-client or have an option
<zzz> was setting up email tunnels
- Browser
<zzzccc> Bug report: i2p browser treats 302 as an error
<zzzccc> Bug 2: rotate screen in i2p browser seems to go back one page
- Console text change
<zzz> "download" and "upload" at the bottom of the status is a little misleading..
<zzz> maybe 'downstream bandwidth' or 'inbound usage' ?
- Fix visibility of advanced tunnel parameter changes
<zzz> when I change an advanced tunnel param e.g. length or variance, the change isn't displayed, I have to go back and forward again to see the change
# New UI fixes
- Addressbook action items are in tunnel overflow menu after moving from console to tunnels
- Material design:
- Style for addressbook headers
- Change console FAM icon when possible
<zzz> on the bottom right, the + and x icons might be better as a double-up arrow and double-down arrow?
# Short-term
- Disable uPnP when on cell networks
<zzz> spewing UPnP out into cell networks is a waste of time at best and a security risk at worst, but you really want it for wifi
- I2PTunnel
- Improve tunnel list status indicators
- Show all messages somewhere
- Icons/header images for tunnel types on details page
- Progress feedback for addressbook subscriptions reload
- Display release notes directly on new router version
- Fill out help pages
- Rewrite release notes to be release-specific
- Fix release notes UI, either make back button use clear or add buttons
- NetDB tablet view fixes
- Refresh detail fragment when changing tab
- Move list to correct item when changing tab
- Create nav history when viewing RI from LS
- Include GeoIP db for country info
- Maybe change router-off mechanic for various pages? Enable as they become available?
# Medium-term
- Network profiles
- User selects profile in settings
- Change network participation etc. based on profile
- Also look at connection type: Connectivity.isConnectionFast()
- Expose log level overrides
- Improve graphs
- Show fixed x range, not only available data
- Think about pan/zoom
- How to persist data across restarts?
# Silent Store approval checks to confirm/implement
- Known Vulnerabilities
- Apps will be tested to ensure that they are not susceptible to known
publicly disclosed vulnerabilities. For example:
- Heartbleed
- Poodle
- MasterKey
- Common Path Traversal attacks
- Common SQL Injection attacks
- Network Security Protocols
- All Apps that require transmission of data from the App to a system that
does not exist on the device must use, at a minimum, TLS1.1 standards.
However, Blackphone would prefer the usage of TLS1.2.
- Apps must not use algorithms for cryptographic purposes that are considered
obsolete or outdated i.e. MD5, SHA1, RC4, DES, or any encryption algorithm
that is weaker than AES128.
- Transport Layer Protection
- All network communication should be encrypted
- Not vulnerable to SSl Strip
- Data Leakage
- No storage of sensitive data outside of application sandbox
- Files should not be created with MODE_WORLD_READABLE or MODE_WORLD_WRITABLE
- Copy & Paste will be evaluated on a case by case basis
- App logs should not contain sensitive information
- Authentication and Authorization
- Validate that authentication credentials are not stored on the device
- Must use an approved password-based key derivation function ie. PBKDF2, scrypt
- Data-at-rest Encryption
- Must use at a minimum AES128 with modes CCM or GCM
- Should not store the encryption key on the file system
- Permission Checks
- The App must function with all permissions disabled
- Apps must not hard crash if a permission is disabled
- Apps should ask users to enable permissions that are disabled if needed to
function properly and explain why the permission is necessary
- Privacy Policy
- Apps must have a privacy policy that details how customer data is used,
stored, shared, etc...
- Apps must be configured with the customer opted out by default
- App logs should not contain PII
- Error Handling
- Apps should follow best-practices for error handling and logging
# Long-term
- Remote router support
- Implement a "router wrapper" that can represent a local or remote router
- Implement/use client APIs to talk to remote router
- I2CP
- I2PControl

View File

@ -1,19 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="net.i2p.router"
android:versionCode="1"
android:versionName="1.0.0">
<uses-permission android:name="android.permission.INTERNET" />
<!-- 3 = 1.5, 2 = 1.1, 1 = 1.0; would probably work with 1 but don't have a 1.0 SDK to test against -->
<uses-sdk android:minSdkVersion="2" />
<application android:label="@string/app_name">
<activity android:name=".I2PAndroid"
android:label="@string/app_name"
android:launchMode="singleTask" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

View File

@ -1,38 +0,0 @@
These instructions are for a recent Android SDK (1.6 or later)..
Should also still work with a 1.5 SDK.
The build file is not compatible with the 1.1 SDK any more.
#Download the SDK from http://developer.android.com/sdk/index.html
#Unzip the android SDK in ../../
#So then the android tools will be in ../../android-sdk-linux_86/tools/
#
# now go to the available packages tab, check the box and click refresh,
# and download an SDK Platform
# Since I2P is configured to run on 1.1 or higher
# (API 2) download that one. Otherwise you must change the
# target in default.properties from android-2 to andriod-x
# where x is the API version.
# create a file local.properties with the following line:
# sdk-location=/path/to/your/android-sdk-linux_86
#then build the android apk file:
ant debug
# Create the android 1.1 (API 2) virtual device
# (don't make a custom hardware profile)
# A AVD created with the 1.5 SDK will not work with the newer tools
../../android-sdk-linux_86/tools/android create avd --name i2p --target 2
#then run the emulator:
../../android-sdk-linux_86/tools/emulator -avd i2p &
#then wait a couple minutes until the emulator is up
#then install the I2P app
ant install
#then run the debugger
../../android-sdk-linux_86/tools/ddms &
#to rebuild and reinstall to emulator:
ant reinstall

View File

@ -1,356 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project name=".I2PAndroid" default="help">
<!-- The local.properties file is created and updated by the 'android' tool.
It contain the path to the SDK. It should *NOT* be checked in in Version
Control Systems. -->
<property file="local.properties"/>
<!-- The build.properties file can be created by you and is never touched
by the 'android' tool. This is the place to change some of the default property values
used by the Ant rules.
Here are some properties you may want to change/update:
application-package
the name of your application package as defined in the manifest. Used by the
'uninstall' rule.
source-folder
the name of the source folder. Default is 'src'.
out-folder
the name of the output folder. Default is 'bin'.
Properties related to the SDK location or the project target should be updated
using the 'android' tool with the 'update' action.
This file is an integral part of the build system for your application and
should be checked in in Version Control Systems.
-->
<property file="build.properties"/>
<!-- The default.properties file is created and updated by the 'android' tool, as well
as ADT.
This file is an integral part of the build system for your application and
should be checked in in Version Control Systems. -->
<property file="default.properties"/>
<!-- Custom Android task to deal with the project target, and import the proper rules.
This requires ant 1.6.0 or above. -->
<path id="android.antlibs">
<pathelement path="${sdk-location}/tools/lib/anttasks.jar" />
<pathelement path="${sdk-location}/tools/lib/sdklib.jar" />
<pathelement path="${sdk-location}/tools/lib/androidprefs.jar" />
<pathelement path="${sdk-location}/tools/lib/apkbuilder.jar" />
<pathelement path="${sdk-location}/tools/lib/jarutils.jar" />
</path>
<taskdef name="setup"
classname="com.android.ant.SetupTask"
classpathref="android.antlibs"/>
<!-- Execute the Android Setup task that will setup some properties specific to the target,
and import the rules files.
To customize the rules, copy/paste them below the task, and disable import by setting
the import attribute to false:
<setup import="false" />
This will ensure that the properties are setup correctly but that your customized
targets are used.
-->
<setup import="false" />
<!--
================================================================================
New I2P rules
================================================================================
-->
<target name="buildrouter" depends="dirs" >
<!-- build router and core -->
<ant dir=".." target="buildrouter" />
<!-- router -->
<copy file="../build/router.jar" todir="${external-libs-folder}" />
<!-- core -->
<mkdir dir="tmp" />
<unjar src="../build/i2p.jar" dest="tmp/" />
<delete file="tmp/net/i2p/util/LogWriter.class" />
<!-- org.bouncycastle.crypto already in android
but we need a little trickery because our HMac is incompatible...
and the libs aren't in the SDK to compile against??? -->
<jar destfile="${external-libs-folder}/crypto.jar" >
<fileset dir="tmp/" >
<include name="org/bouncycastle/crypto/Digest.class" />
<include name="org/bouncycastle/crypto/Mac.class" />
<include name="org/bouncycastle/crypto/digests/GeneralDigest.class" />
<include name="org/bouncycastle/crypto/digests/MD5Digest.class" />
</fileset>
</jar>
<delete>
<fileset dir="tmp/" >
<include name="org/bouncycastle/crypto/Digest.class" />
<include name="org/bouncycastle/crypto/Mac.class" />
<include name="org/bouncycastle/crypto/digests/GeneralDigest.class" />
<include name="org/bouncycastle/crypto/digests/MD5Digest.class" />
</fileset>
</delete>
<!--
<delete dir="tmp/org/bouncycastle/" />
<delete file="tmp/net/i2p/crypto/HMACGenerator.class" />
-->
<delete file="tmp/org/bouncycastle/" />
<!-- lots of unneeded stuff could be deleted here -->
<jar destfile="${external-libs-folder}/i2p.jar" basedir="tmp/" />
<!-- some resources -->
<mkdir dir="res/drawable/" />
<copy file="../installer/resources/themes/console/images/i2plogo.png" todir="res/drawable/" />
<copy file="../installer/resources/blocklist.txt" tofile="res/raw/blocklist_txt" />
</target>
<target name="hackcleanup">
<delete file="${external-libs-folder}/crypto.jar" />
</target>
<!-- fix for property name change sometime after SDK 1.5 -->
<property name="android-jar" value="${android.jar}" />
<property name="android-aidl" value="${android.aidl}" />
<!--
================================================================================
From here down copied from SDK platforms/android-1.1/templates/android_rules.xml
and then modified
================================================================================
-->
<!--
This rules file is meant to be imported by the custom Ant task:
com.android.ant.AndroidInitTask
The following properties are put in place by the importing task:
android-jar, android-aidl, aapt, aidl, and dx
Additionnaly, the task sets up the following classpath reference:
android.target.classpath
This is used by the compiler task as the boot classpath.
-->
<!-- Custom tasks -->
<taskdef name="aaptexec"
classname="com.android.ant.AaptExecLoopTask"
classpathref="android.antlibs"/>
<taskdef name="apkbuilder"
classname="com.android.ant.ApkBuilderTask"
classpathref="android.antlibs"/>
<!-- Properties -->
<property name="android-tools" value="${sdk-location}/tools" />
<!-- Input directories -->
<property name="source-folder" value="src" />
<property name="gen-folder" value="gen" />
<property name="resource-folder" value="res" />
<property name="asset-folder" value="assets" />
<property name="source-location" value="${basedir}/${source-folder}" />
<!-- folder for the 3rd party java libraries -->
<property name="external-libs-folder" value="libs" />
<!-- folder for the native libraries -->
<property name="native-libs-folder" value="libs" />
<!-- Output directories -->
<property name="gen-folder" value="gen" />
<property name="out-folder" value="bin" />
<property name="out-classes" value="${out-folder}/classes" />
<property name="out-classes-location" value="${basedir}/${out-classes}"/>
<!-- out folders for a parent project if this project is an instrumentation project -->
<property name="main-out-folder" value="../${out-folder}" />
<property name="main-out-classes" value="${main-out-folder}/classes"/>
<!-- Intermediate files -->
<property name="dex-file" value="classes.dex" />
<property name="intermediate-dex" value="${out-folder}/${dex-file}" />
<!-- dx does not properly support incorrect / or \ based on the platform
and Ant cannot convert them because the parameter is not a valid path.
Because of this we have to compute different paths depending on the platform. -->
<condition property="intermediate-dex-location"
value="${basedir}\${intermediate-dex}"
else="${basedir}/${intermediate-dex}" >
<os family="windows"/>
</condition>
<!-- The final package file to generate -->
<property name="out-debug-package" value="${out-folder}/${ant.project.name}-debug.apk"/>
<!-- Tools -->
<condition property="exe" value=".exe" else=""><os family="windows"/></condition>
<property name="adb" value="${android-tools}/adb${exe}"/>
<!-- rules -->
<!-- Create the output directories if they don't exist yet. -->
<target name="dirs">
<echo>Creating output directories if needed...</echo>
<mkdir dir="${resource-folder}" />
<mkdir dir="${external-libs-folder}" />
<mkdir dir="${gen-folder}" />
<mkdir dir="${out-folder}" />
<mkdir dir="${out-classes}" />
</target>
<!-- Generate the R.java file for this project's resources. -->
<target name="resource-src" depends="dirs">
<echo>Generating R.java / Manifest.java from the resources...</echo>
<exec executable="${aapt}" failonerror="true">
<arg value="package" />
<arg value="-m" />
<arg value="-J" />
<arg path="${gen-folder}" />
<arg value="-M" />
<arg path="AndroidManifest.xml" />
<arg value="-S" />
<arg path="${resource-folder}" />
<arg value="-I" />
<arg path="${android-jar}" />
</exec>
</target>
<!-- Generate java classes from .aidl files. -->
<target name="aidl" depends="dirs">
<echo>Compiling aidl files into Java classes...</echo>
<apply executable="${aidl}" failonerror="true">
<arg value="-p${android-aidl}" />
<arg value="-I${source-folder}" />
<arg value="-o${gen-folder}" />
<fileset dir="${source-folder}">
<include name="**/*.aidl"/>
</fileset>
</apply>
</target>
<!-- Compile this project's .java files into .class files. -->
<!-- I2P add buildrouter -->
<target name="compile" depends="buildrouter, resource-src, aidl">
<javac encoding="ascii" target="1.5" debug="true" extdirs=""
destdir="${out-classes}"
bootclasspathref="android.target.classpath">
<src path="${source-folder}" />
<src path="${gen-folder}" />
<classpath>
<fileset dir="${external-libs-folder}" includes="*.jar"/>
<pathelement path="${main-out-classes}"/>
</classpath>
</javac>
</target>
<!-- Convert this project's .class files into .dex files. -->
<!-- I2P add hackcleanup -->
<target name="dex" depends="compile, hackcleanup">
<echo>Converting compiled files and external libraries into ${out-folder}/${dex-file}...</echo>
<apply executable="${dx}" failonerror="true" parallel="true">
<!-- I2P this is a bad sign that we need this -->
<arg value="-JXmx256m" />
<arg value="--dex" />
<arg value="--output=${intermediate-dex-location}" />
<arg path="${out-classes-location}" />
<fileset dir="${external-libs-folder}" includes="*.jar"/>
</apply>
</target>
<!-- Put the project's resources into the output package file
This actually can create multiple resource package in case
Some custom apk with specific configuration have been
declared in default.properties.
-->
<target name="package-resources">
<echo>Packaging resources</echo>
<aaptexec executable="${aapt}"
command="package"
manifest="AndroidManifest.xml"
resources="${resource-folder}"
assets="${asset-folder}"
androidjar="${android-jar}"
outfolder="${out-folder}"
basename="${ant.project.name}" />
</target>
<!-- Package the application and sign it with a debug key.
This is the default target when building. It is used for debug. -->
<target name="debug" depends="dex, package-resources">
<apkbuilder
outfolder="${out-folder}"
basename="${ant.project.name}"
signed="true"
verbose="false">
<file path="${intermediate-dex}" />
<sourcefolder path="${source-folder}" />
<jarfolder path="${external-libs-folder}" />
<nativefolder path="${native-libs-folder}" />
</apkbuilder>
</target>
<!-- Package the application without signing it.
This allows for the application to be signed later with an official publishing key. -->
<target name="release" depends="dex, package-resources">
<apkbuilder
outfolder="${out-folder}"
basename="${ant.project.name}"
signed="false"
verbose="false">
<file path="${intermediate-dex}" />
<sourcefolder path="${source-folder}" />
<jarfolder path="${external-libs-folder}" />
<nativefolder path="${native-libs-folder}" />
</apkbuilder>
<echo>All generated packages need to be signed with jarsigner before they are published.</echo>
</target>
<!-- Install the package on the default emulator -->
<target name="install" depends="debug">
<echo>Installing ${out-debug-package} onto default emulator...</echo>
<exec executable="${adb}" failonerror="true">
<arg value="install" />
<arg path="${out-debug-package}" />
</exec>
</target>
<target name="reinstall" depends="debug">
<echo>Installing ${out-debug-package} onto default emulator...</echo>
<exec executable="${adb}" failonerror="true">
<arg value="install" />
<arg value="-r" />
<arg path="${out-debug-package}" />
</exec>
</target>
<!-- Uinstall the package from the default emulator -->
<target name="uninstall">
<echo>Uninstalling ${application-package} from the default emulator...</echo>
<exec executable="${adb}" failonerror="true">
<arg value="uninstall" />
<arg path="${application-package}" />
</exec>
</target>
<target name="help">
<!-- displays starts at col 13
|13 80| -->
<echo>Android Ant Build. Available targets:</echo>
<echo> help: Displays this help.</echo>
<echo> debug: Builds the application and sign it with a debug key.</echo>
<echo> release: Builds the application. The generated apk file must be</echo>
<echo> signed before it is published.</echo>
<echo> install: Installs the debug package onto a running emulator or</echo>
<echo> device. This can only be used if the application has </echo>
<echo> not yet been installed.</echo>
<echo> reinstall: Installs the debug package on a running emulator or</echo>
<echo> device that already has the application.</echo>
<echo> The signatures must match.</echo>
<echo> uninstall: uninstall the application from a running emulator or</echo>
<echo> device.</echo>
</target>
</project>

View File

@ -1,11 +0,0 @@
# This file is automatically generated by Android Tools.
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
#
# This file must be checked in Version Control Systems.
#
# To customize properties used by the Ant build system use,
# "build.properties", and override values to adapt the script to your
# project structure.
# Project target.
target=android-2

View File

@ -1,18 +0,0 @@
<?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:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Hello World, I2PAndroid"
/>
<ImageView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:src="@drawable/i2plogo"
/>
</LinearLayout>

View File

@ -1,3 +0,0 @@
logger.defaultLevel=INFO
logger.record.net.i2p.router.transport.FIFOBandwidthRefiller=ERROR
logger.record.net.i2p.stat.Rate=ERROR

View File

@ -1,22 +0,0 @@
# initial router.config
# temp directory
i2p.dir.temp=/data/data/net.i2p.router/files/tmp
i2p.dir.pid=/data/data/net.i2p.router/files/tmp
# save memory
prng.buffers=2
router.decayingBloomFilterM=20
stat.full=false
i2np.udp.maxConnections=30
# no I2CP
i2p.dummyClientFacade=true
# for now
#i2np.ntcp.enable=false
#
# UDP crashes the JVM, don't know why
#
i2np.udp.enable=false
# no COMM at all!!!
#i2p.vmCommSystem=true
# not on android
i2np.upnp.enable=false
routerconsole.geoip.enable=false

View File

@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">I2PAndroid</string>
</resources>

View File

@ -1,142 +0,0 @@
package net.i2p.router;
import android.app.Activity;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.Resources.NotFoundException;
import android.os.Bundle;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.IOException;
import java.util.List;
import net.i2p.router.Router;
import net.i2p.router.RouterLaunch;
// import net.i2p.util.NativeBigInteger;
public class I2PAndroid extends Activity
{
static Context _context;
private static final String DIR = "/data/data/net.i2p.router/files";
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
_context = this; // Activity extends Context
debugStuff();
initialize();
// 300ms per run
// 5x slower than java on my server and 50x slower than native on my server
// NativeBigInteger.main(null);
}
public void onRestart()
{
System.err.println("onRestart called");
super.onRestart();
}
public void onStart()
{
System.err.println("onStart called");
super.onStart();
RouterLaunch.main(null);
System.err.println("Router.main finished");
}
public void onResume()
{
System.err.println("onResume called");
super.onResume();
}
public void onPause()
{
System.err.println("onPause called");
super.onPause();
}
public void onStop()
{
System.err.println("onStop called");
super.onStop();
// from routerconsole ContextHelper
List contexts = RouterContext.listContexts();
if ( (contexts == null) || (contexts.isEmpty()) )
throw new IllegalStateException("No contexts. This is usually because the router is either starting up or shutting down.");
RouterContext ctx = (RouterContext)contexts.get(0);
// shutdown() doesn't return so use shutdownGracefully()
ctx.router().shutdownGracefully(Router.EXIT_HARD);
System.err.println("shutdown complete");
}
public void onDestroy()
{
System.err.println("onDestroy called");
super.onDestroy();
}
public static Context getContext() {
return _context;
}
private void debugStuff() {
System.err.println("java.io.tmpdir" + ": " + System.getProperty("java.io.tmpdir"));
System.err.println("java.vendor" + ": " + System.getProperty("java.vendor"));
System.err.println("java.version" + ": " + System.getProperty("java.version"));
System.err.println("os.arch" + ": " + System.getProperty("os.arch"));
System.err.println("os.name" + ": " + System.getProperty("os.name"));
System.err.println("os.version" + ": " + System.getProperty("os.version"));
System.err.println("user.dir" + ": " + System.getProperty("user.dir"));
System.err.println("user.home" + ": " + System.getProperty("user.home"));
System.err.println("user.name" + ": " + System.getProperty("user.name"));
}
private void initialize() {
// Until we can edit the router.config on the device,
// copy it from the resource every time.
// File f = new I2PFile("router.config");
// if (!f.exists()) {
copyResourceToFile(R.raw.router_config, "router.config");
copyResourceToFile(R.raw.logger_config, "logger.config");
copyResourceToFile(R.raw.blocklist_txt, "blocklist.txt");
// }
// Set up the locations so Router and WorkingDir can find them
System.setProperty("i2p.dir.base", DIR);
System.setProperty("i2p.dir.config", DIR);
System.setProperty("wrapper.logfile", DIR + "/wrapper.log");
}
private void copyResourceToFile(int resID, String f) {
InputStream in = null;
FileOutputStream out = null;
System.err.println("Creating file " + f + " from resource");
byte buf[] = new byte[4096];
try {
// Context methods
in = getResources().openRawResource(resID);
out = openFileOutput(f, 0);
int read = 0;
while ( (read = in.read(buf)) != -1)
out.write(buf, 0, read);
} catch (IOException ioe) {
} catch (Resources.NotFoundException nfe) {
} finally {
if (in != null) try { in.close(); } catch (IOException ioe) {}
if (out != null) try { out.close(); } catch (IOException ioe) {}
}
}
}

View File

@ -1,163 +0,0 @@
package net.i2p.util;
/*
* public domain
*
*/
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.List;
/**
* bridge to android logging
*
* @author zzz
*/
class LogWriter implements Runnable {
private final static long CONFIG_READ_ITERVAL = 10 * 1000;
private long _lastReadConfig = 0;
private long _numBytesInCurrentFile = 0;
private OutputStream _currentOut; // = System.out
private int _rotationNum = -1;
private String _logFilenamePattern;
private File _currentFile;
private LogManager _manager;
private boolean _write;
private LogWriter() { // nop
}
public LogWriter(LogManager manager) {
_manager = manager;
}
public void stopWriting() {
_write = false;
}
public void run() {
_write = true;
try {
while (_write) {
flushRecords();
rereadConfig();
}
System.err.println("Done writing");
} catch (Exception e) {
System.err.println("Error writing the logs: " + e.getMessage());
e.printStackTrace();
}
}
public void flushRecords() { flushRecords(true); }
public void flushRecords(boolean shouldWait) {
try {
List records = _manager._removeAll();
if (records == null) return;
for (int i = 0; i < records.size(); i++) {
LogRecord rec = (LogRecord) records.get(i);
writeRecord(rec);
}
} catch (Throwable t) {
t.printStackTrace();
} finally {
if (shouldWait) {
try {
synchronized (this) {
this.wait(10*1000);
}
} catch (InterruptedException ie) { // nop
}
}
}
}
public String currentFile() {
return _currentFile != null ? _currentFile.getAbsolutePath() : "uninitialized";
}
private void rereadConfig() {
long now = Clock.getInstance().now();
if (now - _lastReadConfig > CONFIG_READ_ITERVAL) {
_manager.rereadConfig();
_lastReadConfig = now;
}
}
private void writeRecord(LogRecord rec) {
if (rec.getThrowable() == null)
log(rec.getPriority(), rec.getSource(), rec.getSourceName(), rec.getThreadName(), rec.getMessage());
else
log(rec.getPriority(), rec.getSource(), rec.getSourceName(), rec.getThreadName(), rec.getMessage(), rec.getThrowable());
}
public void log(int priority, Class src, String name, String threadName, String msg) {
if (src != null) {
String tag = src.getName();
int dot = tag.lastIndexOf(".");
if (dot >= 0)
tag = tag.substring(dot + 1);
android.util.Log.println(toAndroidLevel(priority),
tag,
'[' + threadName + "] " + msg);
} else if (name != null)
android.util.Log.println(toAndroidLevel(priority),
name,
'[' + threadName + "] " + msg);
else
android.util.Log.println(toAndroidLevel(priority),
threadName, msg);
}
public void log(int priority, Class src, String name, String threadName, String msg, Throwable t) {
if (src != null) {
String tag = src.getName();
int dot = tag.lastIndexOf(".");
if (dot >= 0)
tag = tag.substring(dot + 1);
android.util.Log.println(toAndroidLevel(priority),
tag,
'[' + threadName + "] " + msg +
' ' + t.toString() + ' ' + android.util.Log.getStackTraceString(t));
} else if (name != null)
android.util.Log.println(toAndroidLevel(priority),
name,
'[' + threadName + "] " + msg +
' ' + t.toString() + ' ' + android.util.Log.getStackTraceString(t));
else
android.util.Log.println(toAndroidLevel(priority),
threadName,
msg + ' ' + t.toString() + ' ' + android.util.Log.getStackTraceString(t));
}
private static int toAndroidLevel(int level) {
switch (level) {
case Log.DEBUG:
return android.util.Log.DEBUG;
case Log.INFO:
return android.util.Log.INFO;
case Log.WARN:
return android.util.Log.WARN;
case Log.ERROR:
case Log.CRIT:
default:
return android.util.Log.ERROR;
}
}
private static final String replace(String pattern, int num) {
char c[] = pattern.toCharArray();
StringBuffer buf = new StringBuffer();
for (int i = 0; i < c.length; i++) {
if ( (c[i] != '#') && (c[i] != '@') )
buf.append(c[i]);
else
buf.append(num);
}
return buf.toString();
}
}

238
app/build.gradle Normal file
View File

@ -0,0 +1,238 @@
apply plugin: 'com.android.application'
apply plugin: 'witness'
android {
compileSdkVersion Integer.parseInt(project.ANDROID_BUILD_SDK_VERSION as String)
buildToolsVersion project.ANDROID_BUILD_TOOLS_VERSION as String
defaultConfig {
versionCode 4745230
versionName '0.9.20'
minSdkVersion 9
targetSdkVersion Integer.parseInt(project.ANDROID_BUILD_TARGET_SDK_VERSION as String)
// For Espresso
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
signingConfigs {
release
}
buildTypes {
release {
signingConfig signingConfigs.release
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
}
debug {
applicationIdSuffix '.debug'
versionNameSuffix '-DEBUG'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_7
targetCompatibility JavaVersion.VERSION_1_7
}
lintOptions {
abortOnError false
}
packagingOptions {
exclude 'LICENSE.txt'
}
productFlavors {
free {
applicationId 'net.i2p.android'
}
donate {
applicationId 'net.i2p.android.donate'
}
legacy {
applicationId 'net.i2p.android.router'
}
}
}
dependencies {
// Local dependencies
compile project(':routerjars')
compile project(':client')
// Android Support Repository dependencies
compile 'com.android.support:support-v4:22.2.0'
compile 'com.android.support:appcompat-v7:22.2.0'
compile 'com.android.support:recyclerview-v7:22.2.0'
// Remote dependencies
compile 'net.i2p.android.ext:floatingactionbutton:1.9.0'
compile files('libs/androidplot-core-0.6.1.jar')
compile ('com.android.support:support-v4-preferencefragment:1.0.0@aar'){
exclude module: 'support-v4'
}
compile 'com.pnikosis:materialish-progress:1.5'
compile 'com.eowise:recyclerview-stickyheaders:0.5.2@aar'
compile ('com.mcxiaoke.viewpagerindicator:library:2.4.1') {
exclude group: 'com.android.support', module: 'support-v4'
}
// Testing-only dependencies
androidTestCompile 'com.android.support.test.espresso:espresso-core:2.0'
androidTestCompile 'com.android.support.test:testing-support-lib:0.1'
}
dependencyVerification {
verify = [
'com.android.support:support-v4:7bb6e40a18774aa2595e4d8f9fe0ae14e61670f71a1279272fb0b79b8be71180',
'com.android.support:appcompat-v7:2d5867698410b41f75140c91d6c1e58da74ae0f97baf6e0bdd1f7cc1017ceb2c',
'com.android.support:recyclerview-v7:3a8da14585fa1c81f06e7cef4d93a7641f0323d8f984ff9a7bd7a6e416b46888',
'net.i2p.android.ext:floatingactionbutton:b41eae5fe6be599e3fade00273521b0914f2e199d5f04c50fa34cfe935347f76',
'com.android.support:support-v4-preferencefragment:5470f5872514a6226fa1fc6f4e000991f38805691c534cf0bd2778911fc773ad',
'com.pnikosis:materialish-progress:d71d80e00717a096784482aee21001a9d299fec3833e4ebd87739ed36cf77c54',
'com.eowise:recyclerview-stickyheaders:7b236da49b33b840e9ba6e7e4182218d1a2d9047236fdbc3ca947352f9b0883b',
'com.mcxiaoke.viewpagerindicator:library:1e8aad664137f68abdfee94889f6da3dc98be652a235176a403965a07a25de62',
]
}
project.ext.i2pbase = '../i2p.i2p'
def Properties props = new Properties()
def propFile = new File(project(':routerjars').projectDir, 'local.properties')
if (propFile.canRead()) {
props.load(new FileInputStream(propFile))
if (props != null &&
props.containsKey('i2psrc')) {
i2pbase = props['i2psrc']
} else {
println 'local.properties found but some entries are missing'
}
} else {
println 'local.properties not found'
}
task certificatesZip(type: Zip) {
archiveName = 'certificates_zip'
from files('' + i2pbase + '/installer/resources/certificates')
}
task copyI2PResources(type: Copy) {
// Force this to always run: Copy only detects source changes, not if missing in destination
outputs.upToDateWhen { false }
into 'src/main/res'
into('drawable') {
from file(i2pbase + '/installer/resources/themes/console/images/i2plogo.png')
}
into('raw') {
from(i2pbase + '/installer/resources/blocklist.txt') { rename { 'blocklist_txt' } }
from(i2pbase + '/installer/resources/hosts.txt') { rename { 'hosts_txt' } }
from(i2pbase + '/installer/resources/proxy') {
include { elem ->
elem.name.endsWith('.ht')
}
rename { String name ->
name.toLowerCase(Locale.US).replace('-', '_').replace('.', '_')
}
filter { String line ->
// Remove links to routerconsole
def m = line =~ /127.0.0.1:7657/
if (m.getCount()) {
// Links around content
line = line.replaceAll(/<a href="http:\/\/127.0.0.1:7657[^>]*>(.+?)<\/a>/) { fullmatch, content ->
content
}
// Links in translation substitutions
line = line.replaceAll(/"<a href=\\"http:\/\/127.0.0.1:7657[^>]*>", "<\/a>"/, '"", ""')
}
// Remove "Configuration - Help - Addressbook" heading
def n = line =~ /Configuration.+Help.+Addressbook/
if (n.getCount())
""
else
line
}
}
from('../LICENSE.txt') { rename { 'license_app_txt' } }
from('../licenses/LICENSE-Apache2.0.txt') { rename { 'license_apache20_txt' } }
from(i2pbase + '/licenses') {
include { elem ->
elem.name in [
'LICENSE-ElGamalDSA.txt',
'LICENSE-SHA256.txt',
'LICENSE-BSD.txt',
'LICENSE-SNTP.txt',
'LICENSE-LGPLv2.1.txt',
'LICENSE-InstallCert.txt',
'LICENSE-BlockFile.txt',
'LICENSE-GPLv2.txt',
'LICENSE-GPLv3.txt',
'LICENSE-LGPLv3.txt',
'LICENSE-FatCowIcons.txt',
'LICENSE-Addressbook.txt',
]
}
rename { String name ->
name.toLowerCase(Locale.US).replace('-', '_').replace('.', '_')
}
}
from certificatesZip
}
}
// For peers WebView
task copyI2PAssets(type: Copy) {
// Force this to always run: Copy only detects source changes, not if missing in destination
outputs.upToDateWhen { false }
into 'src/main/assets/themes/console'
into('images') {
from file(i2pbase + '/installer/resources/themes/console/images/i2plogo.png')
from file(i2pbase + '/installer/resources/themes/console/images/inbound.png')
from file(i2pbase + '/installer/resources/themes/console/images/outbound.png')
}
into('light') {
from file(i2pbase + '/installer/resources/themes/console/light/console.css')
}
into('light/images') {
from file(i2pbase + '/installer/resources/themes/console/light/images/header.png')
}
}
preBuild.dependsOn copyI2PResources
preBuild.dependsOn copyI2PAssets
task cleanI2PResources(type: Delete) {
delete file('src/main/res/drawable/i2plogo.png')
delete fileTree('src/main/res/raw') {
include 'blocklist_txt'
include 'hosts_txt'
include '*_ht'
include 'license_*'
include 'certificates_zip'
}
}
task cleanI2PAssets(type: Delete) {
delete fileTree('src/main/assets/themes/console/images')
delete file('src/main/assets/themes/console/light/console.css')
delete file('src/main/assets/themes/console/light/images/header.png')
}
clean.dependsOn cleanI2PResources
clean.dependsOn cleanI2PAssets
props = new Properties()
propFile = new File(project.rootDir, 'signing.properties')
if (propFile.canRead()) {
props.load(new FileInputStream(propFile))
if (props != null &&
props.containsKey('STORE_FILE') &&
props.containsKey('STORE_PASSWORD') &&
props.containsKey('KEY_ALIAS') &&
props.containsKey('KEY_PASSWORD')) {
android.signingConfigs.release.storeFile = file(props['STORE_FILE'])
android.signingConfigs.release.storePassword = props['STORE_PASSWORD']
android.signingConfigs.release.keyAlias = props['KEY_ALIAS']
android.signingConfigs.release.keyPassword = props['KEY_PASSWORD']
} else {
println 'signing.properties found but some entries are missing'
android.buildTypes.release.signingConfig = null
}
} else {
println 'signing.properties not found'
android.buildTypes.release.signingConfig = null
}

Binary file not shown.

View File

@ -0,0 +1,108 @@
package net.i2p.android;
import android.test.ActivityInstrumentationTestCase2;
import net.i2p.android.router.R;
import static android.support.test.espresso.Espresso.closeSoftKeyboard;
import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.Espresso.openActionBarOverflowOrOptionsMenu;
import static android.support.test.espresso.Espresso.pressBack;
import static android.support.test.espresso.action.ViewActions.click;
import static android.support.test.espresso.action.ViewActions.swipeLeft;
import static android.support.test.espresso.assertion.ViewAssertions.doesNotExist;
import static android.support.test.espresso.assertion.ViewAssertions.matches;
import static android.support.test.espresso.matcher.ViewMatchers.hasSibling;
import static android.support.test.espresso.matcher.ViewMatchers.isDescendantOfA;
import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
import static android.support.test.espresso.matcher.ViewMatchers.withId;
import static android.support.test.espresso.matcher.ViewMatchers.withText;
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.not;
public class I2PActivityTest extends ActivityInstrumentationTestCase2<I2PActivity> {
public I2PActivityTest() {
super(I2PActivity.class);
}
@Override
protected void setUp() throws Exception {
super.setUp();
// For each test method invocation, the Activity will not actually be created
// until the first time this method is called.
getActivity();
}
public void testMainTabs() {
onView(withId(R.id.router_onoff_button)).check(matches(isDisplayed()));
// Press "Tunnels" tab
onView(allOf(withText(R.string.label_tunnels),
not(isDescendantOfA(withId(R.id.main_scrollview))))).perform(click());
onView(withId(R.id.router_onoff_button)).check(matches(not(isDisplayed())));
onView(withText(R.string.label_i2ptunnel_client)).check(matches(isDisplayed()));
// Press "Addresses" tab
onView(withText(R.string.label_addresses)).perform(click());
onView(withText(R.string.label_i2ptunnel_client)).check(matches(not(isDisplayed())));
onView(withText(R.string.label_router)).check(matches(isDisplayed()));
// Press "Console" tab
onView(withText(R.string.label_console)).perform(click());
// Addressbook fragment should have been destroyed
onView(withText(R.string.label_router)).check(doesNotExist());
onView(withId(R.id.router_onoff_button)).check(matches(isDisplayed()));
}
public void testMainSwipe() {
onView(withId(R.id.router_onoff_button)).check(matches(isDisplayed()));
onView(allOf(withId(R.id.pager), hasSibling(withId(R.id.main_toolbar)))).perform(swipeLeft());
onView(withId(R.id.router_onoff_button)).check(matches(not(isDisplayed())));
onView(withText(R.string.label_i2ptunnel_client)).check(matches(isDisplayed()));
onView(allOf(withId(R.id.pager), hasSibling(withId(R.id.main_toolbar)))).perform(swipeLeft());
// TODO: test tunnels ViewPager
onView(allOf(withId(R.id.pager), hasSibling(withId(R.id.main_toolbar)))).perform(swipeLeft());
onView(withText(R.string.label_i2ptunnel_client)).check(matches(not(isDisplayed())));
onView(withText(R.string.label_router)).check(matches(isDisplayed()));
// TODO: test addressbook ViewPager
}
public void testSettingsNavigation() {
// Open settings menu
openActionBarOverflowOrOptionsMenu(getActivity());
onView(withText(R.string.menu_settings)).perform(click());
// Open bandwidth page
onView(withText(R.string.settings_label_bandwidth_net)).perform(click());
onView(withText(R.string.settings_label_startOnBoot)).check(matches(isDisplayed()));
pressBack();
// Open graphs page
onView(withText(R.string.label_graphs)).perform(click());
onView(withText(R.string.router_not_running)).check(matches(isDisplayed()));
pressBack();
// Open logging page
onView(withText(R.string.settings_label_logging)).perform(click());
onView(withText(R.string.settings_label_default_log_level)).check(matches(isDisplayed()));
pressBack();
// Open addressbook page
onView(withText(R.string.label_addressbook)).perform(click());
onView(withText("Subscriptions")).check(matches(isDisplayed()));
closeSoftKeyboard();
pressBack();
// Open graphs page
onView(withText(R.string.settings_label_advanced)).perform(click());
onView(withText(R.string.settings_label_transports)).check(matches(isDisplayed()));
pressBack();
// Check back exits settings
onView(withText(R.string.settings_label_advanced)).check(matches(isDisplayed()));
pressBack();
onView(withText(R.string.settings_label_advanced)).check(doesNotExist());
}
}

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name" translatable="false">I2P DEBUG</string>
</resources>

View File

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="utf-8"?>
<preference-headers xmlns:android="http://schemas.android.com/apk/res/android">
<header
android:fragment="net.i2p.android.router.SettingsActivity$SettingsFragment"
android:title="@string/settings_label_bandwidth_net">
<extra
android:name="settings"
android:value="net" />
</header>
<header
android:fragment="net.i2p.android.router.SettingsActivity$SettingsFragment"
android:title="@string/label_graphs">
<extra
android:name="settings"
android:value="graphs" />
</header>
<header
android:fragment="net.i2p.android.router.SettingsActivity$SettingsFragment"
android:title="@string/settings_label_logging">
<extra
android:name="settings"
android:value="logging" />
</header>
<header
android:title="@string/label_addressbook">
<intent
android:targetPackage="net.i2p.android.donate"
android:targetClass="net.i2p.android.router.addressbook.AddressbookSettingsActivity" />
</header>
<header
android:fragment="net.i2p.android.router.SettingsActivity$SettingsFragment"
android:title="@string/settings_label_advanced">
<extra
android:name="settings"
android:value="advanced" />
</header>
</preference-headers>

View File

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >
<Preference android:title="@string/settings_label_bandwidth_net">
<intent
android:targetPackage="net.i2p.android.donate"
android:targetClass="net.i2p.android.router.SettingsActivity"
android:action="net.i2p.android.router.PREFS_NET" />
</Preference>
<Preference android:title="@string/label_graphs">
<intent
android:targetPackage="net.i2p.android.donate"
android:targetClass="net.i2p.android.router.SettingsActivity"
android:action="net.i2p.android.router.PREFS_GRAPHS" />
</Preference>
<Preference android:title="@string/settings_label_logging">
<intent
android:targetPackage="net.i2p.android.donate"
android:targetClass="net.i2p.android.router.SettingsActivity"
android:action="net.i2p.android.router.PREFS_LOGGING" />
</Preference>
<Preference android:title="@string/label_addressbook">
<intent
android:targetPackage="net.i2p.android.donate"
android:targetClass="net.i2p.android.router.addressbook.AddressbookSettingsActivity" />
</Preference>
<Preference android:title="@string/settings_label_advanced">
<intent
android:targetPackage="net.i2p.android.donate"
android:targetClass="net.i2p.android.router.SettingsActivity"
android:action="net.i2p.android.router.PREFS_ADVANCED" />
</Preference>
</PreferenceScreen>

View File

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="utf-8"?>
<preference-headers xmlns:android="http://schemas.android.com/apk/res/android">
<header
android:fragment="net.i2p.android.router.SettingsActivity$SettingsFragment"
android:title="@string/settings_label_bandwidth_net">
<extra
android:name="settings"
android:value="net" />
</header>
<header
android:fragment="net.i2p.android.router.SettingsActivity$SettingsFragment"
android:title="@string/label_graphs">
<extra
android:name="settings"
android:value="graphs" />
</header>
<header
android:fragment="net.i2p.android.router.SettingsActivity$SettingsFragment"
android:title="@string/settings_label_logging">
<extra
android:name="settings"
android:value="logging" />
</header>
<header
android:title="@string/label_addressbook">
<intent
android:targetPackage="net.i2p.android.router"
android:targetClass="net.i2p.android.router.addressbook.AddressbookSettingsActivity" />
</header>
<header
android:fragment="net.i2p.android.router.SettingsActivity$SettingsFragment"
android:title="@string/settings_label_advanced">
<extra
android:name="settings"
android:value="advanced" />
</header>
</preference-headers>

View File

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >
<Preference android:title="@string/settings_label_bandwidth_net">
<intent
android:targetPackage="net.i2p.android.router"
android:targetClass="net.i2p.android.router.SettingsActivity"
android:action="net.i2p.android.router.PREFS_NET" />
</Preference>
<Preference android:title="@string/label_graphs">
<intent
android:targetPackage="net.i2p.android.router"
android:targetClass="net.i2p.android.router.SettingsActivity"
android:action="net.i2p.android.router.PREFS_GRAPHS" />
</Preference>
<Preference android:title="@string/settings_label_logging">
<intent
android:targetPackage="net.i2p.android.router"
android:targetClass="net.i2p.android.router.SettingsActivity"
android:action="net.i2p.android.router.PREFS_LOGGING" />
</Preference>
<Preference android:title="@string/label_addressbook">
<intent
android:targetPackage="net.i2p.android.router"
android:targetClass="net.i2p.android.router.addressbook.AddressbookSettingsActivity" />
</Preference>
<Preference android:title="@string/settings_label_advanced">
<intent
android:targetPackage="net.i2p.android.router"
android:targetClass="net.i2p.android.router.SettingsActivity"
android:action="net.i2p.android.router.PREFS_ADVANCED" />
</Preference>
</PreferenceScreen>

View File

@ -0,0 +1,205 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="net.i2p.android.router"
android:installLocation="auto">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application
android:icon="@drawable/ic_launcher_itoopie"
android:label="@string/app_name"
android:theme="@style/Theme.I2P">
<service
android:name=".service.RouterService"
android:icon="@drawable/ic_launcher_itoopie"
android:label="@string/app_name">
<intent-filter>
<action android:name="net.i2p.android.router.service.IRouterState" />
</intent-filter>
</service>
<provider
android:name=".provider.CacheProvider"
android:authorities="${applicationId}.provider" />
<receiver android:name=".receiver.OnBootReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<activity
android:name="net.i2p.android.I2PActivity"
android:icon="@drawable/ic_launcher_itoopie"
android:label="@string/app_name"
android:launchMode="singleTop">
<!-- Console filters -->
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="net.i2p.android.router.START_I2P" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<!-- Addressbook filters -->
<intent-filter>
<action android:name="android.intent.action.SEARCH" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.PICK" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<meta-data
android:name="android.app.searchable"
android:resource="@xml/searchable_addressbook" />
</activity>
<activity
android:name=".NewsActivity"
android:configChanges="orientation|keyboardHidden"
android:label="@string/label_news"
android:parentActivityName="net.i2p.android.I2PActivity">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="net.i2p.android.I2PActivity" />
</activity>
<activity
android:name="net.i2p.android.help.HelpActivity"
android:label="@string/menu_help"
android:parentActivityName="net.i2p.android.I2PActivity">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="net.i2p.android.I2PActivity" />
</activity>
<activity
android:name="net.i2p.android.help.BrowserConfigActivity"
android:label="@string/label_browser_configuration"
android:parentActivityName="net.i2p.android.I2PActivity">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="net.i2p.android.I2PActivity" />
</activity>
<activity
android:name=".LicenseActivity"
android:label="@string/label_licenses"
android:parentActivityName="net.i2p.android.help.HelpActivity">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="net.i2p.android.help.HelpActivity" />
</activity>
<activity
android:name=".web.WebActivity"
android:configChanges="orientation|keyboardHidden"
android:label="I2P Web Browser">
<!-- Disabled, this browser is not very secure
Temporarily enabled until an alternative browser is ready -->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:host="*.i2p"
android:scheme="http" />
</intent-filter>
</activity>
<activity
android:name=".SettingsActivity"
android:label="@string/menu_settings"
android:parentActivityName="net.i2p.android.I2PActivity">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="net.i2p.android.I2PActivity" />
</activity>
<activity
android:name=".addressbook.AddressbookSettingsActivity"
android:label="@string/label_addressbook"
android:launchMode="singleTop"
android:parentActivityName="net.i2p.android.I2PActivity">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="net.i2p.android.I2PActivity" />
</activity>
<activity
android:name=".addressbook.AddressbookAddWizardActivity"
android:parentActivityName="net.i2p.android.I2PActivity">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="net.i2p.android.I2PActivity" />
</activity>
<activity
android:name="net.i2p.android.i2ptunnel.TunnelDetailActivity"
android:parentActivityName="net.i2p.android.I2PActivity">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="net.i2p.android.I2PActivity" />
</activity>
<activity
android:name="net.i2p.android.i2ptunnel.preferences.EditTunnelActivity"
android:label="@string/edit_tunnel"
android:parentActivityName="net.i2p.android.i2ptunnel.TunnelDetailActivity">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="net.i2p.android.i2ptunnel.TunnelDetailActivity" />
</activity>
<activity
android:name="net.i2p.android.i2ptunnel.TunnelWizardActivity"
android:parentActivityName="net.i2p.android.I2PActivity">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="net.i2p.android.I2PActivity" />
</activity>
<activity
android:name=".log.LogActivity"
android:label="@string/label_logs"
android:parentActivityName="net.i2p.android.I2PActivity">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="net.i2p.android.I2PActivity" />
</activity>
<activity
android:name=".log.LogDetailActivity"
android:label="@string/log_entry"
android:parentActivityName=".log.LogActivity">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="net.i2p.android.router.log.LogActivity" />
</activity>
<activity
android:name=".stats.RateGraphActivity"
android:label="@string/label_graphs"
android:parentActivityName="net.i2p.android.I2PActivity">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="net.i2p.android.I2PActivity" />
</activity>
<activity
android:name=".stats.PeersActivity"
android:configChanges="orientation|keyboardHidden"
android:label="@string/label_peers_status"
android:launchMode="singleTop"
android:parentActivityName="net.i2p.android.I2PActivity">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="net.i2p.android.I2PActivity" />
</activity>
<activity
android:name=".netdb.NetDbActivity"
android:label="NetDB"
android:parentActivityName="net.i2p.android.I2PActivity">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="net.i2p.android.I2PActivity" />
</activity>
<activity
android:name=".netdb.NetDbDetailActivity"
android:label="NetDB Detail"
android:parentActivityName=".netdb.NetDbActivity">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="net.i2p.android.router.netdb.NetDbActivity" />
</activity>
</application>
</manifest>

View File

@ -0,0 +1,162 @@
/*
* The following code was written by Matthew Wiggins
* and is released under the APACHE 2.0 license
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Slight modifications and bugfixes by Sponge <sponge@mail.i2p>
* These modifications are released under the WTFPL (any version)
*
* We don't need negative numbers yet, and may never need to.
*
* XML Usage example:
*
* <com.hlidskialf.android.preference.SeekBarPreference android:key="duration"
* android:title="Duration of something"
* android:summary="How long something will last"
* android:dialogMessage="Something duration"
* android:defaultValue="5"
* android:text=" minutes"
* android:max="60"
* />
*
*/
package com.hlidskialf.android.preference;
import android.content.Context;
import android.preference.DialogPreference;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.SeekBar;
import android.widget.TextView;
public class SeekBarPreference extends DialogPreference implements SeekBar.OnSeekBarChangeListener {
private static final String androidns = "http://schemas.android.com/apk/res/android";
private SeekBar mSeekBar;
private TextView mSplashText;
private TextView mValueText;
private Context mContext;
private String mDialogMessage, mSuffix;
private String mDefault = "0";
private int mMax = 0;
private int mValue = 0;
private int mDirection = LinearLayout.HORIZONTAL;
public SeekBarPreference(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
int dialogMessageR = attrs.getAttributeResourceValue(androidns, "dialogMessage", 0);
mDialogMessage = (dialogMessageR == 0)
? attrs.getAttributeValue(androidns, "dialogMessage")
: context.getResources().getString(dialogMessageR);
int textR = attrs.getAttributeResourceValue(androidns, "text", 0);
mSuffix = (textR == 0)
? attrs.getAttributeValue(androidns, "text")
: context.getResources().getString(textR);
mDefault = attrs.getAttributeValue(androidns, "defaultValue");
mMax = Integer.parseInt(attrs.getAttributeValue(androidns, "max"));
if (attrs.getAttributeValue(androidns, "direction") != null) {
mDirection = Integer.parseInt(attrs.getAttributeValue(androidns, "direction"));
}
}
@Override
protected View onCreateDialogView() {
LinearLayout.LayoutParams params;
LinearLayout layout = new LinearLayout(mContext);
layout.setOrientation(LinearLayout.VERTICAL);
layout.setPadding(6, 6, 6, 10);
// Set the width so that it is as usable as possible.
// We multiplymMax so that the smaller ranges will get a bigger area.
if (mDirection == LinearLayout.HORIZONTAL) {
layout.setMinimumWidth(mMax*5);
} else {
layout.setMinimumHeight(mMax*5);
}
mSplashText = new TextView(mContext);
if (mDialogMessage != null) {
mSplashText.setText(mDialogMessage);
}
layout.addView(mSplashText);
mValueText = new TextView(mContext);
mValueText.setGravity(Gravity.CENTER_HORIZONTAL);
mValueText.setTextSize(32);
params = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
layout.addView(mValueText, params);
mSeekBar = new SeekBar(mContext);
mSeekBar.setOnSeekBarChangeListener(this);
// Move the bar away from the changing text, so you can see it, and
// move it away from the edges to improve usability for the end-ranges.
mSeekBar.setPadding(6, 30, 6, 6);
layout.addView(mSeekBar, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT));
if (shouldPersist()) {
mValue = Integer.parseInt(getPersistedString(mDefault));
}
mSeekBar.setMax(mMax);
mSeekBar.setProgress(mValue);
return layout;
}
@Override
protected void onBindDialogView(View v) {
super.onBindDialogView(v);
mSeekBar.setMax(mMax);
mSeekBar.setProgress(mValue);
}
@Override
protected void onSetInitialValue(boolean restore, Object defaultValue) {
super.onSetInitialValue(restore, defaultValue);
if (restore) {
mValue = shouldPersist() ? Integer.parseInt(getPersistedString(mDefault)) : 0;
} else {
mValue = (Integer) defaultValue;
}
}
public void onProgressChanged(SeekBar seek, int value, boolean fromTouch) {
String t = String.valueOf(value);
mValueText.setText(mSuffix == null ? t : t.concat(mSuffix));
if (shouldPersist()) {
persistString(t);
}
callChangeListener(value);
}
public void onStartTrackingTouch(SeekBar seek) {
}
public void onStopTrackingTouch(SeekBar seek) {
}
public void setMax(int max) {
mMax = max;
}
public int getMax() {
return mMax;
}
public void setProgress(int progress) {
mValue = progress;
if (mSeekBar != null) {
mSeekBar.setProgress(progress);
}
}
public int getProgress() {
return mValue;
}
}

View File

@ -0,0 +1,358 @@
package net.i2p.android;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
import net.i2p.android.help.HelpActivity;
import net.i2p.android.i2ptunnel.TunnelsContainer;
import net.i2p.android.router.ConsoleContainer;
import net.i2p.android.router.MainFragment;
import net.i2p.android.router.R;
import net.i2p.android.router.SettingsActivity;
import net.i2p.android.router.addressbook.AddressbookContainer;
import net.i2p.android.router.service.RouterService;
import net.i2p.android.router.service.State;
import net.i2p.android.router.util.Connectivity;
import net.i2p.android.router.util.Util;
import net.i2p.android.util.MemoryFragmentPagerAdapter;
import net.i2p.android.widget.CustomViewPager;
import net.i2p.android.widget.SlidingTabLayout;
import net.i2p.router.RouterContext;
import java.io.File;
/**
* The main activity of the app. Contains a ViewPager that holds the three main
* views:
* <ul>
* <li>The console</li>
* <li>The addressbook</li>
* <li>The tunnel manager</li>
* </ul>
*/
public class I2PActivity extends I2PActivityBase implements
MainFragment.RouterControlListener {
CustomViewPager mViewPager;
ViewPagerAdapter mViewPagerAdapter;
SlidingTabLayout mSlidingTabLayout;
private boolean mAutoStartFromIntent = false;
private boolean _keep = true;
private boolean _startPressed = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_viewpager);
Toolbar toolbar = (Toolbar) findViewById(R.id.main_toolbar);
setSupportActionBar(toolbar);
mViewPager = (CustomViewPager) findViewById(R.id.pager);
mViewPagerAdapter = new ViewPagerAdapter(this, getSupportFragmentManager());
mViewPager.setAdapter(mViewPagerAdapter);
mSlidingTabLayout = (SlidingTabLayout) findViewById(R.id.sliding_tabs);
// Center the tabs in the layout
mSlidingTabLayout.setDistributeEvenly(true);
// Customize tab color
mSlidingTabLayout.setCustomTabColorizer(new SlidingTabLayout.TabColorizer() {
@Override
public int getIndicatorColor(int position) {
return getResources().getColor(R.color.accent);
}
});
// Give the SlidingTabLayout the ViewPager
mSlidingTabLayout.setViewPager(mViewPager);
_keep = true;
}
public static class ViewPagerAdapter extends MemoryFragmentPagerAdapter {
private static final int NUM_ITEMS = 3;
private Context mContext;
public ViewPagerAdapter(Context context, FragmentManager fm) {
super(fm);
mContext = context;
}
@Override
public int getCount() {
return NUM_ITEMS;
}
@Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return new ConsoleContainer();
case 1:
return new TunnelsContainer();
case 2:
return new AddressbookContainer();
default:
return null;
}
}
@Override
public CharSequence getPageTitle(int position) {
switch (position) {
case 0:
return mContext.getString(R.string.label_console);
case 1:
return mContext.getString(R.string.label_tunnels);
case 2:
return mContext.getString(R.string.label_addresses);
default:
return null;
}
}
}
@Override
protected void onPostCreate(Bundle savedInstanceState) {
Util.d("Initializing...");
InitActivities init = new InitActivities(this);
init.debugStuff();
init.initialize();
super.onPostCreate(savedInstanceState);
handleIntents();
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
handleIntents();
}
private void handleIntents() {
if (getIntent() == null)
return;
Intent intent = getIntent();
String action = intent.getAction();
if (action == null)
return;
if (action.equals("net.i2p.android.router.START_I2P")) {
if (mViewPager.getCurrentItem() != 0)
mViewPager.setCurrentItem(0, false);
autoStart();
}
}
private void autoStart() {
if (canStart()) {
if (Connectivity.isConnected(this)) {
mAutoStartFromIntent = true;
onStartRouterClicked();
} else {
// Not connected to a network
// TODO: Notify user
}
} else {
// TODO: Notify user
}
}
@Override
public void onStart() {
super.onStart();
LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(this);
IntentFilter filter = new IntentFilter();
filter.addAction(RouterService.LOCAL_BROADCAST_STATE_NOTIFICATION);
filter.addAction(RouterService.LOCAL_BROADCAST_STATE_CHANGED);
lbm.registerReceiver(onStateChange, filter);
}
private BroadcastReceiver onStateChange = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
State state = intent.getParcelableExtra(RouterService.LOCAL_BROADCAST_EXTRA_STATE);
if (_startPressed && Util.getRouterContext() != null)
_startPressed = false;
// Update menus, FAMs etc.
supportInvalidateOptionsMenu();
// Update main paging state
mViewPager.setPagingEnabled(!(Util.isStopping(state) || Util.isStopped(state)));
// If I2P was started by another app and is running, return to that app
if (state == State.RUNNING && mAutoStartFromIntent) {
I2PActivity.this.setResult(RESULT_OK);
finish();
}
}
};
@Override
public void onResume() {
super.onResume();
// Handle edge cases after shutting down router
mViewPager.updatePagingState();
LocalBroadcastManager.getInstance(this).sendBroadcast(new Intent(RouterService.LOCAL_BROADCAST_REQUEST_STATE));
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_base_actions, menu);
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_settings:
Intent intent = new Intent(this, SettingsActivity.class);
startActivity(intent);
return true;
case R.id.menu_help:
Intent hi = new Intent(this, HelpActivity.class);
switch (mViewPager.getCurrentItem()) {
case 1:
hi.putExtra(HelpActivity.CATEGORY, HelpActivity.CAT_I2PTUNNEL);
break;
case 2:
hi.putExtra(HelpActivity.CATEGORY, HelpActivity.CAT_ADDRESSBOOK);
break;
}
startActivity(hi);
return true;
default:
return super.onOptionsItemSelected(item);
}
}
public void onBackPressed() {
super.onBackPressed();
RouterContext ctx = Util.getRouterContext();
// RouterService svc = _routerService; Which is better to use?!
_keep = Connectivity.isConnected(this) && (ctx != null || _startPressed);
Util.d("*********************************************************");
Util.d("Back pressed, Keep? " + _keep);
Util.d("*********************************************************");
}
@Override
public void onStop() {
super.onStop();
LocalBroadcastManager.getInstance(this).unregisterReceiver(onStateChange);
}
@Override
public void onDestroy() {
super.onDestroy();
if (!_keep) {
Thread t = new Thread(new KillMe());
t.start();
}
}
private class KillMe implements Runnable {
public void run() {
Util.d("*********************************************************");
Util.d("KillMe started!");
Util.d("*********************************************************");
try {
Thread.sleep(500); // is 500ms long enough?
} catch (InterruptedException ex) {
}
System.exit(0);
}
}
private boolean canStart() {
RouterService svc = _routerService;
return (svc == null) || (!_isBound) || svc.canManualStart();
}
private boolean canStop() {
RouterService svc = _routerService;
return svc != null && _isBound && svc.canManualStop();
}
// MainFragment.RouterControlListener
public boolean shouldShowOnOff() {
return (canStart() && Connectivity.isConnected(this)) || (canStop() && !isGracefulShutdownInProgress());
}
public boolean shouldBeOn() {
String action = getIntent().getAction();
return (canStop()) ||
(action != null && action.equals("net.i2p.android.router.START_I2P"));
}
public void onStartRouterClicked() {
_startPressed = true;
RouterService svc = _routerService;
if (svc != null && _isBound) {
setPref(PREF_AUTO_START, true);
svc.manualStart();
} else {
(new File(Util.getFileDir(this), "wrapper.log")).delete();
startRouter();
}
}
public boolean onStopRouterClicked() {
RouterService svc = _routerService;
if (svc != null && _isBound) {
setPref(PREF_AUTO_START, false);
svc.manualQuit();
return true;
}
return false;
}
/** @since 0.9.19 */
public boolean isGracefulShutdownInProgress() {
RouterService svc = _routerService;
return svc != null && svc.isGracefulShutdownInProgress();
}
/** @since 0.9.19 */
public boolean onGracefulShutdownClicked() {
RouterService svc = _routerService;
if(svc != null && _isBound) {
setPref(PREF_AUTO_START, false);
svc.gracefulShutdown();
return true;
}
return false;
}
/** @since 0.9.19 */
public boolean onCancelGracefulShutdownClicked() {
RouterService svc = _routerService;
if(svc != null && _isBound) {
setPref(PREF_AUTO_START, false);
svc.cancelGracefulShutdown();
return true;
}
return false;
}
}

View File

@ -0,0 +1,207 @@
package net.i2p.android;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.IBinder;
import android.support.v7.app.AppCompatActivity;
import net.i2p.android.router.service.RouterBinder;
import net.i2p.android.router.service.RouterService;
import net.i2p.android.router.util.Util;
import net.i2p.android.util.LocaleManager;
public abstract class I2PActivityBase extends AppCompatActivity {
/**
* Router variables
*/
protected boolean _isBound;
protected boolean _triedBind;
protected ServiceConnection _connection;
protected RouterService _routerService;
private SharedPreferences _sharedPrefs;
private static final String SHARED_PREFS = "net.i2p.android.router";
protected static final String PREF_AUTO_START = "autoStart";
/**
* true leads to a poor install experience, very slow to paint the screen
*/
protected static final boolean DEFAULT_AUTO_START = false;
private final LocaleManager localeManager = new LocaleManager();
/**
* Called when the activity is first created.
*/
@Override
protected void onCreate(Bundle savedInstanceState) {
Util.d(this + " onCreate called");
localeManager.onCreate(this);
super.onCreate(savedInstanceState);
_sharedPrefs = getSharedPreferences(SHARED_PREFS, 0);
}
@Override
public void onRestart() {
Util.d(this + " onRestart called");
super.onRestart();
}
@Override
public void onStart() {
Util.d(this + " onStart called");
super.onStart();
if (_sharedPrefs.getBoolean(PREF_AUTO_START, DEFAULT_AUTO_START))
startRouter();
else
bindRouter(false);
}
/**
* @param def default
*/
public boolean getPref(String pref, boolean def) {
return _sharedPrefs.getBoolean(pref, def);
}
/**
* @param def default
*/
public String getPref(String pref, String def) {
return _sharedPrefs.getString(pref, def);
}
/**
* @return success
*/
public boolean setPref(String pref, boolean val) {
SharedPreferences.Editor edit = _sharedPrefs.edit();
edit.putBoolean(pref, val);
return edit.commit();
}
/**
* @return success
*/
public boolean setPref(String pref, String val) {
SharedPreferences.Editor edit = _sharedPrefs.edit();
edit.putString(pref, val);
return edit.commit();
}
@Override
public void onResume() {
Util.d(this + " onResume called");
super.onResume();
localeManager.onResume(this);
}
public void notifyLocaleChanged() {
localeManager.onResume(this);
}
@Override
public void onPause() {
Util.d(this + " onPause called");
super.onPause();
}
@Override
public void onSaveInstanceState(Bundle outState) {
Util.d(this + " onSaveInstanceState called");
super.onSaveInstanceState(outState);
}
@Override
public void onStop() {
Util.d(this + " onStop called");
unbindRouter();
super.onStop();
}
@Override
public void onDestroy() {
Util.d(this + " onDestroy called");
super.onDestroy();
}
////// Service stuff
/**
* Start the service and bind to it
*/
protected boolean startRouter() {
Intent intent = new Intent();
intent.setClassName(this, "net.i2p.android.router.service.RouterService");
Util.d(this + " calling startService");
ComponentName name = startService(intent);
if (name == null)
Util.d(this + " XXXXXXXXXXXXXXXXXXXX got null from startService!");
Util.d(this + " got from startService: " + name);
boolean success = bindRouter(true);
if (!success)
Util.d(this + " Bind router failed");
return success;
}
/**
* Bind only
*/
protected boolean bindRouter(boolean autoCreate) {
Intent intent = new Intent(RouterBinder.class.getName());
intent.setClassName(this, "net.i2p.android.router.service.RouterService");
Util.d(this + " calling bindService");
_connection = new RouterConnection();
_triedBind = bindService(intent, _connection, autoCreate ? BIND_AUTO_CREATE : 0);
Util.d(this + " bindService: auto create? " + autoCreate + " success? " + _triedBind);
return _triedBind;
}
protected void unbindRouter() {
Util.d(this + " unbindRouter called with _isBound:" + _isBound + " _connection:" + _connection + " _triedBind:" + _triedBind);
if (_triedBind && _connection != null)
unbindService(_connection);
_triedBind = false;
_connection = null;
_routerService = null;
_isBound = false;
}
/**
* Class for interacting with the main interface of the RouterService.
*/
protected class RouterConnection implements ServiceConnection {
public void onServiceConnected(ComponentName name, IBinder service) {
Util.d(this + " connected to router service");
RouterBinder binder = (RouterBinder) service;
RouterService svc = binder.getService();
_routerService = svc;
_isBound = true;
onRouterBind(svc);
}
public void onServiceDisconnected(ComponentName name) {
Util.d(this + " disconnected from router service!!!!!!!");
// save memory
_routerService = null;
_isBound = false;
onRouterUnbind();
}
}
/**
* callback from ServiceConnection, override as necessary
*/
protected void onRouterBind(RouterService svc) {
}
/**
* callback from ServiceConnection, override as necessary
*/
protected void onRouterUnbind() {
}
}

View File

@ -0,0 +1,280 @@
package net.i2p.android;
import android.content.Context;
import android.content.res.Resources;
import android.os.Build;
import net.i2p.android.router.R;
import net.i2p.android.router.util.Util;
import net.i2p.data.DataHelper;
import net.i2p.util.FileUtil;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Properties;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
// Wouldn't this be better as a private class in MainActivity?
class InitActivities {
private final Context ctx;
private final String myDir;
private final String _ourVersion;
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 InitActivities(Context c) {
ctx = c;
myDir = Util.getFileDir(c);
_ourVersion = Util.getOurVersion(c);
}
void debugStuff() {
Util.d("java.io.tmpdir" + ": " + System.getProperty("java.io.tmpdir"));
Util.d("java.vendor" + ": " + System.getProperty("java.vendor"));
Util.d("java.version" + ": " + System.getProperty("java.version"));
Util.d("os.arch" + ": " + System.getProperty("os.arch"));
Util.d("os.name" + ": " + System.getProperty("os.name"));
Util.d("os.version" + ": " + System.getProperty("os.version"));
Util.d("user.dir" + ": " + System.getProperty("user.dir"));
Util.d("user.home" + ": " + System.getProperty("user.home"));
Util.d("user.name" + ": " + System.getProperty("user.name"));
Util.d("getFilesDir()" + ": " + myDir);
Util.d("max mem" + ": " + DataHelper.formatSize(Runtime.getRuntime().maxMemory()));
Util.d("Package" + ": " + ctx.getPackageName());
Util.d("Version" + ": " + _ourVersion);
Util.d("MODEL" + ": " + Build.MODEL);
Util.d("DISPLAY" + ": " + Build.DISPLAY);
Util.d("VERSION" + ": " + Build.VERSION.RELEASE);
Util.d("SDK" + ": " + Build.VERSION.SDK_INT);
}
void initialize() {
if (checkNewVersion()) {
List<Properties> lProps = Util.getPropertiesFromPreferences(ctx);
Properties props = lProps.get(0);
props.setProperty("i2p.dir.temp", myDir + "/tmp");
props.setProperty("i2p.dir.pid", myDir + "/tmp");
// Time disabled in default router.config
// But lots of time problems on Android, not all carriers support NITZ
// and there was no NTP before 3.0. Tablets should be fine?
// Phones in airplane mode with wifi enabled still a problem.
// Deactivated phones in airplane mode definitely won't have correct time.
if (Build.VERSION.SDK_INT < 11) // Honeycomb 3.0
props.setProperty("time.disabled", "false");
mergeResourceToFile(R.raw.router_config, "router.config", props);
mergeResourceToFile(R.raw.logger_config, "logger.config", lProps.get(1));
// This is not needed for now, i2ptunnel.config only contains tunnel
// settings, which can now be configured manually. We don't want to
// overwrite the user's tunnels.
//mergeResourceToFile(R.raw.i2ptunnel_config, "i2ptunnel.config", null);
copyResourceToFileIfAbsent(R.raw.i2ptunnel_config, "i2ptunnel.config");
// FIXME this is a memory hog to merge this way
mergeResourceToFile(R.raw.hosts_txt, "hosts.txt", null);
mergeResourceToFile(R.raw.more_hosts_txt, "hosts.txt", null);
copyResourceToFile(R.raw.blocklist_txt, "blocklist.txt");
File abDir = new File(myDir, "addressbook");
abDir.mkdir();
copyResourceToFile(R.raw.subscriptions_txt, "addressbook/subscriptions.txt");
mergeResourceToFile(R.raw.addressbook_config_txt, "addressbook/config.txt", null);
File docsDir = new File(myDir, "docs");
docsDir.mkdir();
copyResourceToFile(R.raw.ahelper_conflict_header_ht, "docs/ahelper-conflict-header.ht");
copyResourceToFile(R.raw.ahelper_new_header_ht, "docs/ahelper-new-header.ht");
copyResourceToFile(R.raw.ahelper_notfound_header_ht, "docs/ahelper-notfound-header.ht");
copyResourceToFile(R.raw.auth_header_ht, "docs/auth-header.ht");
copyResourceToFile(R.raw.baduri_header_ht, "docs/baduri-header.ht");
copyResourceToFile(R.raw.denied_header_ht, "docs/denied-header.ht");
copyResourceToFile(R.raw.dnf_header_ht, "docs/dnf-header.ht");
copyResourceToFile(R.raw.dnfb_header_ht, "docs/dnfb-header.ht");
copyResourceToFile(R.raw.dnfh_header_ht, "docs/dnfh-header.ht");
copyResourceToFile(R.raw.dnfp_header_ht, "docs/dnfp-header.ht");
copyResourceToFile(R.raw.enc_header_ht, "docs/enc-header.ht");
copyResourceToFile(R.raw.encp_header_ht, "docs/encp-header.ht");
copyResourceToFile(R.raw.localhost_header_ht, "docs/localhost-header.ht");
copyResourceToFile(R.raw.nols_header_ht, "docs/nols-header.ht");
copyResourceToFile(R.raw.nolsp_header_ht, "docs/nolsp-header.ht");
copyResourceToFile(R.raw.noproxy_header_ht, "docs/noproxy-header.ht");
copyResourceToFile(R.raw.protocol_header_ht, "docs/protocol-header.ht");
copyResourceToFile(R.raw.reset_header_ht, "docs/reset-header.ht");
copyResourceToFile(R.raw.resetp_header_ht, "docs/resetp-header.ht");
File cssDir = new File(docsDir, "themes/console/light");
cssDir.mkdirs();
//copyResourceToFile(R.raw.console_css, "docs/themes/console/light/console.css");
//copyResourceToFile(R.raw.android_css, "docs/themes/console/light/android.css");
File imgDir = new File(docsDir, "themes/console/images");
imgDir.mkdir();
copyResourceToFile(R.drawable.i2plogo, "docs/themes/console/images/i2plogo.png");
copyResourceToFile(R.drawable.itoopie_sm, "docs/themes/console/images/itoopie_sm.png");
//copyResourceToFile(R.drawable.outbound, "docs/themes/console/images/outbound.png");
//copyResourceToFile(R.drawable.inbound, "docs/themes/console/images/inbound.png");
File img2Dir = new File(cssDir, "images");
img2Dir.mkdir();
//copyResourceToFile(R.drawable.header, "docs/themes/console/light/images/header.png");
File certDir = new File(myDir, "certificates");
certDir.mkdir();
File certificates = new File(myDir, "certificates");
File[] allcertificates = certificates.listFiles();
if ( allcertificates != null) {
for (File f : allcertificates) {
Util.d("Deleting old certificate file/dir " + f);
FileUtil.rmdir(f, false);
}
}
unzipResourceToDir(R.raw.certificates_zip, "certificates");
//File netDBDir = new File(myDir, "netDB");
//netDBDir.mkdir();
//unzipResourceToDir(R.raw.netdb_zip, "netDB");
}
// Set up the locations so settings can find them
System.setProperty("i2p.dir.base", myDir);
System.setProperty("i2p.dir.config", myDir);
System.setProperty("wrapper.logfile", myDir + "/wrapper.log");
}
/**
* @param f relative to base dir
*/
private void copyResourceToFileIfAbsent(int resID, String f) {
File file = new File(myDir, f);
if (!file.exists())
copyResourceToFile(resID, f);
}
/**
* @param f relative to base dir
*/
private void copyResourceToFile(int resID, String f) {
InputStream in = null;
FileOutputStream out = null;
Util.d("Creating file " + f + " from resource");
byte buf[] = new byte[4096];
try {
// Context methods
in = ctx.getResources().openRawResource(resID);
out = new FileOutputStream(new File(myDir, f));
int read;
while ( (read = in.read(buf)) != -1)
out.write(buf, 0, read);
} catch (IOException ioe) {
} catch (Resources.NotFoundException nfe) {
} finally {
if (in != null) try { in.close(); } catch (IOException ioe) {}
if (out != null) try { out.close(); } catch (IOException ioe) {}
}
}
/**
* @param folder relative to base dir
*/
private void unzipResourceToDir(int resID, String folder) {
InputStream in = null;
FileOutputStream out = null;
ZipInputStream zis = null;
Util.d("Creating files in '" + myDir + "/" + folder + "/' from resource");
try {
// Context methods
in = ctx.getResources().openRawResource(resID);
zis = new ZipInputStream((in));
ZipEntry ze;
while ((ze = zis.getNextEntry()) != null) {
out = null;
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int count;
while ((count = zis.read(buffer)) != -1) {
baos.write(buffer, 0, count);
}
String name = ze.getName();
File f = new File(myDir + "/" + folder +"/" + name);
if (ze.isDirectory()) {
Util.d("Creating directory " + myDir + "/" + folder +"/" + name + " from resource");
f.mkdir();
} else {
Util.d("Creating file " + myDir + "/" + folder +"/" + name + " from resource");
byte[] bytes = baos.toByteArray();
out = new FileOutputStream(f);
out.write(bytes);
}
} catch (IOException ioe) {
} finally {
if (out != null) { try { out.close(); } catch (IOException ioe) {} out = null; }
}
}
} catch (IOException ioe) {
} catch (Resources.NotFoundException nfe) {
} finally {
if (in != null) try { in.close(); } catch (IOException ioe) {}
if (out != null) try { out.close(); } catch (IOException ioe) {}
if (zis != null) try { zis.close(); } catch (IOException ioe) {}
}
}
/**
* Load defaults from resource,
* then add props from settings,
* and write back.
*
* @param f relative to base dir
* @param overrides local overrides or null
*/
private void mergeResourceToFile(int resID, String f, Properties overrides) {
Util.mergeResourceToFile(ctx, myDir, f, resID, overrides, null);
}
/**
* Check for new version.
* FIXME we could just use shared prefs for this instead of storing in a file
* @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) {
Util.d("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);
if (newVersion) {
Util.d("New version " + _ourVersion);
props.setProperty(PROP_INSTALLED_VERSION, _ourVersion);
try {
DataHelper.storeProps(props, ctx.getFileStreamPath(CONFIG_FILE));
} catch (IOException ioe) {
Util.d("Failed to write " + CONFIG_FILE);
}
}
return newVersion;
}
}

View File

@ -0,0 +1,157 @@
package net.i2p.android.apps;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import net.i2p.I2PAppContext;
import net.i2p.data.DataHelper;
import net.i2p.util.EepGet;
import net.i2p.util.Log;
/**
* EepGet and return as a string. 256KB max.
*/
public class EepGetFetcher implements EepGet.StatusListener {
private final I2PAppContext _context;
private final Log _log;
private final String _url;
private final EepGet _eepget;
private final File _file;
private boolean _success;
private static final long MAX_LEN = 256*1024;
private static final String ERROR_HEADER = "<html><head><title>Not Found</title></head><body>";
private static final String ERROR_URL = "<p>Unable to load URL: ";
private static final String ERROR_ROUTER = "<p>Your router (or the HTTP proxy) does not appear to be running.</p>";
private static final String ERROR_FOOTER = "</body></html>";
/**
* Writes to temp file, call getData()
* to get the data as a String.
* Temp file sticks around forever.
*/
public EepGetFetcher(String url) {
_context = I2PAppContext.getGlobalContext();
_log = _context.logManager().getLog(EepGetFetcher.class);
_url = url;
_file = new File(_context.getTempDir(), "eepget-" + _context.random().nextLong());
_eepget = new EepGet(_context, true, "localhost", 4444, 0, -1, MAX_LEN,
_file.getAbsolutePath(), null, url,
true, null, null, null);
// use new 0.8.8 feature
_eepget.setWriteErrorToOutput();
//_eepget.addStatusListener(this);
}
/**
* Writes to output stream
*/
public EepGetFetcher(String url, OutputStream out, boolean writeErrorToStream) {
_context = I2PAppContext.getGlobalContext();
_log = _context.logManager().getLog(EepGetFetcher.class);
_url = url;
_file = null;
_eepget = new EepGet(_context, true, "localhost", 4444, 0, -1, MAX_LEN,
null, out, url,
true, null, null, null);
if (writeErrorToStream)
_eepget.setWriteErrorToOutput();
}
public void addStatusListener(EepGet.StatusListener l) {
_eepget.addStatusListener(l);
}
public boolean fetch() {
_success = _eepget.fetch();
return _success;
}
/**
* @return non-null
*/
public String getContentType() {
if (_eepget.getStatusCode() < 0)
return "text/html";
String rv = _eepget.getContentType();
if (rv == null)
return "text/html";
int semi = rv.indexOf(";");
if (semi > 0)
rv = rv.substring(0, semi);
return rv.toLowerCase();
}
/**
* @return non-null
*/
public String getEncoding() {
if (_eepget.getStatusCode() < 0)
return "UTF-8";
String type = _eepget.getContentType();
String rv;
if (type == null || !type.startsWith("text"))
rv = "ISO-8859-1";
else
rv = "UTF-8";
return rv;
}
/**
* @return -1 if nothing back from server
*/
public int getStatusCode() {
return _eepget.getStatusCode();
}
/**
* Only for the constructor without the output stream
* Only call ONCE!
* FIXME we don't get the proxy error pages this way
*/
public String getData() {
String rv;
int statusCode = _eepget.getStatusCode();
if (statusCode < 0) {
rv = ERROR_HEADER + ERROR_URL + "<a href=\"" + _url + "\">" + _url +
"</a></p>" + ERROR_ROUTER + ERROR_FOOTER;
_file.delete();
} else if (_file.length() <= 0) {
rv = ERROR_HEADER + ERROR_URL + "<a href=\"" + _url + "\">" + _url +
"</a> No data returned, error code: " + statusCode +
"</p>" + ERROR_FOOTER;
_file.delete();
} else {
InputStream fis = null;
try {
fis = new FileInputStream(_file);
byte[] data = new byte[(int) _file.length()];
DataHelper.read(fis, data);
rv = new String(data, getEncoding());
} catch (IOException ioe) {
_log.error("fetcher", ioe);
rv = "I/O error";
} finally {
if (fis != null) try { fis.close(); } catch (IOException ioe) {}
_file.delete();
}
}
return rv;
}
public void attemptFailed(String url, long bytesTransferred, long bytesRemaining, int currentAttempt, int numRetries, Exception cause) {}
public void bytesTransferred(long alreadyTransferred, int currentWrite, long bytesTransferred, long bytesRemaining, String url) {}
public void transferComplete(long alreadyTransferred, long bytesTransferred, long bytesRemaining, String url, String outputFile, boolean notModified) {}
public void transferFailed(String url, long bytesTransferred, long bytesRemaining, int currentAttempt) {}
public void headerReceived(String url, int attemptNum, String key, String val) {}
public void attempting(String url) {}
}

View File

@ -0,0 +1,420 @@
package net.i2p.android.apps;
import android.content.Context;
import net.i2p.android.router.NewsActivity;
import net.i2p.android.router.R;
import net.i2p.android.router.util.Notifications;
import net.i2p.crypto.SU3File;
import net.i2p.data.DataHelper;
import net.i2p.router.RouterContext;
import net.i2p.router.news.NewsEntry;
import net.i2p.router.news.NewsMetadata;
import net.i2p.router.news.NewsXMLParser;
import net.i2p.router.util.RFC822Date;
import net.i2p.util.EepGet;
import net.i2p.util.FileUtil;
import net.i2p.util.Log;
import net.i2p.util.ReusableGZIPInputStream;
import net.i2p.util.SecureFileOutputStream;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.Date;
import java.util.List;
/**
* From router console, simplified since we don't deal with router versions
* or updates.
*/
public class NewsFetcher implements Runnable, EepGet.StatusListener {
private final Context mCtx;
private final RouterContext _context;
private final Notifications _notif;
private final Log _log;
private long _lastFetch;
private long _lastUpdated;
private String _lastModified;
private boolean _invalidated;
private File _newsFile;
private File _tempFile;
private static NewsFetcher _instance;
private volatile boolean _isRunning = true;
private Thread _thread;
public static /*final */ NewsFetcher getInstance() {
return _instance;
}
public static /* final */ synchronized NewsFetcher getInstance(
Context context, RouterContext ctx, Notifications notif) {
if (_instance != null)
return _instance;
_instance = new NewsFetcher(context, ctx, notif);
return _instance;
}
private static final String NEWS_DIR = "docs";
private static final String NEWS_FILE = "news.xml";
private static final String TEMP_NEWS_FILE = "news.xml.temp";
/**
* Changed in 0.9.11 to the b32 for psi.i2p, run by psi.
* We may be able to change it to psi.i2p in a future release after
* the hostname propagates.
*
* @since 0.7.14 not configurable
*/
private static final String BACKUP_NEWS_URL_SU3 = "http://avviiexdngd32ccoy4kuckvc3mkf53ycvzbz6vz75vzhv4tbpk5a.b32.i2p/news.su3";
private static final String PROP_LAST_CHECKED = "router.newsLastChecked";
private static final String PROP_REFRESH_FREQUENCY = "router.newsRefreshFrequency";
private static final String DEFAULT_REFRESH_FREQUENCY = 24 * 60 * 60 * 1000 + "";
private static final String PROP_NEWS_URL = "router.newsURL";
public static final String DEFAULT_NEWS_URL_SU3 = "http://echelon.i2p/news/news.su3";
private NewsFetcher(Context context, RouterContext ctx, Notifications notif) {
mCtx = context;
_context = ctx;
_notif = notif;
_context.addShutdownTask(new Shutdown());
_log = ctx.logManager().getLog(NewsFetcher.class);
try {
String last = ctx.getProperty(PROP_LAST_CHECKED);
if (last != null)
_lastFetch = Long.parseLong(last);
} catch (NumberFormatException nfe) {
}
File newsDir = new File(_context.getRouterDir(), NEWS_DIR);
// isn't already there on android
newsDir.mkdir();
_newsFile = new File(newsDir, NEWS_FILE);
_tempFile = new File(_context.getTempDir(), TEMP_NEWS_FILE);
updateLastFetched();
}
private void updateLastFetched() {
if (_newsFile.exists()) {
if (_lastUpdated == 0)
_lastUpdated = _newsFile.lastModified();
if (_lastFetch == 0)
_lastFetch = _lastUpdated;
if (_lastModified == null)
_lastModified = RFC822Date.to822Date(_lastFetch);
} else {
_lastUpdated = 0;
_lastFetch = 0;
_lastModified = null;
}
}
public String status() {
StringBuilder buf = new StringBuilder(128);
long now = _context.clock().now();
if (_lastUpdated > 0) {
buf.append(mCtx.getString(R.string.news_last_updated,
DataHelper.formatDuration2(now - _lastUpdated)))
.append('\n');
}
if (_lastFetch > _lastUpdated) {
buf.append(mCtx.getString(R.string.news_last_checked,
DataHelper.formatDuration2(now - _lastFetch)));
}
return buf.toString();
}
// Runnable
private static final long INITIAL_DELAY = 5 * 60 * 1000;
private static final long RUN_DELAY = 30 * 60 * 1000;
public void run() {
_thread = Thread.currentThread();
try {
Thread.sleep(INITIAL_DELAY);
} catch (InterruptedException ie) {
return;
}
while (_isRunning && _context.router().isAlive()) {
if (shouldFetchNews()) {
fetchNews();
}
try {
Thread.sleep(RUN_DELAY);
} catch (InterruptedException ie) {
break;
}
}
}
private boolean shouldFetchNews() {
if (_invalidated)
return true;
updateLastFetched();
String freq = _context.getProperty(PROP_REFRESH_FREQUENCY,
DEFAULT_REFRESH_FREQUENCY);
try {
long ms = Long.parseLong(freq);
if (ms <= 0)
return false;
if (_lastFetch + ms < _context.clock().now()) {
return true;
} else {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Last fetched " + DataHelper.formatDuration(_context.clock().now() - _lastFetch) + " ago");
return false;
}
} catch (NumberFormatException nfe) {
if (_log.shouldLog(Log.ERROR))
_log.error("Invalid refresh frequency: " + freq);
return false;
}
}
/**
* Call this when changing news URLs to force an update next time the timer fires.
*
* @since 0.8.7
*/
void invalidateNews() {
_lastModified = null;
_invalidated = true;
}
public void fetchNews() {
String newsURL = _context.getProperty(PROP_NEWS_URL, DEFAULT_NEWS_URL_SU3);
String proxyHost = "127.0.0.1";
int proxyPort = 4444;
if (_tempFile.exists())
_tempFile.delete();
try {
// EepGet get = null;
EepGet get = new EepGet(_context, true, proxyHost, proxyPort, 0, _tempFile.getAbsolutePath(), newsURL, true, null, _lastModified);
get.addStatusListener(this);
if (get.fetch()) {
_lastModified = get.getLastModified();
_invalidated = false;
} else {
// backup news location - always proxied
_tempFile.delete();
get = new EepGet(_context, true, proxyHost, proxyPort, 0, _tempFile.getAbsolutePath(), BACKUP_NEWS_URL_SU3, true, null, _lastModified);
get.addStatusListener(this);
if (get.fetch())
_lastModified = get.getLastModified();
}
} catch (Throwable t) {
_log.error("Error fetching the news", t);
}
}
// EepGet.StatusListener
public void bytesTransferred(long alreadyTransferred, int currentWrite, long bytesTransferred, long bytesRemaining, String url) {
// ignore
}
public void transferComplete(long alreadyTransferred, long bytesTransferred, long bytesRemaining, String url, String outputFile, boolean notModified) {
if (_log.shouldLog(Log.INFO))
_log.info("News fetched from " + url + " with " + (alreadyTransferred + bytesTransferred));
long now = _context.clock().now();
if (_tempFile.exists() && _tempFile.length() > 0) {
File from;
if (url.endsWith(".su3")) {
try {
from = processSU3();
} catch (IOException ioe) {
_log.error("Failed to extract the news file", ioe);
_tempFile.delete();
return;
}
} else {
from = _tempFile;
}
boolean copied = FileUtil.rename(from, _newsFile);
_tempFile.delete();
if (copied) {
_lastUpdated = now;
// Notify user
_notif.notify(mCtx.getString(R.string.news_updated),
mCtx.getString(R.string.view_news),
NewsActivity.class);
} else {
if (_log.shouldLog(Log.ERROR))
_log.error("Failed to copy the news file!");
}
} else {
if (_log.shouldLog(Log.WARN))
_log.warn("Transfer complete, but no file? - probably 304 Not Modified");
}
_lastFetch = now;
_context.router().setConfigSetting(PROP_LAST_CHECKED, "" + now);
_context.router().saveConfig();
}
public void attemptFailed(String url, long bytesTransferred, long bytesRemaining, int currentAttempt, int numRetries, Exception cause) {
// ignore
}
public void transferFailed(String url, long bytesTransferred, long bytesRemaining, int currentAttempt) {
if (_log.shouldLog(Log.WARN))
_log.warn("Failed to fetch the news from " + url);
_tempFile.delete();
}
public void headerReceived(String url, int attemptNum, String key, String val) {
}
public void attempting(String url) {
}
private class Shutdown implements Runnable {
public void run() {
_isRunning = false;
if (_thread != null)
_thread.interrupt();
}
}
//
// SU3 handlers
//
/**
* Process the fetched su3 news file _tempFile.
* Handles 3 types of contained files: xml.gz (preferred), xml, and html (old format fake xml)
*
* @return the temp file contining the HTML-format news.xml
* @since 0.9.20
*/
private File processSU3() throws IOException {
SU3File su3 = new SU3File(_context, _tempFile);
// real xml, maybe gz, maybe not
File to1 = new File(_context.getTempDir(), "tmp-" + _context.random().nextInt() + ".xml");
// real xml
File to2 = new File(_context.getTempDir(), "tmp2-" + _context.random().nextInt() + ".xml");
try {
su3.verifyAndMigrate(to1);
int type = su3.getFileType();
if (su3.getContentType() != SU3File.CONTENT_NEWS)
throw new IOException("bad content type: " + su3.getContentType());
if (type == SU3File.TYPE_HTML)
return to1;
if (type != SU3File.TYPE_XML && type != SU3File.TYPE_XML_GZ)
throw new IOException("bad file type: " + type);
File xml;
if (type == SU3File.TYPE_XML_GZ) {
gunzip(to1, to2);
xml = to2;
to1.delete();
} else {
xml = to1;
}
NewsXMLParser parser = new NewsXMLParser(_context);
parser.parse(xml);
xml.delete();
NewsMetadata data = parser.getMetadata();
List<NewsEntry> entries = parser.getEntries();
String sudVersion = su3.getVersionString();
String signingKeyName = su3.getSignerString();
File to3 = new File(_context.getTempDir(), "tmp3-" + _context.random().nextInt() + ".xml");
outputOldNewsXML(data, entries, sudVersion, signingKeyName, to3);
return to3;
} finally {
to2.delete();
}
}
/**
* Gunzip the file
*
* @since 0.9.20
*/
private static void gunzip(File from, File to) throws IOException {
ReusableGZIPInputStream in = ReusableGZIPInputStream.acquire();
OutputStream out = null;
try {
in.initialize(new FileInputStream(from));
out = new SecureFileOutputStream(to);
byte buf[] = new byte[4096];
int read;
while ((read = in.read(buf)) != -1) {
out.write(buf, 0, read);
}
} finally {
if (out != null) try {
out.close();
} catch (IOException ioe) {}
ReusableGZIPInputStream.release(in);
}
}
/**
* Output in the old format.
*
* @since 0.9.20
*/
private void outputOldNewsXML(NewsMetadata data, List<NewsEntry> entries,
String sudVersion, String signingKeyName, File to) throws IOException {
NewsMetadata.Release latestRelease = data.releases.get(0);
Writer out = null;
try {
out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(to), "UTF-8"));
out.write("<!--\n");
// update metadata in old format
out.write("<i2p.release ");
if (latestRelease.i2pVersion != null)
out.write(" version=\"" + latestRelease.i2pVersion + '"');
if (latestRelease.minVersion != null)
out.write(" minVersion=\"" + latestRelease.minVersion + '"');
if (latestRelease.minJavaVersion != null)
out.write(" minJavaVersion=\"" + latestRelease.minJavaVersion + '"');
String su3Torrent = "";
String su2Torrent = "";
for (NewsMetadata.Update update : latestRelease.updates) {
if (update.torrent != null) {
if ("su3".equals(update.type))
su3Torrent = update.torrent;
else if ("su2".equals(update.type))
su2Torrent = update.torrent;
}
}
if (!su2Torrent.isEmpty())
out.write(" su2Torrent=\"" + su2Torrent + '"');
if (!su3Torrent.isEmpty())
out.write(" su3Torrent=\"" + su3Torrent + '"');
out.write("/>\n");
// su3 and feed metadata for debugging
out.write("** News version:\t" + DataHelper.stripHTML(sudVersion) + '\n');
out.write("** Signed by:\t" + signingKeyName + '\n');
out.write("** Feed:\t" + DataHelper.stripHTML(data.feedTitle) + '\n');
out.write("** Feed ID:\t" + DataHelper.stripHTML(data.feedID) + '\n');
out.write("** Feed Date:\t" + (new Date(data.feedUpdated)) + '\n');
out.write("-->\n");
if (entries == null)
return;
for (NewsEntry e : entries) {
if (e.title == null || e.content == null)
continue;
out.write("<!-- Entry Date: " + (new Date(e.updated)) + " -->\n");
out.write("<h3>");
out.write(e.title);
out.write("</h3>\n");
out.write(e.content);
out.write("\n\n");
}
} finally {
if (out != null) try {
out.close();
} catch (IOException ioe) {}
}
}
}

View File

@ -0,0 +1,83 @@
package net.i2p.android.help;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.graphics.drawable.Drawable;
import android.support.annotation.NonNull;
public class Browser implements Comparable<Browser> {
public final String packageName;
public final CharSequence label;
public final Drawable icon;
public final boolean isInstalled;
public final boolean isKnown;
public final boolean isSupported;
public final boolean isRecommended;
/**
* A browser that we don't know about.
*
* @param pm the PackageManager used to find the browser
* @param browser the browser
*/
public Browser(PackageManager pm, ResolveInfo browser) {
this(
browser.activityInfo.packageName,
browser.loadLabel(pm),
browser.loadIcon(pm),
true, false, false, false
);
}
/**
* A browser that we know about.
*
* @param pm the PackageManager used to find the browser
* @param browser the browser
* @param supported can this browser be used with I2P?
*/
public Browser(PackageManager pm, ResolveInfo browser, boolean supported, boolean recommended) {
this(
browser.activityInfo.packageName,
browser.loadLabel(pm),
browser.loadIcon(pm),
true, true, supported, recommended
);
}
public Browser(String pn, CharSequence l, Drawable ic, boolean i, boolean k, boolean s, boolean r) {
packageName = pn;
label = l;
icon = ic;
isInstalled = i;
isKnown = k;
isSupported = s;
isRecommended = r;
}
@Override
public int compareTo(@NonNull Browser browser) {
// Sort order: supported -> unknown -> unsupported
int a = getOrder(this);
int b = getOrder(browser);
if (a < b)
return -1;
else if (a > b)
return 1;
return label.toString().compareTo(browser.label.toString());
}
private static int getOrder(Browser browser) {
if (browser.isKnown) {
if (browser.isRecommended)
return 0;
else if (browser.isSupported)
return 1;
else
return 3;
} else
return 2;
}
}

View File

@ -0,0 +1,117 @@
package net.i2p.android.help;
import android.content.Context;
import android.content.Intent;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.net.Uri;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import net.i2p.android.router.R;
public class BrowserAdapter extends RecyclerView.Adapter<BrowserAdapter.ViewHolder> {
private Context mCtx;
private Browser[] mBrowsers;
private OnBrowserSelectedListener mListener;
// Provide a reference to the views for each data item
// Complex data items may need more than one view per item, and
// you provide access to all the views for a data item in a view holder
public static class ViewHolder extends RecyclerView.ViewHolder {
public ImageView mIcon;
public TextView mLabel;
public ImageView mStatus;
public ViewHolder(View v) {
super(v);
mIcon = (ImageView) v.findViewById(R.id.browser_icon);
mLabel = (TextView) v.findViewById(R.id.browser_label);
mStatus = (ImageView) v.findViewById(R.id.browser_status_icon);
}
}
public interface OnBrowserSelectedListener {
void onBrowserSelected(Browser browser);
}
public BrowserAdapter(Context ctx, OnBrowserSelectedListener listener) {
mCtx = ctx;
mListener = listener;
}
public void setBrowsers(Browser[] browsers) {
mBrowsers = browsers;
notifyDataSetChanged();
}
public void clear() {
mBrowsers = null;
notifyDataSetChanged();
}
// Create new views (invoked by the layout manager)
@Override
public BrowserAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,
int viewType) {
View v = LayoutInflater.from(parent.getContext())
.inflate(R.layout.listitem_browser, parent, false);
return new ViewHolder(v);
}
// Replace the contents of a view (invoked by the layout manager)
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
final Browser browser = mBrowsers[position];
holder.mIcon.setImageDrawable(browser.icon);
holder.mLabel.setText(browser.label);
if (browser.isKnown) {
if (browser.isRecommended && browser.isInstalled) {
holder.mStatus.setImageDrawable(
mCtx.getResources().getDrawable(R.drawable.ic_stars_white_24dp));
holder.mStatus.setVisibility(View.VISIBLE);
} else if (browser.isSupported && !browser.isInstalled) {
holder.mStatus.setImageDrawable(
mCtx.getResources().getDrawable(R.drawable.ic_shop_white_24dp));
holder.mStatus.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String uriMarket = "market://search?q=pname:" + browser.packageName;
Uri uri = Uri.parse(uriMarket);
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
mCtx.startActivity(intent);
}
});
holder.mStatus.setVisibility(View.VISIBLE);
} else if (!browser.isSupported) {
// Make the icon gray-scale to show it is unsupported
ColorMatrix matrix = new ColorMatrix();
matrix.setSaturation(0);
ColorMatrixColorFilter filter = new ColorMatrixColorFilter(matrix);
holder.mIcon.setColorFilter(filter);
holder.mLabel.setTextColor(
mCtx.getResources().getColor(R.color.primary_text_disabled_material_dark));
}
}
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mListener.onBrowserSelected(browser);
}
});
}
// Return the size of the dataset (invoked by the layout manager)
@Override
public int getItemCount() {
if (mBrowsers != null)
return mBrowsers.length;
return 0;
}
}

View File

@ -0,0 +1,104 @@
package net.i2p.android.help;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.MenuItem;
import net.i2p.android.router.R;
import net.i2p.android.util.LocaleManager;
import java.lang.reflect.Field;
public class BrowserConfigActivity extends AppCompatActivity implements
BrowserAdapter.OnBrowserSelectedListener {
/**
* Whether or not the activity is in two-pane mode, i.e. running on a tablet
* device.
*/
private boolean mTwoPane;
private final LocaleManager localeManager = new LocaleManager();
@Override
public void onCreate(Bundle savedInstanceState) {
localeManager.onCreate(this);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_help);
// Set the action bar
Toolbar toolbar = (Toolbar) findViewById(R.id.main_toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
if (findViewById(R.id.detail_fragment) != null) {
// The detail container view will be present only in the
// large-screen layouts (res/values-large and
// res/values-sw600dp). If this view is present, then the
// activity should be in two-pane mode.
mTwoPane = true;
}
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction()
.add(R.id.main_fragment, new BrowserListFragment())
.commit();
}
}
@Override
public void onResume() {
super.onResume();
localeManager.onResume(this);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
onBackPressed();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
// BrowserAdapter.OnBrowserSelected
@Override
public void onBrowserSelected(Browser browser) {
int file;
if (browser.isKnown) {
if (browser.isSupported) {
// Check for embedded browser
if (browser.packageName.startsWith("net.i2p.android"))
file = R.raw.help_embedded_browser;
else {
// Load the configuration guide for this browser
try {
String name = "help_" + browser.packageName.replace('.', '_');
Class res = R.raw.class;
Field field = res.getField(name);
file = field.getInt(null);
} catch (Exception e) {
file = R.raw.help_unknown_browser;
}
}
} else
file = R.raw.help_unsupported_browser;
} else
file = R.raw.help_unknown_browser;
HelpHtmlFragment configFrag = HelpHtmlFragment.newInstance(file);
if (mTwoPane) {
getSupportFragmentManager().beginTransaction()
.replace(R.id.detail_fragment, configFrag)
.commit();
} else {
getSupportFragmentManager().beginTransaction()
.replace(R.id.main_fragment, configFrag)
.addToBackStack("config" + browser.packageName)
.commit();
}
}
}

View File

@ -0,0 +1,191 @@
package net.i2p.android.help;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.Loader;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import net.i2p.android.router.R;
import net.i2p.android.router.util.BetterAsyncTaskLoader;
import net.i2p.android.widget.DividerItemDecoration;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class BrowserListFragment extends Fragment implements
LoaderManager.LoaderCallbacks<List<Browser>> {
private static final int BROWSER_LOADER_ID = 1;
private BrowserAdapter.OnBrowserSelectedListener mCallback;
private BrowserAdapter mAdapter;
@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 {
mCallback = (BrowserAdapter.OnBrowserSelectedListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement OnBrowserSelectedListener");
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_help_browsers, container, false);
RecyclerView mRecyclerView = (RecyclerView) v.findViewById(R.id.browser_list);
mRecyclerView.setHasFixedSize(true);
mRecyclerView.addItemDecoration(new DividerItemDecoration(getActivity(), DividerItemDecoration.VERTICAL_LIST));
// use a linear layout manager
RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getActivity());
mRecyclerView.setLayoutManager(mLayoutManager);
mAdapter = new BrowserAdapter(getActivity(), mCallback);
mRecyclerView.setAdapter(mAdapter);
return v;
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
getLoaderManager().initLoader(BROWSER_LOADER_ID, null, this);
}
// LoaderManager.LoaderCallbacks<List<Browser>>
@Override
public Loader<List<Browser>> onCreateLoader(int id, Bundle args) {
return new BrowserLoader(getActivity());
}
public static class BrowserLoader extends BetterAsyncTaskLoader<List<Browser>> {
private List<String> recommended;
private List<String> recommendedLabels;
private List<String> supported;
private List<String> supportedLabels;
private List<String> unsupported;
public BrowserLoader(Context context) {
super(context);
recommended = Arrays.asList(
getContext().getResources().getStringArray(R.array.recommended_browsers));
recommendedLabels = Arrays.asList(
getContext().getResources().getStringArray(R.array.recommended_browser_labels));
supported = Arrays.asList(
getContext().getResources().getStringArray(R.array.supported_browsers));
supportedLabels = Arrays.asList(
getContext().getResources().getStringArray(R.array.supported_browser_labels));
unsupported = Arrays.asList(
context.getResources().getStringArray(R.array.unsupported_browsers));
}
@Override
public List<Browser> loadInBackground() {
List<Browser> browsers = new ArrayList<>();
Map<String, String> recommendedMap = new HashMap<>();
for (int i = 0; i < recommended.size(); i++) {
recommendedMap.put(recommended.get(i), recommendedLabels.get(i));
}
Map<String, String> supportedMap = new HashMap<>();
for (int i = 0; i < supported.size(); i++) {
supportedMap.put(supported.get(i), supportedLabels.get(i));
}
// Find all installed browsers that listen for ".i2p"
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("http://stats.i2p"));
final PackageManager pm = getContext().getPackageManager();
List<ResolveInfo> installedBrowsers = pm.queryIntentActivities(intent, 0);
for (ResolveInfo browser : installedBrowsers) {
if (recommended.contains(browser.activityInfo.packageName)) {
browsers.add(new Browser(pm, browser, true, true));
recommendedMap.remove(browser.activityInfo.packageName);
} else if (supported.contains(browser.activityInfo.packageName) ||
browser.activityInfo.packageName.startsWith("net.i2p.android")) {
browsers.add(new Browser(pm, browser, true, false));
supportedMap.remove(browser.activityInfo.packageName);
} else if (unsupported.contains(browser.activityInfo.packageName))
browsers.add(new Browser(pm, browser, false, false));
else
browsers.add(new Browser(pm, browser));
}
// Now add the remaining recommended and supported browsers
for (Map.Entry<String, String> browser : recommendedMap.entrySet()) {
browsers.add(new Browser(browser.getKey(), browser.getValue(),
getDrawableForPackage(browser.getKey()),
false, true, true, true));
}
for (Map.Entry<String, String> browser : supportedMap.entrySet()) {
browsers.add(new Browser(browser.getKey(), browser.getValue(),
getDrawableForPackage(browser.getKey()),
false, true, true, false));
}
Collections.sort(browsers);
return browsers;
}
private Drawable getDrawableForPackage(String packageName) {
try {
String name = "icon_" + packageName.replace('.', '_');
Class res = R.drawable.class;
Field field = res.getField(name);
int drawable = field.getInt(null);
return getContext().getResources().getDrawable(drawable);
} catch (Exception e) {
return null;
}
}
@Override
protected void onStartMonitoring() {
}
@Override
protected void onStopMonitoring() {
}
@Override
protected void releaseResources(List<Browser> data) {
}
}
@Override
public void onLoadFinished(Loader<List<Browser>> listLoader, List<Browser> browsers) {
if (listLoader.getId() == BROWSER_LOADER_ID)
mAdapter.setBrowsers(browsers.toArray(new Browser[browsers.size()]));
}
@Override
public void onLoaderReset(Loader<List<Browser>> listLoader) {
if (listLoader.getId() == BROWSER_LOADER_ID)
mAdapter.clear();
}
}

View File

@ -0,0 +1,165 @@
package net.i2p.android.help;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.NavUtils;
import android.support.v4.app.TaskStackBuilder;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
import net.i2p.android.router.LicenseActivity;
import net.i2p.android.router.R;
import net.i2p.android.router.dialog.TextResourceDialog;
import net.i2p.android.util.LocaleManager;
public class HelpActivity extends AppCompatActivity implements
HelpListFragment.OnEntrySelectedListener {
public static final String CATEGORY = "help_category";
public static final int CAT_MAIN = 0;
public static final int CAT_CONFIGURE_BROWSER = 1;
public static final int CAT_ADDRESSBOOK = 2;
public static final int CAT_I2PTUNNEL = 3;
/**
* Whether or not the activity is in two-pane mode, i.e. running on a tablet
* device.
*/
private boolean mTwoPane;
private int mCategory;
private final LocaleManager localeManager = new LocaleManager();
@Override
public void onCreate(Bundle savedInstanceState) {
localeManager.onCreate(this);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_help);
// Set the action bar
Toolbar toolbar = (Toolbar) findViewById(R.id.main_toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
if (findViewById(R.id.detail_fragment) != null) {
// The detail container view will be present only in the
// large-screen layouts (res/values-large and
// res/values-sw600dp). If this view is present, then the
// activity should be in two-pane mode.
mTwoPane = true;
}
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction()
.add(R.id.main_fragment, new HelpListFragment())
.commit();
}
mCategory = getIntent().getIntExtra(CATEGORY, -1);
if (mCategory >= 0) {
showCategory(mCategory);
}
}
@Override
public void onResume() {
super.onResume();
localeManager.onResume(this);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_help_actions, menu);
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
if (mCategory >= 0) {
onBackPressed();
} else {
Intent upIntent = NavUtils.getParentActivityIntent(this);
if (NavUtils.shouldUpRecreateTask(this, upIntent)) {
// This activity is NOT part of this app's task, so create a new task
// when navigating up, with a synthesized back stack.
TaskStackBuilder.create(this)
// Add all of this activity's parents to the back stack
.addNextIntentWithParentStack(upIntent)
// Navigate up to the closest parent
.startActivities();
} else {
// This activity is part of this app's task, so simply
// navigate up to the logical parent activity.
NavUtils.navigateUpTo(this, upIntent);
}
}
return true;
case R.id.menu_help_licenses:
Intent lic = new Intent(HelpActivity.this, LicenseActivity.class);
startActivity(lic);
return true;
case R.id.menu_help_release_notes:
TextResourceDialog dialog = new TextResourceDialog();
Bundle args = new Bundle();
args.putString(TextResourceDialog.TEXT_DIALOG_TITLE,
getResources().getString(R.string.label_release_notes));
args.putInt(TextResourceDialog.TEXT_RESOURCE_ID, R.raw.releasenotes_txt);
dialog.setArguments(args);
dialog.show(getSupportFragmentManager(), "release_notes");
return true;
default:
return super.onOptionsItemSelected(item);
}
}
@Override
public void onBackPressed() {
super.onBackPressed();
if (mCategory >= 0)
mCategory = -1;
}
// HelpListFragment.OnEntrySelectedListener
@Override
public void onEntrySelected(int entry) {
if (entry == CAT_CONFIGURE_BROWSER) {
Intent i = new Intent(this, BrowserConfigActivity.class);
startActivity(i);
} else {
mCategory = entry;
showCategory(entry);
}
}
private void showCategory(int category) {
int file;
switch (category) {
case CAT_ADDRESSBOOK:
file = R.raw.help_addressbook;
break;
case CAT_I2PTUNNEL:
file = R.raw.help_i2ptunnel;
break;
case CAT_MAIN:
default:
file = R.raw.help_main;
break;
}
HelpHtmlFragment f = HelpHtmlFragment.newInstance(file);
if (mTwoPane) {
getSupportFragmentManager().beginTransaction()
.replace(R.id.detail_fragment, f).commit();
} else {
getSupportFragmentManager().beginTransaction()
.replace(R.id.main_fragment, f)
.addToBackStack("help" + category)
.commit();
}
}
}

View File

@ -0,0 +1,36 @@
package net.i2p.android.help;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ScrollView;
import net.i2p.android.router.R;
import org.sufficientlysecure.htmltextview.HtmlTextView;
public class HelpHtmlFragment extends Fragment {
public static final String ARG_HTML_FILE = "htmlFile";
static HelpHtmlFragment newInstance(int htmlFile) {
HelpHtmlFragment f = new HelpHtmlFragment();
Bundle args = new Bundle();
args.putInt(ARG_HTML_FILE, htmlFile);
f.setArguments(args);
return f;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
ScrollView scroller = new ScrollView(getActivity());
HtmlTextView text = new HtmlTextView(getActivity());
scroller.addView(text);
int padH = getResources().getDimensionPixelOffset(R.dimen.activity_horizontal_margin);
int padV = getResources().getDimensionPixelOffset(R.dimen.activity_vertical_margin);
text.setPadding(padH, padV, padH, padV);
text.setHtmlFromRawResource(getActivity(), getArguments().getInt(ARG_HTML_FILE), true);
return scroller;
}
}

View File

@ -0,0 +1,47 @@
package net.i2p.android.help;
import android.app.Activity;
import android.os.Bundle;
import android.support.v4.app.ListFragment;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import net.i2p.android.router.R;
public class HelpListFragment extends ListFragment {
OnEntrySelectedListener mEntrySelectedCallback;
// Container Activity must implement this interface
public interface OnEntrySelectedListener {
void onEntrySelected(int entry);
}
@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 void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setListAdapter(ArrayAdapter.createFromResource(getActivity(),
R.array.help_categories, R.layout.listitem_text));
}
@Override
public void onListItemClick(ListView parent, View view, int pos, long id) {
super.onListItemClick(parent, view, pos, id);
mEntrySelectedCallback.onEntrySelected(pos);
}
}

View File

@ -0,0 +1,65 @@
package net.i2p.android.i2ptunnel;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.ActivityCompat;
import android.support.v7.widget.Toolbar;
import android.view.View;
import net.i2p.android.I2PActivityBase;
import net.i2p.android.i2ptunnel.preferences.EditTunnelActivity;
import net.i2p.android.router.R;
public class TunnelDetailActivity extends I2PActivityBase implements
TunnelDetailFragment.TunnelDetailListener {
private boolean transitionReversed;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
transitionReversed = false;
if (savedInstanceState == null) {
int tunnelId = getIntent().getIntExtra(TunnelDetailFragment.TUNNEL_ID, 0);
TunnelDetailFragment detailFrag = TunnelDetailFragment.newInstance(tunnelId);
getSupportFragmentManager().beginTransaction()
.add(android.R.id.content, detailFrag).commit();
}
}
@Override
public void onStart() {
super.onStart();
Toolbar toolbar = (Toolbar) findViewById(R.id.detail_toolbar);
toolbar.setNavigationIcon(getResources().getDrawable(R.drawable.ic_arrow_back_white_24dp));
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onBackPressed();
}
});
}
@Override
public void finish() {
if (transitionReversed)
super.finish();
else {
transitionReversed = true;
ActivityCompat.finishAfterTransition(this);
}
}
// TunnelDetailFragment.TunnelDetailListener
@Override
public void onEditTunnel(int tunnelId) {
Intent editIntent = new Intent(this, EditTunnelActivity.class);
editIntent.putExtra(TunnelDetailFragment.TUNNEL_ID, tunnelId);
startActivity(editIntent);
}
public void onTunnelDeleted(int tunnelId, int numTunnelsLeft) {
finish();
}
}

View File

@ -0,0 +1,277 @@
package net.i2p.android.i2ptunnel;
import android.app.Activity;
import android.app.Dialog;
import android.content.ActivityNotFoundException;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.Fragment;
import android.support.v7.app.AlertDialog;
import android.support.v7.widget.Toolbar;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.TextView;
import android.widget.Toast;
import net.i2p.I2PAppContext;
import net.i2p.android.i2ptunnel.util.TunnelUtil;
import net.i2p.android.router.R;
import net.i2p.android.util.FragmentUtils;
import net.i2p.app.ClientAppState;
import net.i2p.i2ptunnel.TunnelControllerGroup;
import java.util.List;
public class TunnelDetailFragment extends Fragment {
public static final String TUNNEL_ID = "tunnel_id";
TunnelDetailListener mCallback;
private TunnelControllerGroup mGroup;
private TunnelEntry mTunnel;
private Toolbar mToolbar;
public static TunnelDetailFragment newInstance(int tunnelId) {
TunnelDetailFragment f = new TunnelDetailFragment();
Bundle args = new Bundle();
args.putInt(TUNNEL_ID, tunnelId);
f.setArguments(args);
return f;
}
// Container Activity must implement this interface
public interface TunnelDetailListener {
void onEditTunnel(int tunnelId);
void onTunnelDeleted(int tunnelId, int numTunnelsLeft);
}
@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
mCallback = FragmentUtils.getParent(this, TunnelDetailListener.class);
if (mCallback == null)
throw new ClassCastException("Parent must implement TunnelDetailListener");
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String error;
try {
mGroup = TunnelControllerGroup.getInstance();
error = mGroup == null ? getResources().getString(R.string.i2ptunnel_not_initialized) : null;
} catch (IllegalArgumentException iae) {
mGroup = null;
error = iae.toString();
}
if (mGroup == null) {
// Show error
} else if (getArguments().containsKey(TUNNEL_ID)) {
int tunnelId = getArguments().getInt(TUNNEL_ID);
mTunnel = new TunnelEntry(getActivity(),
mGroup.getControllers().get(tunnelId),
tunnelId);
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_i2ptunnel_detail, container, false);
mToolbar = (Toolbar) v.findViewById(R.id.detail_toolbar);
mToolbar.inflateMenu(R.menu.fragment_i2ptunnel_detail_actions);
mToolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem menuItem) {
return onToolbarItemSelected(menuItem);
}
});
updateToolbar();
if (mTunnel != null) {
TextView name = (TextView) v.findViewById(R.id.tunnel_name);
name.setText(mTunnel.getName());
TextView type = (TextView) v.findViewById(R.id.tunnel_type);
type.setText(mTunnel.getType());
TextView description = (TextView) v.findViewById(R.id.tunnel_description);
description.setText(mTunnel.getDescription());
TextView details = (TextView) v.findViewById(R.id.tunnel_details);
details.setText(mTunnel.getDetails());
View accessIfacePortItem = v.findViewById(R.id.tunnel_access_interface_port_item);
TextView accessIfacePort = (TextView) v.findViewById(R.id.tunnel_access_interface_port);
View accessIfaceOpen = v.findViewById(R.id.tunnel_access_open);
View targetIfacePortItem = v.findViewById(R.id.tunnel_target_interface_port_item);
TextView targetIfacePort = (TextView) v.findViewById(R.id.tunnel_target_interface_port);
View targetIfaceOpen = v.findViewById(R.id.tunnel_target_open);
switch (mTunnel.getInternalType()) {
case "httpbidirserver":
accessIfacePort.setText(mTunnel.getClientLink(false));
setupOpen(accessIfaceOpen, true);
v.findViewById(R.id.icon_link_access).setVisibility(View.GONE);
targetIfacePort.setText(mTunnel.getServerLink(false));
setupOpen(targetIfaceOpen, false);
break;
case "streamrserver":
accessIfacePort.setText(mTunnel.getServerLink(false));
setupOpen(accessIfaceOpen, true);
targetIfacePortItem.setVisibility(View.GONE);
break;
case "streamrclient":
accessIfacePortItem.setVisibility(View.GONE);
targetIfacePort.setText(mTunnel.getClientLink(false));
setupOpen(targetIfaceOpen, false);
break;
default:
if (mTunnel.isClient()) {
accessIfacePort.setText(mTunnel.getClientLink(false));
setupOpen(accessIfaceOpen, true);
targetIfacePortItem.setVisibility(View.GONE);
} else {
accessIfacePortItem.setVisibility(View.GONE);
targetIfacePort.setText(mTunnel.getServerLink(false));
setupOpen(targetIfaceOpen, false);
}
}
CheckBox autoStart = (CheckBox) v.findViewById(R.id.tunnel_autostart);
autoStart.setChecked(mTunnel.startAutomatically());
}
return v;
}
private void setupOpen(View open, final boolean client) {
if (mTunnel.isRunning() &&
(client ? mTunnel.isClientLinkValid() : mTunnel.isServerLinkValid())) {
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(client ? mTunnel.getClientLink(true) : mTunnel.getServerLink(true)));
try {
startActivity(i);
} catch (ActivityNotFoundException e) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setTitle(R.string.install_recommended_app)
.setMessage(R.string.app_needed_for_this_tunnel_type)
.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialogInterface, int i) {
Uri uri = mTunnel.getRecommendedAppForTunnel();
if (uri != null) {
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
}
}
})
.setNegativeButton(net.i2p.android.lib.client.R.string.no, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialogInterface, int i) {
}
});
builder.show();
}
}
});
} else
open.setVisibility(View.GONE);
}
private void updateToolbar() {
Menu menu = mToolbar.getMenu();
MenuItem start = menu.findItem(R.id.action_start_tunnel);
MenuItem stop = menu.findItem(R.id.action_stop_tunnel);
if (mTunnel != null && mGroup != null &&
(mGroup.getState() == ClientAppState.STARTING ||
mGroup.getState() == ClientAppState.RUNNING)) {
boolean isStopped = mTunnel.getStatus() == TunnelEntry.NOT_RUNNING;
start.setVisible(isStopped);
start.setEnabled(isStopped);
stop.setVisible(!isStopped);
stop.setEnabled(!isStopped);
} else {
start.setVisible(false);
start.setEnabled(false);
stop.setVisible(false);
stop.setEnabled(false);
}
}
private boolean onToolbarItemSelected(MenuItem item) {
if (mTunnel == null)
return false;
// Handle presses on the action bar items
switch (item.getItemId()) {
case R.id.action_start_tunnel:
mTunnel.getController().startTunnelBackground();
Toast.makeText(getActivity().getApplicationContext(),
getResources().getString(R.string.i2ptunnel_msg_tunnel_starting)
+ ' ' + mTunnel.getName(), Toast.LENGTH_LONG).show();
// Reload the toolbar to change the start/stop action
updateToolbar();
return true;
case R.id.action_stop_tunnel:
mTunnel.getController().stopTunnel();
Toast.makeText(getActivity().getApplicationContext(),
getResources().getString(R.string.i2ptunnel_msg_tunnel_stopping)
+ ' ' + mTunnel.getName(), Toast.LENGTH_LONG).show();
// Reload the toolbar to change the start/stop action
updateToolbar();
return true;
case R.id.action_edit_tunnel:
mCallback.onEditTunnel(mTunnel.getId());
return true;
case R.id.action_delete_tunnel:
DialogFragment dg = new DialogFragment() {
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
return new AlertDialog.Builder(getActivity())
.setMessage(R.string.i2ptunnel_delete_confirm_message)
.setPositiveButton(R.string.i2ptunnel_delete_confirm_button,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
List<String> msgs = TunnelUtil.deleteTunnel(
I2PAppContext.getGlobalContext(),
mGroup, mTunnel.getId(), null);
dialog.dismiss();
Toast.makeText(getActivity().getApplicationContext(),
msgs.get(0), Toast.LENGTH_LONG).show();
mCallback.onTunnelDeleted(mTunnel.getId(),
mGroup.getControllers().size());
}
})
.setNegativeButton(android.R.string.cancel, null)
.create();
}
};
dg.show(getFragmentManager(), "delete_tunnel_dialog");
return true;
default:
return super.onOptionsItemSelected(item);
}
}
}

View File

@ -0,0 +1,287 @@
package net.i2p.android.i2ptunnel;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.widget.Toast;
import net.i2p.I2PAppContext;
import net.i2p.android.i2ptunnel.util.TunnelUtil;
import net.i2p.android.router.R;
import net.i2p.data.Destination;
import net.i2p.data.PrivateKeyFile;
import net.i2p.i2ptunnel.TunnelController;
import net.i2p.i2ptunnel.TunnelControllerGroup;
import net.i2p.i2ptunnel.ui.TunnelConfig;
import java.util.List;
public class TunnelEntry {
public static final int RUNNING = 1;
public static final int STARTING = 2;
public static final int NOT_RUNNING = 3;
public static final int STANDBY = 4;
private final Context mContext;
private final TunnelController mController;
private final int mId;
public static TunnelEntry createNewTunnel(
Context ctx,
TunnelControllerGroup tcg,
TunnelConfig cfg) {
int tunnelId = tcg.getControllers().size();
List<String> msgs = TunnelUtil.saveTunnel(
I2PAppContext.getGlobalContext(), tcg, -1, cfg);
// TODO: Do something else with the other messages.
Toast.makeText(ctx.getApplicationContext(),
msgs.get(0), Toast.LENGTH_LONG).show();
TunnelController cur = TunnelUtil.getController(tcg, tunnelId);
return new TunnelEntry(ctx, cur, tunnelId);
}
public TunnelEntry(Context context, TunnelController controller, int id) {
mContext = context;
mController = controller;
mId = id;
}
public int getId() {
return mId;
}
public TunnelController getController() {
return mController;
}
/* General tunnel data for any type */
public String getName() {
if (mController.getName() != null)
return mController.getName();
else
return mContext.getResources()
.getString(R.string.i2ptunnel_new_tunnel);
}
public String getInternalType() {
return mController.getType();
}
public String getType() {
return TunnelUtil.getTypeName(mController.getType(), mContext);
}
public String getDescription() {
String rv = mController.getDescription();
if (rv != null)
return rv;
return "";
}
public boolean startAutomatically() {
return mController.getStartOnLoad();
}
public int getStatus() {
if (mController.getIsRunning()) {
if (isClient() && mController.getIsStandby())
return STANDBY;
else
return RUNNING;
} else if (mController.getIsStarting()) return STARTING;
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());
}
/* Client tunnel data */
public boolean isSharedClient() {
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()))
rv = mController.getTargetHost();
else
rv = mController.getListenOnInterface();
return rv != null ? rv : "";
}
public String getClientPort() {
String rv = mController.getListenPort();
return rv != null ? rv : "";
}
public String getClientDestination() {
String rv;
if ("client".equals(getInternalType()) ||
"ircclient".equals(getInternalType()) ||
"streamrclient".equals(getInternalType()))
rv = mController.getTargetDestination();
else
rv = mController.getProxyList();
return rv != null ? rv : "";
}
/* Server tunnel data */
/**
* Call this to see if it is okay to linkify getServerLink()
* @return true if getServerLink() can be linkified, false otherwise.
*/
public boolean isServerLinkValid() {
return ("httpserver".equals(mController.getType()) ||
"httpbidirserver".equals(mController.getType())) &&
mController.getTargetHost() != null &&
mController.getTargetPort() != null;
}
/**
* @return valid host:port only if isServerLinkValid() is true
*/
public String getServerLink(boolean linkify) {
String host;
if ("streamrserver".equals(getInternalType()))
host = mController.getListenOnInterface();
else
host = mController.getTargetHost();
String port = mController.getTargetPort();
if (host == null) host = "";
if (port == null) port = "";
if (host.indexOf(':') >= 0)
host = '[' + host + ']';
String link = host + ":" + port;
if (linkify) {
if ("httpserver".equals(mController.getType()) ||
"httpbidirserver".equals(mController.getType()))
link = "http://" + link;
}
return link;
}
public String getDestinationBase64() {
String rv = mController.getMyDestination();
if (rv != null)
return rv;
// if not running, do this the hard way
String keyFile = mController.getPrivKeyFile();
if (keyFile != null && keyFile.trim().length() > 0) {
PrivateKeyFile pkf = new PrivateKeyFile(keyFile);
try {
Destination d = pkf.getDestination();
if (d != null)
return d.toBase64();
} catch (Exception e) {}
}
return "";
}
public String getDestHashBase32() {
String rv = mController.getMyDestHashBase32();
if (rv != null)
return rv;
return "";
}
/* Data for some client and server tunnels */
/* Other output formats */
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 Uri getRecommendedAppForTunnel() {
int resId = 0;
if ("ircclient".equals(mController.getType()))
resId = R.string.market_irc;
if (resId > 0)
return Uri.parse(mContext.getString(resId));
else
return null;
}
public String getDetails() {
String details;
if (isClient())
details = getClientDestination();
else
details = "";
return details;
}
public Drawable getStatusIcon() {
switch (getStatus()) {
case STANDBY:
return mContext.getResources()
.getDrawable(R.drawable.ic_schedule_black_24dp);
case STARTING:
case RUNNING:
case NOT_RUNNING:
default:
return null;
}
}
public Drawable getStatusBackground() {
switch (getStatus()) {
case STANDBY:
case STARTING:
return mContext.getResources()
.getDrawable(R.drawable.tunnel_yellow);
case RUNNING:
return mContext.getResources()
.getDrawable(R.drawable.tunnel_green);
case NOT_RUNNING:
default:
return mContext.getResources()
.getDrawable(R.drawable.tunnel_red);
}
}
}

View File

@ -0,0 +1,174 @@
package net.i2p.android.i2ptunnel;
import android.content.Context;
import android.os.Build;
import android.support.v4.util.Pair;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import net.i2p.android.router.R;
import net.i2p.android.util.FragmentUtils;
import java.util.List;
public class TunnelEntryAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private Context mCtx;
private boolean mClientTunnels;
private TunnelListFragment.OnTunnelSelectedListener mListener;
private FragmentUtils.TwoPaneProvider mTwoPane;
private List<TunnelEntry> mTunnels;
/**
* The current activated item position. Only used on tablets.
*/
private int mActivatedPosition = -1;
public static class SimpleViewHolder extends RecyclerView.ViewHolder {
public SimpleViewHolder(View itemView) {
super(itemView);
}
}
public static class TunnelViewHolder extends RecyclerView.ViewHolder {
public ImageView status;
public TextView name;
public TextView description;
public TextView interfacePort;
public TunnelViewHolder(View itemView) {
super(itemView);
status = (ImageView) itemView.findViewById(R.id.tunnel_status);
name = (TextView) itemView.findViewById(R.id.tunnel_name);
description = (TextView) itemView.findViewById(R.id.tunnel_description);
interfacePort = (TextView) itemView.findViewById(R.id.tunnel_interface_port);
}
}
public TunnelEntryAdapter(Context context, boolean clientTunnels,
TunnelListFragment.OnTunnelSelectedListener listener,
FragmentUtils.TwoPaneProvider twoPane) {
super();
mCtx = context;
mClientTunnels = clientTunnels;
mListener = listener;
mTwoPane = twoPane;
}
public void setTunnels(List<TunnelEntry> tunnels) {
mTunnels = tunnels;
notifyDataSetChanged();
}
public void addTunnel(TunnelEntry tunnel) {
mTunnels.add(tunnel);
notifyItemInserted(mTunnels.size()-1);
}
public TunnelEntry getTunnel(int position) {
if (position < 0)
return null;
return mTunnels.get(position);
}
public void setActivatedPosition(int position) {
mActivatedPosition = position;
}
public int getActivatedPosition() {
return mActivatedPosition;
}
public void clearActivatedPosition() {
mActivatedPosition = -1;
}
@Override
public int getItemViewType(int position) {
if (mTunnels == null)
return R.string.router_not_running;
else if (mTunnels.isEmpty())
return R.layout.listitem_empty;
else
return R.layout.listitem_i2ptunnel;
}
// Create new views (invoked by the layout manager)
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
int vt = viewType;
if (viewType == R.string.router_not_running)
vt = R.layout.listitem_empty;
View v = LayoutInflater.from(parent.getContext())
.inflate(vt, parent, false);
switch (viewType) {
case R.layout.listitem_i2ptunnel:
return new TunnelViewHolder(v);
default:
return new SimpleViewHolder(v);
}
}
// Replace the contents of a view (invoked by the layout manager)
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {
switch (holder.getItemViewType()) {
case R.string.router_not_running:
((TextView) holder.itemView).setText(
mCtx.getString(R.string.router_not_running));
break;
case R.layout.listitem_empty:
((TextView) holder.itemView).setText(mClientTunnels ?
R.string.no_configured_client_tunnels :
R.string.no_configured_server_tunnels);
break;
case R.layout.listitem_i2ptunnel:
final TunnelViewHolder tvh = (TunnelViewHolder) holder;
final TunnelEntry tunnel = getTunnel(position);
tvh.status.setImageDrawable(tunnel.getStatusIcon());
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN)
tvh.status.setBackgroundDrawable(tunnel.getStatusBackground());
else
tvh.status.setBackground(tunnel.getStatusBackground());
tvh.name.setText(tunnel.getName());
tvh.description.setText(tunnel.getDescription());
tvh.interfacePort.setText(tunnel.getTunnelLink(false));
tvh.itemView.setSelected(mTwoPane.isTwoPane() && position == mActivatedPosition);
tvh.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
int oldPosition = mActivatedPosition;
mActivatedPosition = position;
notifyItemChanged(oldPosition);
notifyItemChanged(position);
mListener.onTunnelSelected(tunnel.getId(),
Pair.create((View)tvh.name, mCtx.getString(R.string.TUNNEL_NAME)),
Pair.create((View)tvh.description, mCtx.getString(R.string.TUNNEL_DESCRIPTION)));
}
});
break;
default:
break;
}
}
// Return the size of the dataset (invoked by the layout manager)
@Override
public int getItemCount() {
if (mTunnels == null || mTunnels.isEmpty())
return 1;
return mTunnels.size();
}
}

View File

@ -0,0 +1,148 @@
package net.i2p.android.i2ptunnel;
import android.content.Context;
import android.os.Handler;
import android.support.v4.content.AsyncTaskLoader;
import net.i2p.android.router.util.Util;
import net.i2p.i2ptunnel.TunnelController;
import net.i2p.i2ptunnel.TunnelControllerGroup;
import net.i2p.router.RouterContext;
import java.util.ArrayList;
import java.util.List;
public class TunnelEntryLoader extends AsyncTaskLoader<List<TunnelEntry>> {
private TunnelControllerGroup mGroup;
private boolean mClientTunnels;
private List<TunnelEntry> mData;
private Handler mHandler;
private TunnelControllerMonitor mMonitor;
public TunnelEntryLoader(Context context, TunnelControllerGroup tcg, boolean clientTunnels) {
super(context);
mGroup = tcg;
mClientTunnels = clientTunnels;
mHandler = new Handler();
}
@Override
public List<TunnelEntry> loadInBackground() {
// Don't load tunnels if the router is not running
// TODO: in future we might be able to view and edit tunnels while router is not running
RouterContext routerContext = Util.getRouterContext();
if (routerContext == null)
return null;
List<TunnelEntry> ret = new ArrayList<>();
List<TunnelController> controllers = mGroup.getControllers();
for (int i = 0; i < controllers.size(); i++) {
TunnelEntry tunnel = new TunnelEntry(getContext(), controllers.get(i), i);
if ( (mClientTunnels && tunnel.isClient()) ||
(!mClientTunnels && !tunnel.isClient()) )
ret.add(tunnel);
}
return ret;
}
@Override
public void deliverResult(List<TunnelEntry> data) {
if (isReset()) {
// The Loader has been reset; ignore the result and invalidate the data.
if (data != null) {
releaseResources(data);
return;
}
}
// Hold a reference to the old data so it doesn't get garbage collected.
// We must protect it until the new data has been delivered.
List<TunnelEntry> oldData = mData;
mData = data;
if (isStarted()) {
// If the Loader is in a started state, have the superclass deliver the
// results to the client.
super.deliverResult(data);
}
// Invalidate the old data as we don't need it any more.
if (oldData != null && oldData != data) {
releaseResources(oldData);
}
}
@Override
protected void onStartLoading() {
if (mData != null) {
// Deliver any previously loaded data immediately.
deliverResult(mData);
}
// Begin monitoring the underlying data source.
mMonitor = new TunnelControllerMonitor();
mHandler.postDelayed(mMonitor, 50);
if (takeContentChanged() || mData == null) {
// When the observer detects a change, it should call onContentChanged()
// on the Loader, which will cause the next call to takeContentChanged()
// to return true. If this is ever the case (or if the current data is
// null), we force a new load.
forceLoad();
}
}
@Override
protected void onStopLoading() {
// The Loader is in a stopped state, so we should attempt to cancel the
// current load (if there is one).
cancelLoad();
// Note that we leave the observer as is. Loaders in a stopped state
// should still monitor the data source for changes so that the Loader
// will know to force a new load if it is ever started again.
}
@Override
protected void onReset() {
// Ensure the loader has been stopped.
onStopLoading();
// At this point we can release the resources associated with 'mData'.
if (mData != null) {
releaseResources(mData);
mData = null;
}
// The Loader is being reset, so we should stop monitoring for changes.
if (mMonitor != null) {
mHandler.removeCallbacks(mMonitor);
mMonitor = null;
}
}
@Override
public void onCanceled(List<TunnelEntry> data) {
// Attempt to cancel the current asynchronous load.
super.onCanceled(data);
// The load has been canceled, so we should release the resources
// associated with 'data'.
releaseResources(data);
}
private void releaseResources(List<TunnelEntry> data) {
// For a simple List, there is nothing to do. For something like a Cursor, we
// would close it in this method. All resources associated with the Loader
// should be released here.
}
private class TunnelControllerMonitor implements Runnable {
public void run() {
// There is no way (yet) to monitor for changes to the list of
// TunnelControllers, so just force a refresh every 10 seconds.
onContentChanged();
mHandler.postDelayed(this, 10 * 1000);
}
}
}

View File

@ -0,0 +1,233 @@
package net.i2p.android.i2ptunnel;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.Loader;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v4.util.Pair;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.pnikosis.materialishprogress.ProgressWheel;
import net.i2p.android.router.R;
import net.i2p.android.router.service.RouterService;
import net.i2p.android.router.service.State;
import net.i2p.android.router.util.Util;
import net.i2p.android.util.FragmentUtils;
import net.i2p.android.widget.DividerItemDecoration;
import net.i2p.android.widget.LoadingRecyclerView;
import net.i2p.i2ptunnel.TunnelControllerGroup;
import java.util.ArrayList;
import java.util.List;
public class TunnelListFragment extends Fragment implements
LoaderManager.LoaderCallbacks<List<TunnelEntry>> {
public static final String SHOW_CLIENT_TUNNELS = "show_client_tunnels";
private static final int CLIENT_LOADER_ID = 1;
private static final int SERVER_LOADER_ID = 2;
/**
* The serialization (saved instance state) Bundle key representing the
* activated item position. Only used on tablets.
*/
private static final String STATE_ACTIVATED_POSITION = "activated_position";
OnTunnelSelectedListener mCallback;
FragmentUtils.TwoPaneProvider mTwoPane;
private TunnelControllerGroup mGroup;
private LoadingRecyclerView mRecyclerView;
private TunnelEntryAdapter mAdapter;
private boolean mClientTunnels;
// Container Activity must implement this interface
public interface OnTunnelSelectedListener {
void onTunnelSelected(int tunnelId, Pair<View, String> tunnelName,
Pair<View, String> tunnelDescription);
}
public static TunnelListFragment newInstance(boolean showClientTunnels) {
TunnelListFragment f = new TunnelListFragment();
Bundle args = new Bundle();
args.putBoolean(TunnelListFragment.SHOW_CLIENT_TUNNELS, showClientTunnels);
f.setArguments(args);
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
mCallback = FragmentUtils.getParent(this, OnTunnelSelectedListener.class);
if (mCallback == null)
throw new ClassCastException("Parent must implement OnTunnelSelectedListener");
mTwoPane = FragmentUtils.getParent(this, FragmentUtils.TwoPaneProvider.class);
if (mTwoPane == null)
throw new ClassCastException("Parent must implement TwoPaneProvider");
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_list, container, false);
mRecyclerView = (LoadingRecyclerView) v.findViewById(R.id.list);
View empty = v.findViewById(R.id.empty);
ProgressWheel loading = (ProgressWheel) v.findViewById(R.id.loading);
mRecyclerView.setLoadingView(empty, loading);
return v;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mClientTunnels = getArguments().getBoolean(SHOW_CLIENT_TUNNELS);
mRecyclerView.setHasFixedSize(true);
mRecyclerView.addItemDecoration(new DividerItemDecoration(getActivity(), DividerItemDecoration.VERTICAL_LIST));
// use a linear layout manager
RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getActivity());
mRecyclerView.setLayoutManager(mLayoutManager);
// Set the adapter for the list view
mAdapter = new TunnelEntryAdapter(getActivity(), mClientTunnels, mCallback, mTwoPane);
mRecyclerView.setAdapter(mAdapter);
// Restore the previously serialized activated item position.
if (savedInstanceState != null
&& savedInstanceState.containsKey(STATE_ACTIVATED_POSITION))
mAdapter.setActivatedPosition(savedInstanceState
.getInt(STATE_ACTIVATED_POSITION));
else
mAdapter.clearActivatedPosition();
// Initialize the adapter in case the RouterService has not been created
if (Util.getRouterContext() == null)
mAdapter.setTunnels(null);
}
@Override
public void onStart() {
super.onStart();
LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(getActivity());
IntentFilter filter = new IntentFilter();
filter.addAction(RouterService.LOCAL_BROADCAST_STATE_NOTIFICATION);
filter.addAction(RouterService.LOCAL_BROADCAST_STATE_CHANGED);
lbm.registerReceiver(onStateChange, filter);
}
private State lastRouterState = null;
private BroadcastReceiver onStateChange = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
State state = intent.getParcelableExtra(RouterService.LOCAL_BROADCAST_EXTRA_STATE);
if (lastRouterState == null || lastRouterState != state) {
updateState(state);
lastRouterState = state;
}
}
};
public void updateState(State state) {
if (state == State.STOPPING || state == State.STOPPED ||
state == State.MANUAL_STOPPING ||
state == State.MANUAL_STOPPED ||
state == State.MANUAL_QUITTING ||
state == State.MANUAL_QUITTED)
getLoaderManager().destroyLoader(mClientTunnels ? CLIENT_LOADER_ID : SERVER_LOADER_ID);
else
initTunnels();
}
private void initTunnels() {
if (mGroup == null) {
try {
mGroup = TunnelControllerGroup.getInstance();
} catch (IllegalArgumentException iae) {
Util.e("Could not load tunnels", iae);
mGroup = null;
}
}
if (mGroup != null && isAdded()) {
mRecyclerView.setLoading(true);
getLoaderManager().initLoader(mClientTunnels ? CLIENT_LOADER_ID
: SERVER_LOADER_ID, null, this);
}
}
@Override
public void onResume() {
super.onResume();
// Triggers loader init via updateState() if the router is running
LocalBroadcastManager.getInstance(getActivity()).sendBroadcast(new Intent(RouterService.LOCAL_BROADCAST_REQUEST_STATE));
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
int activatedPosition = mAdapter.getActivatedPosition();
if (activatedPosition >= 0) {
// Serialize and persist the activated item position.
outState.putInt(STATE_ACTIVATED_POSITION, activatedPosition);
}
}
@Override
public void onStop() {
super.onStop();
LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(onStateChange);
}
public void addTunnel(TunnelEntry tunnelEntry) {
mAdapter.addTunnel(tunnelEntry);
}
// LoaderManager.LoaderCallbacks<List<TunnelEntry>>
public Loader<List<TunnelEntry>> onCreateLoader(int id, Bundle args) {
return new TunnelEntryLoader(getActivity(), mGroup, mClientTunnels);
}
public void onLoadFinished(Loader<List<TunnelEntry>> loader,
List<TunnelEntry> data) {
if (loader.getId() == (mClientTunnels ?
CLIENT_LOADER_ID : SERVER_LOADER_ID)) {
mAdapter.setTunnels(data);
}
}
public void onLoaderReset(Loader<List<TunnelEntry>> loader) {
if (loader.getId() == (mClientTunnels ?
CLIENT_LOADER_ID : SERVER_LOADER_ID)) {
if (Util.getRouterContext() == null)
mAdapter.setTunnels(null);
else
mAdapter.setTunnels(new ArrayList<TunnelEntry>());
}
}
}

View File

@ -0,0 +1,46 @@
package net.i2p.android.i2ptunnel;
import android.app.Activity;
import android.app.Dialog;
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.v7.app.AlertDialog;
import net.i2p.android.router.R;
import net.i2p.android.wizard.model.AbstractWizardModel;
import net.i2p.android.wizard.ui.AbstractWizardActivity;
public class TunnelWizardActivity extends AbstractWizardActivity {
@Override
protected AbstractWizardModel onCreateModel() {
return new TunnelWizardModel(this);
}
@Override
protected DialogFragment onGetFinishWizardDialog() {
return new DialogFragment() {
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
return new AlertDialog.Builder(getActivity())
.setMessage(R.string.i2ptunnel_wizard_submit_confirm_message)
.setPositiveButton(R.string.i2ptunnel_wizard_submit_confirm_button,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
Intent result = new Intent();
result.putExtra(TunnelsContainer.TUNNEL_WIZARD_DATA, mWizardModel.save());
setResult(Activity.RESULT_OK, result);
dialog.dismiss();
finish();
}
})
.setNegativeButton(android.R.string.cancel, null)
.create();
}
};
}
}

View File

@ -0,0 +1,125 @@
package net.i2p.android.i2ptunnel;
import android.content.Context;
import android.content.res.Resources;
import net.i2p.android.router.R;
import net.i2p.android.wizard.model.AbstractWizardModel;
import net.i2p.android.wizard.model.BranchPage;
import net.i2p.android.wizard.model.Conditional;
import net.i2p.android.wizard.model.I2PDestinationPage;
import net.i2p.android.wizard.model.PageList;
import net.i2p.android.wizard.model.SingleFixedBooleanPage;
import net.i2p.android.wizard.model.SingleFixedChoicePage;
import net.i2p.android.wizard.model.SingleTextFieldPage;
public class TunnelWizardModel extends AbstractWizardModel {
public TunnelWizardModel(Context context) {
super(context);
}
@Override
protected PageList onNewRootPageList() {
Resources res = mContext.getResources();
Conditional cTunnelType = new Conditional();
Conditional cClientType = new Conditional();
Conditional cServerType = new Conditional();
return new PageList(
new BranchPage(this, res.getString(R.string.i2ptunnel_wizard_k_client_server))
.addBranch(res.getString(R.string.i2ptunnel_wizard_v_client),
new SingleFixedChoicePage(this, res.getString(R.string.i2ptunnel_wizard_k_type))
.setChoices(
res.getString(R.string.i2ptunnel_type_client),
res.getString(R.string.i2ptunnel_type_httpclient),
res.getString(R.string.i2ptunnel_type_ircclient),
res.getString(R.string.i2ptunnel_type_sockstunnel),
res.getString(R.string.i2ptunnel_type_socksirctunnel),
res.getString(R.string.i2ptunnel_type_connectclient),
res.getString(R.string.i2ptunnel_type_streamrclient))
.setRequired(true)
.makeConditional(cClientType))
.addBranch(res.getString(R.string.i2ptunnel_wizard_v_server),
new SingleFixedChoicePage(this, res.getString(R.string.i2ptunnel_wizard_k_type))
.setChoices(
res.getString(R.string.i2ptunnel_type_server),
res.getString(R.string.i2ptunnel_type_httpserver),
res.getString(R.string.i2ptunnel_type_httpbidirserver),
res.getString(R.string.i2ptunnel_type_ircserver),
res.getString(R.string.i2ptunnel_type_streamrserver))
.setRequired(true)
.makeConditional(cServerType))
.setRequired(true)
.makeConditional(cTunnelType),
new SingleTextFieldPage(this, res.getString(R.string.i2ptunnel_wizard_k_name))
.setDescription(res.getString(R.string.i2ptunnel_wizard_desc_name))
.setRequired(true),
new SingleTextFieldPage(this, res.getString(R.string.i2ptunnel_wizard_k_desc))
.setDescription(res.getString(R.string.i2ptunnel_wizard_desc_desc)),
new I2PDestinationPage(this, res.getString(R.string.i2ptunnel_wizard_k_dest))
.setDescription(res.getString(R.string.i2ptunnel_wizard_desc_dest))
.setRequired(true)
.setEqualAnyCondition(cClientType,
res.getString(R.string.i2ptunnel_type_client),
res.getString(R.string.i2ptunnel_type_ircclient),
res.getString(R.string.i2ptunnel_type_streamrclient)),
new SingleTextFieldPage(this, res.getString(R.string.i2ptunnel_wizard_k_outproxies))
.setDescription(res.getString(R.string.i2ptunnel_wizard_desc_outproxies))
.setEqualAnyCondition(cClientType,
res.getString(R.string.i2ptunnel_type_httpclient),
res.getString(R.string.i2ptunnel_type_connectclient),
res.getString(R.string.i2ptunnel_type_sockstunnel),
res.getString(R.string.i2ptunnel_type_socksirctunnel)),
// Not set required because a default is specified.
// Otherwise user would need to edit the field to
// enable the Next button.
new SingleTextFieldPage(this, res.getString(R.string.i2ptunnel_wizard_k_target_host))
.setDefault("127.0.0.1")
.setDescription(res.getString(R.string.i2ptunnel_wizard_desc_target_host))
.setEqualCondition(cClientType,
res.getString(R.string.i2ptunnel_type_streamrclient))
.setEqualAnyCondition(cServerType,
res.getString(R.string.i2ptunnel_type_server),
res.getString(R.string.i2ptunnel_type_httpserver),
res.getString(R.string.i2ptunnel_type_httpbidirserver),
res.getString(R.string.i2ptunnel_type_ircserver)),
new SingleTextFieldPage(this, res.getString(R.string.i2ptunnel_wizard_k_target_port))
.setDescription(res.getString(R.string.i2ptunnel_wizard_desc_target_port))
.setNumeric(true)
.setRequired(true)
.setEqualCondition(cTunnelType, res.getString(R.string.i2ptunnel_wizard_v_server)),
// Not set required because a default is specified.
new SingleTextFieldPage(this, res.getString(R.string.i2ptunnel_wizard_k_reachable_on))
.setDefault("127.0.0.1")
.setDescription(res.getString(R.string.i2ptunnel_wizard_desc_reachable_on))
.setEqualAnyCondition(cClientType,
res.getString(R.string.i2ptunnel_type_client),
res.getString(R.string.i2ptunnel_type_httpclient),
res.getString(R.string.i2ptunnel_type_ircclient),
res.getString(R.string.i2ptunnel_type_sockstunnel),
res.getString(R.string.i2ptunnel_type_socksirctunnel),
res.getString(R.string.i2ptunnel_type_connectclient))
.setEqualAnyCondition(cServerType,
res.getString(R.string.i2ptunnel_type_httpbidirserver),
res.getString(R.string.i2ptunnel_type_streamrserver)),
new SingleTextFieldPage(this, res.getString(R.string.i2ptunnel_wizard_k_binding_port))
.setDescription(res.getString(R.string.i2ptunnel_wizard_k_binding_port))
.setNumeric(true)
.setRequired(true)
.setEqualCondition(cTunnelType, res.getString(R.string.i2ptunnel_wizard_v_client))
.setEqualCondition(cServerType, res.getString(R.string.i2ptunnel_type_httpbidirserver)),
new SingleFixedBooleanPage(this, res.getString(R.string.i2ptunnel_wizard_k_auto_start))
.setDescription(res.getString(R.string.i2ptunnel_wizard_desc_auto_start))
.setRequired(true)
);
}
}

View File

@ -0,0 +1,289 @@
package net.i2p.android.i2ptunnel;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.ActivityOptionsCompat;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.util.Pair;
import android.support.v4.view.ViewPager;
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.ImageButton;
import android.widget.Toast;
import com.viewpagerindicator.TitlePageIndicator;
import net.i2p.android.i2ptunnel.preferences.EditTunnelContainerFragment;
import net.i2p.android.i2ptunnel.util.TunnelUtil;
import net.i2p.android.router.R;
import net.i2p.android.router.util.Util;
import net.i2p.android.util.FragmentUtils;
import net.i2p.app.ClientAppState;
import net.i2p.i2ptunnel.TunnelControllerGroup;
import net.i2p.i2ptunnel.ui.TunnelConfig;
import net.i2p.router.RouterContext;
import java.util.List;
public class TunnelsContainer extends Fragment implements
FragmentUtils.TwoPaneProvider,
TunnelListFragment.OnTunnelSelectedListener,
TunnelDetailFragment.TunnelDetailListener {
static final int TUNNEL_WIZARD_REQUEST = 1;
public static final String TUNNEL_WIZARD_DATA = "tunnel_wizard_data";
/**
* Whether or not the activity is in two-pane mode, i.e. running on a tablet
* device.
*/
private boolean mTwoPane;
ViewPager mViewPager;
TitlePageIndicator mPageIndicator;
FragmentPagerAdapter mFragPagerAdapter;
private static final String FRAGMENT_CLIENT = "client_fragment";
private static final String FRAGMENT_SERVER = "server_fragment";
private static final int FRAGMENT_ID_CLIENT = 0;
private static final int FRAGMENT_ID_SERVER = 1;
TunnelListFragment mClientFrag;
TunnelListFragment mServerFrag;
private ImageButton mNewTunnel;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.container_tunnels, container, false);
mViewPager = (ViewPager) v.findViewById(R.id.pager);
mPageIndicator = (TitlePageIndicator) v.findViewById(R.id.page_indicator);
mNewTunnel = (ImageButton) v.findViewById(R.id.promoted_action);
if (v.findViewById(R.id.detail_fragment) != null) {
// The detail container view will be present only in the
// large-screen layouts (res/values-w720dp). If this view
// is present, then the activity should be in two-pane mode.
mTwoPane = true;
}
if (savedInstanceState != null) {
mClientFrag = (TunnelListFragment) getChildFragmentManager().getFragment(
savedInstanceState, FRAGMENT_CLIENT);
mServerFrag = (TunnelListFragment) getChildFragmentManager().getFragment(
savedInstanceState, FRAGMENT_SERVER);
}
return v;
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mFragPagerAdapter = new TunnelsPagerAdapter(getChildFragmentManager());
mViewPager.setAdapter(mFragPagerAdapter);
// Bind the page indicator to the pager.
mPageIndicator.setViewPager(mViewPager);
mNewTunnel.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent wi = new Intent(getActivity(), TunnelWizardActivity.class);
startActivityForResult(wi, TUNNEL_WIZARD_REQUEST);
}
});
}
public class TunnelsPagerAdapter extends FragmentPagerAdapter {
private static final int NUM_ITEMS = 2;
public TunnelsPagerAdapter(FragmentManager fm) {
super(fm);
}
@Override
public int getCount() {
return NUM_ITEMS;
}
@Override
public Fragment getItem(int position) {
switch (position) {
case FRAGMENT_ID_CLIENT:
return (mClientFrag = TunnelListFragment.newInstance(true));
case FRAGMENT_ID_SERVER:
return (mServerFrag = TunnelListFragment.newInstance(false));
default:
return null;
}
}
@Override
public CharSequence getPageTitle(int position) {
switch (position) {
case FRAGMENT_ID_CLIENT:
return getActivity().getString(R.string.label_i2ptunnel_client);
case FRAGMENT_ID_SERVER:
return getActivity().getString(R.string.label_i2ptunnel_server);
default:
return null;
}
}
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
inflater.inflate(R.menu.fragment_i2ptunnel_list_actions, menu);
}
@Override
public void onPrepareOptionsMenu(Menu menu) {
RouterContext rCtx = Util.getRouterContext();
TunnelControllerGroup tcg = TunnelControllerGroup.getInstance();
boolean showActions = rCtx != null && tcg != null &&
(tcg.getState() == ClientAppState.STARTING ||
tcg.getState() == ClientAppState.RUNNING);
menu.findItem(R.id.action_start_all_tunnels).setVisible(showActions);
menu.findItem(R.id.action_stop_all_tunnels).setVisible(showActions);
menu.findItem(R.id.action_restart_all_tunnels).setVisible(showActions);
mNewTunnel.setVisibility(showActions ? View.VISIBLE : View.GONE);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
TunnelControllerGroup tcg = TunnelControllerGroup.getInstance();
if (tcg == null)
return false;
// Handle presses on the action bar items
List<String> msgs;
switch (item.getItemId()) {
case R.id.action_start_all_tunnels:
msgs = tcg.startAllControllers();
break;
case R.id.action_stop_all_tunnels:
msgs = tcg.stopAllControllers();
break;
case R.id.action_restart_all_tunnels:
msgs = tcg.restartAllControllers();
break;
default:
return super.onOptionsItemSelected(item);
}
// TODO: Do something with the other messages
if (msgs.size() > 0)
Toast.makeText(getActivity().getApplicationContext(),
msgs.get(0), Toast.LENGTH_LONG).show();
return true;
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == TUNNEL_WIZARD_REQUEST) {
if (resultCode == Activity.RESULT_OK) {
Bundle tunnelData = data.getExtras().getBundle(TUNNEL_WIZARD_DATA);
// TODO fetch earlier
TunnelControllerGroup tcg = TunnelControllerGroup.getInstance();
TunnelConfig cfg = TunnelUtil.createConfigFromWizard(getActivity(), tcg, tunnelData);
TunnelEntry tunnel = TunnelEntry.createNewTunnel(getActivity(), tcg, cfg);
if (tunnel.isClient() && mClientFrag != null)
mClientFrag.addTunnel(tunnel);
else if (mServerFrag != null)
mServerFrag.addTunnel(tunnel);
}
}
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
// Since the pager fragments don't have known tags or IDs, the only way to persist the
// reference is to use putFragment/getFragment. Remember, we're not persisting the exact
// Fragment instance. This mechanism simply gives us a way to persist access to the
// 'current' fragment instance for the given fragment (which changes across orientation
// changes).
//
// The outcome of all this is that the "Refresh" menu button refreshes the stream across
// orientation changes.
if (mClientFrag != null)
getChildFragmentManager().putFragment(outState, FRAGMENT_CLIENT, mClientFrag);
if (mServerFrag != null)
getChildFragmentManager().putFragment(outState, FRAGMENT_SERVER, mServerFrag);
}
// FragmentUtils.TwoPaneProvider
public boolean isTwoPane() {
return mTwoPane;
}
// TunnelListFragment.OnTunnelSelectedListener
public final void onTunnelSelected(int tunnelId, Pair<View, String> tunnelName,
Pair<View, String> tunnelDescription) {
if (mTwoPane) {
// In two-pane mode, show the detail view in this activity by
// adding or replacing the detail fragment using a
// fragment transaction.
TunnelDetailFragment detailFrag = TunnelDetailFragment.newInstance(tunnelId);
getChildFragmentManager().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(getActivity(), TunnelDetailActivity.class);
detailIntent.putExtra(TunnelDetailFragment.TUNNEL_ID, tunnelId);
ActivityOptionsCompat options = ActivityOptionsCompat.makeSceneTransitionAnimation(
getActivity(), tunnelName, tunnelDescription);
ActivityCompat.startActivity(getActivity(), detailIntent, options.toBundle());
}
}
// TunnelDetailFragment.TunnelDetailListener
@Override
public void onEditTunnel(int tunnelId) {
Fragment editFrag = EditTunnelContainerFragment.newInstance(tunnelId);
getChildFragmentManager().beginTransaction()
.replace(R.id.detail_fragment, editFrag)
.addToBackStack("")
.commit();
}
public void onTunnelDeleted(int tunnelId, int numTunnelsLeft) {
// Should only get here in two-pane mode, but just to be safe:
if (mTwoPane) {
if (numTunnelsLeft > 0) {
TunnelDetailFragment detailFrag = TunnelDetailFragment.newInstance(
(tunnelId > 0 ? tunnelId - 1 : 0));
getChildFragmentManager().beginTransaction()
.replace(R.id.detail_fragment, detailFrag).commit();
} else {
TunnelDetailFragment detailFrag = (TunnelDetailFragment) getChildFragmentManager().findFragmentById(R.id.detail_fragment);
getChildFragmentManager().beginTransaction()
.remove(detailFrag).commit();
}
}
}
}

View File

@ -0,0 +1,193 @@
package net.i2p.android.i2ptunnel.preferences;
import android.content.DialogInterface;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.CheckBoxPreference;
import android.preference.Preference;
import android.preference.PreferenceCategory;
import android.preference.PreferenceScreen;
import android.support.v7.app.AlertDialog;
import net.i2p.android.i2ptunnel.util.TunnelLogic;
import net.i2p.android.i2ptunnel.util.TunnelUtil;
import net.i2p.android.router.R;
public class AdvancedTunnelPreferenceFragment extends BaseTunnelPreferenceFragment {
public static AdvancedTunnelPreferenceFragment newInstance(int tunnelId) {
AdvancedTunnelPreferenceFragment f = new AdvancedTunnelPreferenceFragment();
Bundle args = new Bundle();
args.putInt(ARG_TUNNEL_ID, tunnelId);
f.setArguments(args);
return f;
}
@Override
protected void loadPreferences() {
String type = TunnelUtil.getController(mGroup, mTunnelId).getType();
new TunnelPreferences(type).runLogic();
}
class TunnelPreferences extends TunnelLogic {
PreferenceScreen ps;
PreferenceCategory tunParamCategory;
public TunnelPreferences(String type) {
super(type);
}
@Override
protected void general() {
}
@Override
protected void generalClient() {
}
@Override
protected void generalClientStreamr(boolean isStreamr) {
}
@Override
protected void generalClientPort() {
}
@Override
protected void generalClientPortStreamr(boolean isStreamr) {
}
@Override
protected void generalClientProxy(boolean isProxy) {
}
@Override
protected void generalClientProxyHttp(boolean isHttp) {
}
@Override
protected void generalClientStandardOrIrc(boolean isStandardOrIrc) {
}
@Override
protected void generalClientIrc() {
}
@Override
protected void generalServerHttp() {
}
@Override
protected void generalServerHttpBidirOrStreamr(boolean isStreamr) {
}
@Override
protected void generalServerPort() {
}
@Override
protected void generalServerPortStreamr(boolean isStreamr) {
}
@Override
protected void advanced() {
addPreferencesFromResource(R.xml.tunnel_adv);
ps = getPreferenceScreen();
tunParamCategory = (PreferenceCategory) ps.findPreference(
getString(R.string.TUNNEL_CAT_TUNNEL_PARAMS));
}
@Override
protected void advancedStreamr(boolean isStreamr) {
if (isStreamr)
tunParamCategory.removePreference(tunParamCategory.findPreference(getString(R.string.TUNNEL_OPT_PROFILE)));
}
@Override
protected void advancedServerOrStreamrClient(boolean isServerOrStreamrClient) {
if (isServerOrStreamrClient)
tunParamCategory.removePreference(tunParamCategory.findPreference(getString(R.string.TUNNEL_OPT_DELAY_CONNECT)));
}
@Override
protected void advancedServer() {
addPreferencesFromResource(R.xml.tunnel_adv_server);
}
@Override
protected void advancedServerHttp(boolean isHttp) {
if (isHttp)
addPreferencesFromResource(R.xml.tunnel_adv_server_http);
else {
PreferenceCategory accessCtlCategory = (PreferenceCategory) ps.findPreference(
getString(R.string.TUNNEL_CAT_ACCESS_CONTROL));
accessCtlCategory.removePreference(accessCtlCategory.findPreference(getString(R.string.TUNNEL_OPT_REJECT_INPROXY)));
}
}
@Override
protected void advancedIdle() {
addPreferencesFromResource(R.xml.tunnel_adv_idle);
}
@Override
protected void advancedIdleServerOrStreamrClient(boolean isServerOrStreamrClient) {
if (isServerOrStreamrClient)
ps.removePreference(ps.findPreference(getString(R.string.TUNNEL_OPT_DELAY_OPEN)));
}
@Override
protected void advancedClient() {
PreferenceCategory idleCategory = (PreferenceCategory) ps.findPreference(
getString(R.string.TUNNEL_CAT_IDLE)
);
addPreferencesFromResource(R.xml.tunnel_adv_idle_client, idleCategory);
// PERSISTENT_KEY and NEW_KEYS can't be set simultaneously
final CheckBoxPreference nk = (CheckBoxPreference) findPreference(getString(R.string.TUNNEL_OTP_NEW_KEYS));
nk.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object o) {
final SharedPreferences prefs = getPreferenceManager().getSharedPreferences();
if ((Boolean) o && prefs.getBoolean(getString(R.string.TUNNEL_OPT_PERSISTENT_KEY),
getResources().getBoolean(R.bool.DEFAULT_PERSISTENT_KEY))) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setTitle(R.string.new_keys_on_reopen_conflict_title)
.setMessage(R.string.new_keys_on_reopen_conflict_msg)
.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
SharedPreferences.Editor editor = prefs.edit();
editor.putBoolean(getString(R.string.TUNNEL_OPT_PERSISTENT_KEY), false);
editor.apply();
nk.setChecked(true);
}
})
.setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
}
});
builder.show();
return false;
} else
return true;
}
});
}
@Override
protected void advancedClientHttp() {
addPreferencesFromResource(R.xml.tunnel_adv_client_http);
}
@Override
protected void advancedClientProxy() {
addPreferencesFromResource(R.xml.tunnel_adv_client_proxy);
}
@Override
protected void advancedOther() {
addPreferencesFromResource(R.xml.tunnel_adv_other);
}
}
}

View File

@ -0,0 +1,89 @@
package net.i2p.android.i2ptunnel.preferences;
import android.os.Build;
import android.os.Bundle;
import android.preference.Preference;
import android.preference.PreferenceGroup;
import android.preference.PreferenceScreen;
import android.support.v4.preference.PreferenceFragment;
import net.i2p.I2PAppContext;
import net.i2p.android.i2ptunnel.util.TunnelUtil;
import net.i2p.android.router.R;
import net.i2p.i2ptunnel.TunnelControllerGroup;
import net.i2p.i2ptunnel.ui.TunnelConfig;
public abstract class BaseTunnelPreferenceFragment extends PreferenceFragment {
protected static final String ARG_TUNNEL_ID = "tunnelId";
protected TunnelControllerGroup mGroup;
protected int mTunnelId;
@Override
public void onCreate(Bundle paramBundle) {
super.onCreate(paramBundle);
String error;
try {
mGroup = TunnelControllerGroup.getInstance();
error = mGroup == null ? getResources().getString(R.string.i2ptunnel_not_initialized) : null;
} catch (IllegalArgumentException iae) {
mGroup = null;
error = iae.toString();
}
if (mGroup == null) {
// TODO Show error
} else if (getArguments().containsKey(ARG_TUNNEL_ID)) {
mTunnelId = getArguments().getInt(ARG_TUNNEL_ID, 0);
TunnelUtil.writeTunnelToPreferences(getActivity(), mGroup, mTunnelId);
// https://stackoverflow.com/questions/17880437/which-settings-file-does-preferencefragment-read-write
getPreferenceManager().setSharedPreferencesName(TunnelUtil.getPreferencesFilename(mTunnelId));
loadPreferences();
}
}
@Override
public void onPause() {
super.onPause();
// Pre-Honeycomb: onPause() is the last method guaranteed to be called.
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB)
saveTunnel();
}
@Override
public void onStop() {
super.onStop();
// Honeycomb and above: onStop() is the last method guaranteed to be called.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
saveTunnel();
}
private void saveTunnel() {
if (mGroup != null) {
TunnelConfig cfg = TunnelUtil.createConfigFromPreferences(getActivity(), mGroup, mTunnelId);
TunnelUtil.saveTunnel(I2PAppContext.getGlobalContext(), mGroup, mTunnelId, cfg);
}
}
protected abstract void loadPreferences();
/**
* http://stackoverflow.com/a/20806812
*
* @param id the Preferences XML to load
* @param newParent the parent PreferenceGroup to add the new Preferences to.
*/
protected void addPreferencesFromResource(int id, PreferenceGroup newParent) {
PreferenceScreen screen = getPreferenceScreen();
int last = screen.getPreferenceCount();
addPreferencesFromResource(id);
while (screen.getPreferenceCount() > last) {
Preference p = screen.getPreference(last);
screen.removePreference(p); // decreases the preference count
newParent.addPreference(p);
}
}
}

View File

@ -0,0 +1,59 @@
package net.i2p.android.i2ptunnel.preferences;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import net.i2p.android.i2ptunnel.TunnelDetailActivity;
import net.i2p.android.i2ptunnel.TunnelDetailFragment;
import net.i2p.android.router.R;
import net.i2p.android.util.LocaleManager;
public class EditTunnelActivity extends AppCompatActivity {
private int mTunnelId;
private final LocaleManager localeManager = new LocaleManager();
@Override
public void onCreate(Bundle savedInstanceState) {
localeManager.onCreate(this);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_single_fragment);
// Set the action bar
Toolbar toolbar = (Toolbar) findViewById(R.id.main_toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
if (savedInstanceState == null) {
mTunnelId = getIntent().getIntExtra(TunnelDetailFragment.TUNNEL_ID, 0);
Fragment editFrag = GeneralTunnelPreferenceFragment.newInstance(mTunnelId);
getSupportFragmentManager().beginTransaction()
.add(R.id.fragment, editFrag).commit();
}
}
@Override
public void onResume() {
super.onResume();
localeManager.onResume(this);
}
@Override
public boolean onSupportNavigateUp() {
FragmentManager fragmentManager = getSupportFragmentManager();
if (fragmentManager.getBackStackEntryCount() > 0) {
fragmentManager.popBackStack();
} else {
Intent intent = new Intent(this, TunnelDetailActivity.class);
intent.putExtra(TunnelDetailFragment.TUNNEL_ID, mTunnelId);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
finish();
}
return true;
}
}

View File

@ -0,0 +1,64 @@
package net.i2p.android.i2ptunnel.preferences;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v7.widget.Toolbar;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import net.i2p.android.router.R;
/**
* A shim that emulates EditTunnelActivity to provide a Toolbar with navigation
* in two-pane mode.
*/
public class EditTunnelContainerFragment extends Fragment {
private static final String ARG_TUNNEL_ID = "tunnelId";
public static EditTunnelContainerFragment newInstance(int tunnelId) {
EditTunnelContainerFragment f = new EditTunnelContainerFragment();
Bundle args = new Bundle();
args.putInt(ARG_TUNNEL_ID, tunnelId);
f.setArguments(args);
return f;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.activity_single_fragment, container, false);
// Set the action bar
Toolbar toolbar = (Toolbar) v.findViewById(R.id.main_toolbar);
toolbar.setTitle(R.string.edit_tunnel);
toolbar.setNavigationIcon(getResources().getDrawable(R.drawable.ic_arrow_back_white_24dp));
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// Try and navigate back through the edit tunnel fragments.
// Otherwise, pop us back off.
FragmentManager fragmentManager = getChildFragmentManager();
if (fragmentManager.getBackStackEntryCount() > 0)
fragmentManager.popBackStack();
else
getFragmentManager().popBackStack();
}
});
return v;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
if (savedInstanceState == null) {
int tunnelId = getArguments().getInt(ARG_TUNNEL_ID);
BaseTunnelPreferenceFragment editFrag = GeneralTunnelPreferenceFragment.newInstance(tunnelId);
getChildFragmentManager().beginTransaction()
.add(R.id.fragment, editFrag).commit();
}
}
}

View File

@ -0,0 +1,258 @@
package net.i2p.android.i2ptunnel.preferences;
import android.content.DialogInterface;
import android.content.SharedPreferences;
import android.os.AsyncTask;
import android.os.Bundle;
import android.preference.CheckBoxPreference;
import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.PreferenceCategory;
import android.preference.PreferenceScreen;
import android.support.v4.app.Fragment;
import android.support.v7.app.AlertDialog;
import net.i2p.android.i2ptunnel.util.TunnelLogic;
import net.i2p.android.i2ptunnel.util.TunnelUtil;
import net.i2p.android.router.R;
import net.i2p.util.Addresses;
import java.util.Set;
public class GeneralTunnelPreferenceFragment extends BaseTunnelPreferenceFragment {
private CheckBoxPreference persistentKeys;
public static GeneralTunnelPreferenceFragment newInstance(int tunnelId) {
GeneralTunnelPreferenceFragment f = new GeneralTunnelPreferenceFragment();
Bundle args = new Bundle();
args.putInt(ARG_TUNNEL_ID, tunnelId);
f.setArguments(args);
return f;
}
@Override
protected void loadPreferences() {
String type = TunnelUtil.getController(mGroup, mTunnelId).getType();
new TunnelPreferences(type).runLogic();
}
@Override
public void onStart() {
super.onStart();
// In case this was changed when toggling NEW_KEYS and then we navigated back
if (persistentKeys != null)
persistentKeys.setChecked(getPreferenceManager().getSharedPreferences().getBoolean(
getString(R.string.TUNNEL_OPT_PERSISTENT_KEY),
getResources().getBoolean(R.bool.DEFAULT_PERSISTENT_KEY)
));
}
class TunnelPreferences extends TunnelLogic {
PreferenceScreen ps;
PreferenceCategory generalCategory;
PreferenceCategory portCategory;
public TunnelPreferences(String type) {
super(type);
}
@Override
protected void general() {
addPreferencesFromResource(R.xml.tunnel_gen);
ps = getPreferenceScreen();
generalCategory = (PreferenceCategory) ps.findPreference(
getString(R.string.TUNNEL_CAT_GENERAL));
portCategory = (PreferenceCategory) ps.findPreference(
getString(R.string.TUNNEL_CAT_PORT));
}
@Override
protected void generalClient() {
addPreferencesFromResource(R.xml.tunnel_gen_client, generalCategory);
// PERSISTENT_KEY and NEW_KEYS can't be set simultaneously
persistentKeys = (CheckBoxPreference) findPreference(getString(R.string.TUNNEL_OPT_PERSISTENT_KEY));
persistentKeys.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object o) {
final SharedPreferences prefs = getPreferenceManager().getSharedPreferences();
if ((Boolean) o && prefs.getBoolean(getString(R.string.TUNNEL_OTP_NEW_KEYS),
getResources().getBoolean(R.bool.DEFAULT_NEW_KEYS))) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setTitle(R.string.persistent_key_conflict_title)
.setMessage(R.string.persistent_key_conflict_msg)
.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
SharedPreferences.Editor editor = prefs.edit();
editor.putBoolean(getString(R.string.TUNNEL_OTP_NEW_KEYS), false);
editor.apply();
persistentKeys.setChecked(true);
}
})
.setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
}
});
builder.show();
return false;
} else
return true;
}
});
}
@Override
protected void generalClientStreamr(boolean isStreamr) {
if (isStreamr) {
generalCategory.removePreference(generalCategory.findPreference(getString(R.string.TUNNEL_SHARED_CLIENT)));
addPreferencesFromResource(R.xml.tunnel_gen_server_port, portCategory);
portCategory.removePreference(portCategory.findPreference(getString(R.string.TUNNEL_TARGET_PORT)));
portCategory.removePreference(portCategory.findPreference(getString(R.string.TUNNEL_USE_SSL)));
}
}
@Override
protected void generalClientPort() {
addPreferencesFromResource(R.xml.tunnel_gen_client_port, portCategory);
}
@Override
protected void generalClientPortStreamr(boolean isStreamr) {
ListPreference reachableBy = (ListPreference) portCategory.findPreference(getString(R.string.TUNNEL_INTERFACE));
if (isStreamr)
portCategory.removePreference(reachableBy);
else
setupReachableBy(reachableBy);
}
private void setupReachableBy(final ListPreference reachableBy) {
reachableBy.setEnabled(false);
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... voids) {
Set<String> interfaceSet = Addresses.getAllAddresses();
String[] interfaces = interfaceSet.toArray(new String[interfaceSet.size()]);
reachableBy.setEntries(interfaces);
reachableBy.setEntryValues(interfaces);
reachableBy.setEnabled(true);
return null;
}
}.execute();
}
@Override
protected void generalClientProxy(boolean isProxy) {
if (isProxy) {
generalCategory.removePreference(generalCategory.findPreference(getString(R.string.TUNNEL_DEST)));
addPreferencesFromResource(R.xml.tunnel_gen_client_proxy);
}
}
@Override
protected void generalClientProxyHttp(boolean isHttp) {
if (!isHttp)
ps.removePreference(ps.findPreference(getString(R.string.TUNNEL_HTTPCLIENT_SSL_OUTPROXIES)));
}
@Override
protected void generalClientStandardOrIrc(boolean isStandardOrIrc) {
if (!isStandardOrIrc)
portCategory.removePreference(portCategory.findPreference(getString(R.string.TUNNEL_USE_SSL)));
}
@Override
protected void generalClientIrc() {
addPreferencesFromResource(R.xml.tunnel_gen_client_irc);
}
@Override
protected void generalServerHttp() {
addPreferencesFromResource(R.xml.tunnel_gen_server_http, generalCategory);
}
@Override
protected void generalServerHttpBidirOrStreamr(boolean isStreamr) {
addPreferencesFromResource(R.xml.tunnel_gen_client_port, portCategory);
portCategory.removePreference(portCategory.findPreference(getString(R.string.TUNNEL_USE_SSL)));
if (isStreamr)
portCategory.removePreference(portCategory.findPreference(getString(R.string.TUNNEL_LISTEN_PORT)));
setupReachableBy((ListPreference) portCategory.findPreference(getString(R.string.TUNNEL_INTERFACE)));
}
@Override
protected void generalServerPort() {
addPreferencesFromResource(R.xml.tunnel_gen_server_port, portCategory);
}
@Override
protected void generalServerPortStreamr(boolean isStreamr) {
if (isStreamr) {
portCategory.removePreference(portCategory.findPreference(getString(R.string.TUNNEL_TARGET_HOST)));
portCategory.removePreference(portCategory.findPreference(getString(R.string.TUNNEL_USE_SSL)));
}
}
@Override
protected void advanced() {
Preference advanced = new Preference(getActivity());
advanced.setKey(getString(R.string.TUNNEL_CAT_ADVANCED));
advanced.setTitle(R.string.settings_label_advanced);
advanced.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
Fragment fragment = AdvancedTunnelPreferenceFragment.newInstance(mTunnelId);
getFragmentManager().beginTransaction()
.replace(R.id.fragment, fragment)
.addToBackStack(null)
.commit();
return true;
}
});
ps.addPreference(advanced);
}
@Override
protected void advancedStreamr(boolean isStreamr) {
}
@Override
protected void advancedServerOrStreamrClient(boolean isServerOrStreamrClient) {
}
@Override
protected void advancedServer() {
}
@Override
protected void advancedServerHttp(boolean isHttp) {
}
@Override
protected void advancedIdle() {
}
@Override
protected void advancedIdleServerOrStreamrClient(boolean isServerOrStreamrClient) {
}
@Override
protected void advancedClient() {
}
@Override
protected void advancedClientHttp() {
}
@Override
protected void advancedClientProxy() {
}
@Override
protected void advancedOther() {
}
}
}

View File

@ -0,0 +1,101 @@
package net.i2p.android.i2ptunnel.util;
/**
* Generic class for handling the composition of tunnel properties.
* <p/>
* See I2PTunnel's editClient.jsp and editServer.jsp for composition logic.
* <p/>
* Some of the abstract methods have boolean parameters. These are the methods
* where the corresponding tunnel properties may or may not exist, depending on
* the value of the boolean. In all other abstract methods, all corresponding
* tunnel properties always exist.
*/
public abstract class TunnelLogic {
protected String mType;
public TunnelLogic(String type) {
mType = type;
}
public void runLogic() {
boolean isProxy = "httpclient".equals(mType) ||
"connectclient".equals(mType) ||
"sockstunnel".equals(mType) ||
"socksirctunnel".equals(mType);
general();
if (TunnelUtil.isClient(mType)) {
generalClient();
generalClientStreamr("streamrclient".equals(mType));
generalClientPort();
generalClientPortStreamr("streamrclient".equals(mType));
generalClientProxy(isProxy);
if (isProxy)
generalClientProxyHttp("httpclient".equals(mType));
generalClientStandardOrIrc("client".equals(mType) || "ircclient".equals(mType));
if ("ircclient".equals(mType))
generalClientIrc();
} else {
if ("httpserver".equals(mType) || "httpbidirserver".equals(mType))
generalServerHttp();
if ("httpbidirserver".equals(mType) || "streamrserver".equals(mType))
generalServerHttpBidirOrStreamr("streamrserver".equals(mType));
generalServerPort();
generalServerPortStreamr("streamrserver".equals(mType));
}
advanced();
advancedStreamr("streamrclient".equals(mType) || "streamrserver".equals(mType));
advancedServerOrStreamrClient(!TunnelUtil.isClient(mType) || "streamrclient".equals(mType));
if (!TunnelUtil.isClient(mType)) {
advancedServer();
advancedServerHttp("httpserver".equals(mType) || "httpbidirserver".equals(mType));
}
advancedIdle();
// streamr client sends pings so it will never be idle
advancedIdleServerOrStreamrClient(!TunnelUtil.isClient(mType) || "streamrclient".equals(mType));
if (TunnelUtil.isClient(mType)) {
advancedClient();
if ("httpclient".equals(mType))
advancedClientHttp();
if (isProxy)
advancedClientProxy();
}
advancedOther();
}
protected abstract void general();
protected abstract void generalClient();
protected abstract void generalClientStreamr(boolean isStreamr);
protected abstract void generalClientPort();
protected abstract void generalClientPortStreamr(boolean isStreamr);
protected abstract void generalClientProxy(boolean isProxy);
protected abstract void generalClientProxyHttp(boolean isHttp);
protected abstract void generalClientStandardOrIrc(boolean isStandardOrIrc);
protected abstract void generalClientIrc();
protected abstract void generalServerHttp();
protected abstract void generalServerHttpBidirOrStreamr(boolean isStreamr);
protected abstract void generalServerPort();
protected abstract void generalServerPortStreamr(boolean isStreamr);
protected abstract void advanced();
protected abstract void advancedStreamr(boolean isStreamr);
protected abstract void advancedServerOrStreamrClient(boolean isServerOrStreamrClient);
protected abstract void advancedServer();
protected abstract void advancedServerHttp(boolean isHttp);
protected abstract void advancedIdle();
protected abstract void advancedIdleServerOrStreamrClient(boolean isServerOrStreamrClient);
protected abstract void advancedClient();
protected abstract void advancedClientHttp();
protected abstract void advancedClientProxy();
protected abstract void advancedOther();
}

View File

@ -0,0 +1,782 @@
package net.i2p.android.i2ptunnel.util;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.os.Bundle;
import net.i2p.I2PAppContext;
import net.i2p.android.router.R;
import net.i2p.android.wizard.model.Page;
import net.i2p.i2ptunnel.TunnelController;
import net.i2p.i2ptunnel.TunnelControllerGroup;
import net.i2p.i2ptunnel.ui.GeneralHelper;
import net.i2p.i2ptunnel.ui.TunnelConfig;
public class TunnelUtil extends GeneralHelper {
public static final String PREFERENCES_FILENAME_PREFIX = "tunnel.";
public TunnelUtil(I2PAppContext context, TunnelControllerGroup tcg) {
super(context, tcg);
}
public TunnelUtil(TunnelControllerGroup tcg) {
super(tcg);
}
/* General tunnel data for any type */
public static String getTypeFromName(String typeName, Context ctx) {
Resources res = ctx.getResources();
if (res.getString(R.string.i2ptunnel_type_client).equals(typeName))
return "client";
else if (res.getString(R.string.i2ptunnel_type_httpclient).equals(typeName))
return "httpclient";
else if (res.getString(R.string.i2ptunnel_type_ircclient).equals(typeName))
return "ircclient";
else if (res.getString(R.string.i2ptunnel_type_server).equals(typeName))
return "server";
else if (res.getString(R.string.i2ptunnel_type_httpserver).equals(typeName))
return "httpserver";
else if (res.getString(R.string.i2ptunnel_type_sockstunnel).equals(typeName))
return "sockstunnel";
else if (res.getString(R.string.i2ptunnel_type_socksirctunnel).equals(typeName))
return "socksirctunnel";
else if (res.getString(R.string.i2ptunnel_type_connectclient).equals(typeName))
return "connectclient";
else if (res.getString(R.string.i2ptunnel_type_ircserver).equals(typeName))
return "ircserver";
else if (res.getString(R.string.i2ptunnel_type_streamrclient).equals(typeName))
return "streamrclient";
else if (res.getString(R.string.i2ptunnel_type_streamrserver).equals(typeName))
return "streamrserver";
else if (res.getString(R.string.i2ptunnel_type_httpbidirserver).equals(typeName))
return "httpbidirserver";
else
return typeName;
}
public static String getTypeName(String type, Context context) {
Resources res = context.getResources();
switch (type) {
case "client":
return res.getString(R.string.i2ptunnel_type_client);
case "httpclient":
return res.getString(R.string.i2ptunnel_type_httpclient);
case "ircclient":
return res.getString(R.string.i2ptunnel_type_ircclient);
case "server":
return res.getString(R.string.i2ptunnel_type_server);
case "httpserver":
return res.getString(R.string.i2ptunnel_type_httpserver);
case "sockstunnel":
return res.getString(R.string.i2ptunnel_type_sockstunnel);
case "socksirctunnel":
return res.getString(R.string.i2ptunnel_type_socksirctunnel);
case "connectclient":
return res.getString(R.string.i2ptunnel_type_connectclient);
case "ircserver":
return res.getString(R.string.i2ptunnel_type_ircserver);
case "streamrclient":
return res.getString(R.string.i2ptunnel_type_streamrclient);
case "streamrserver":
return res.getString(R.string.i2ptunnel_type_streamrserver);
case "httpbidirserver":
return res.getString(R.string.i2ptunnel_type_httpbidirserver);
default:
return type;
}
}
public static boolean isClient(String type) {
return TunnelController.isClient(type);
}
public static String getPreferencesFilename(int tunnel) {
return PREFERENCES_FILENAME_PREFIX + tunnel;
}
public static void writeTunnelToPreferences(Context ctx, TunnelControllerGroup tcg, int tunnel) {
new TunnelUtil(tcg).writeTunnelToPreferences(ctx, tunnel);
}
public void writeTunnelToPreferences(Context ctx, int tunnel) {
Resources res = ctx.getResources();
if (getController(tunnel) == null)
throw new IllegalArgumentException("Cannot write non-existent tunnel to Preferences");
// Get the current preferences for this tunnel
SharedPreferences preferences = ctx.getSharedPreferences(
getPreferencesFilename(tunnel), Context.MODE_PRIVATE);
// Clear all previous values
SharedPreferences.Editor ed = preferences.edit().clear();
// Load the tunnel config into the preferences
String type = getTunnelType(tunnel);
ed.putString(res.getString(R.string.TUNNEL_TYPE), type);
new TunnelToPreferences(ed, res, tunnel, type).runLogic();
ed.apply();
}
class TunnelToPreferences extends TunnelLogic {
SharedPreferences.Editor ed;
Resources res;
int tunnel;
public TunnelToPreferences(SharedPreferences.Editor ed, Resources res, int tunnel, String type) {
super(type);
this.ed = ed;
this.res = res;
this.tunnel = tunnel;
}
@Override
protected void general() {
ed.putString(res.getString(R.string.TUNNEL_NAME), getTunnelName(tunnel));
ed.putString(res.getString(R.string.TUNNEL_DESCRIPTION), getTunnelDescription(tunnel));
ed.putBoolean(res.getString(R.string.TUNNEL_START_ON_LOAD), shouldStartAutomatically(tunnel));
if (!isClient(mType) || getPersistentClientKey(tunnel))
ed.putString(res.getString(R.string.TUNNEL_PRIV_KEY_FILE), getPrivateKeyFile(tunnel));
}
@Override
protected void generalClient() {
ed.putBoolean(res.getString(R.string.TUNNEL_OPT_PERSISTENT_KEY), getPersistentClientKey(tunnel));
}
@Override
protected void generalClientStreamr(boolean isStreamr) {
if (isStreamr)
ed.putString(res.getString(R.string.TUNNEL_TARGET_HOST), getTargetHost(tunnel));
else
ed.putBoolean(res.getString(R.string.TUNNEL_SHARED_CLIENT), isSharedClient(tunnel));
}
@Override
protected void generalClientPort() {
ed.putInt(res.getString(R.string.TUNNEL_LISTEN_PORT), getClientPort(tunnel));
}
@Override
protected void generalClientPortStreamr(boolean isStreamr) {
if (!isStreamr)
ed.putString(res.getString(R.string.TUNNEL_INTERFACE), getClientInterface(tunnel));
}
@Override
protected void generalClientProxy(boolean isProxy) {
if (isProxy)
ed.putString(res.getString(R.string.TUNNEL_PROXIES), getClientDestination(tunnel));
else
ed.putString(res.getString(R.string.TUNNEL_DEST), getClientDestination(tunnel));
}
@Override
protected void generalClientProxyHttp(boolean isHttp) {
if (isHttp)
ed.putString(res.getString(R.string.TUNNEL_HTTPCLIENT_SSL_OUTPROXIES), getSslProxies(tunnel));
}
@Override
protected void generalClientStandardOrIrc(boolean isStandardOrIrc) {
if (isStandardOrIrc)
ed.putBoolean(res.getString(R.string.TUNNEL_USE_SSL), isSSLEnabled(tunnel));
}
@Override
protected void generalClientIrc() {
ed.putBoolean(res.getString(R.string.TUNNEL_IRCCLIENT_ENABLE_DCC), getDCC(tunnel));
}
@Override
protected void generalServerHttp() {
ed.putString(res.getString(R.string.TUNNEL_SPOOFED_HOST), getSpoofedHost(tunnel));
}
@Override
protected void generalServerHttpBidirOrStreamr(boolean isStreamr) {
ed.putString(res.getString(R.string.TUNNEL_INTERFACE), getClientInterface(tunnel));
if (!isStreamr)
ed.putInt(res.getString(R.string.TUNNEL_LISTEN_PORT), getClientPort(tunnel));
}
@Override
protected void generalServerPort() {
ed.putInt(res.getString(R.string.TUNNEL_TARGET_PORT), getTargetPort(tunnel));
}
@Override
protected void generalServerPortStreamr(boolean isStreamr) {
if (!isStreamr) {
ed.putString(res.getString(R.string.TUNNEL_TARGET_HOST), getTargetHost(tunnel));
ed.putBoolean(res.getString(R.string.TUNNEL_USE_SSL), isSSLEnabled(tunnel));
}
}
@Override
protected void advanced() {
ed.putInt(res.getString(R.string.TUNNEL_OPT_LENGTH),
getTunnelDepth(tunnel, res.getInteger(R.integer.DEFAULT_TUNNEL_LENGTH)));
ed.putInt(res.getString(R.string.TUNNEL_OPT_VARIANCE),
getTunnelVariance(tunnel, res.getInteger(R.integer.DEFAULT_TUNNEL_VARIANCE)));
ed.putInt(res.getString(R.string.TUNNEL_OPT_QUANTITY),
getTunnelQuantity(tunnel, res.getInteger(R.integer.DEFAULT_TUNNEL_QUANTITY)));
ed.putInt(res.getString(R.string.TUNNEL_OPT_BACKUP_QUANTITY),
getTunnelBackupQuantity(tunnel, res.getInteger(R.integer.DEFAULT_TUNNEL_BACKUP_QUANTITY)));
}
@Override
protected void advancedStreamr(boolean isStreamr) {
if (!isStreamr)
ed.putString(res.getString(R.string.TUNNEL_OPT_PROFILE),
isInteractive(tunnel) ? "interactive" : "bulk");
}
@Override
protected void advancedServerOrStreamrClient(boolean isServerOrStreamrClient) {
if (!isServerOrStreamrClient)
ed.putBoolean(res.getString(R.string.TUNNEL_OPT_DELAY_CONNECT),
shouldDelayConnect(tunnel));
}
@Override
protected void advancedServer() {
//ed.putBoolean(res.getString(R.string.TUNNEL_OPT_ENCRYPT), getEncrypt(tunnel));
//ed.putString(res.getString(R.string.TUNNEL_OPT_ENCRYPT_KEY), getEncryptKey(tunnel));
ed.putInt(res.getString(R.string.TUNNEL_OPT_ACCESS_MODE), getAccessMode(tunnel));
ed.putString(res.getString(R.string.TUNNEL_OPT_ACCESS_LIST), getAccessList(tunnel));
ed.putBoolean(res.getString(R.string.TUNNEL_OPT_UNIQUE_LOCAL), getUniqueLocal(tunnel));
ed.putBoolean(res.getString(R.string.TUNNEL_OPT_MULTIHOME), getMultihome(tunnel));
ed.putInt(res.getString(R.string.TUNNEL_OPT_LIMIT_MINUTE), getLimitMinute(tunnel));
ed.putInt(res.getString(R.string.TUNNEL_OPT_LIMIT_HOUR), getLimitHour(tunnel));
ed.putInt(res.getString(R.string.TUNNEL_OPT_LIMIT_DAY), getLimitDay(tunnel));
ed.putInt(res.getString(R.string.TUNNEL_OPT_TOTAL_MINUTE), getTotalMinute(tunnel));
ed.putInt(res.getString(R.string.TUNNEL_OPT_TOTAL_HOUR), getTotalHour(tunnel));
ed.putInt(res.getString(R.string.TUNNEL_OPT_TOTAL_DAY), getTotalDay(tunnel));
ed.putInt(res.getString(R.string.TUNNEL_OPT_MAX_STREAMS), getMaxStreams(tunnel));
}
@Override
protected void advancedServerHttp(boolean isHttp) {
if (isHttp) {
ed.putBoolean(res.getString(R.string.TUNNEL_OPT_REJECT_INPROXY), getRejectInproxy(tunnel));
ed.putInt(res.getString(R.string.TUNNEL_OPT_POST_CHECK_TIME), getPostCheckTime(tunnel));
ed.putInt(res.getString(R.string.TUNNEL_OPT_POST_MAX), getPostMax(tunnel));
ed.putInt(res.getString(R.string.TUNNEL_OPT_POST_BAN_TIME), getPostBanTime(tunnel));
ed.putInt(res.getString(R.string.TUNNEL_OPT_POST_TOTAL_MAX), getPostTotalMax(tunnel));
ed.putInt(res.getString(R.string.TUNNEL_OPT_POST_TOTAL_BAN_TIME), getPostTotalBanTime(tunnel));
}
}
@Override
protected void advancedIdle() {
ed.putBoolean(res.getString(R.string.TUNNEL_OPT_REDUCE_IDLE),
getReduceOnIdle(tunnel, res.getBoolean(R.bool.DEFAULT_REDUCE_ON_IDLE)));
ed.putInt(res.getString(R.string.TUNNEL_OPT_REDUCE_QUANTITY),
getReduceCount(tunnel, res.getInteger(R.integer.DEFAULT_REDUCE_COUNT)));
ed.putInt(res.getString(R.string.TUNNEL_OPT_REDUCE_TIME),
getReduceTime(tunnel, res.getInteger(R.integer.DEFAULT_REDUCE_TIME)));
}
@Override
protected void advancedIdleServerOrStreamrClient(boolean isServerOrStreamrClient) {
if (!isServerOrStreamrClient)
ed.putBoolean(res.getString(R.string.TUNNEL_OPT_DELAY_OPEN), getDelayOpen(tunnel));
}
@Override
protected void advancedClient() {
ed.putBoolean(res.getString(R.string.TUNNEL_OPT_CLOSE_IDLE),
getCloseOnIdle(tunnel, res.getBoolean(R.bool.DEFAULT_CLOSE_ON_IDLE)));
ed.putInt(res.getString(R.string.TUNNEL_OPT_CLOSE_TIME),
getCloseTime(tunnel, res.getInteger(R.integer.DEFAULT_CLOSE_TIME)));
ed.putBoolean(res.getString(R.string.TUNNEL_OTP_NEW_KEYS), getNewDest(tunnel));
}
@Override
protected void advancedClientHttp() {
ed.putBoolean(res.getString(R.string.TUNNEL_OPT_HTTPCLIENT_PASS_UA), getAllowUserAgent(tunnel));
ed.putBoolean(res.getString(R.string.TUNNEL_OPT_HTTPCLIENT_PASS_REFERER), getAllowReferer(tunnel));
ed.putBoolean(res.getString(R.string.TUNNEL_OPT_HTTPCLIENT_PASS_ACCEPT), getAllowAccept(tunnel));
ed.putBoolean(res.getString(R.string.TUNNEL_OPT_HTTPCLIENT_ALLOW_SSL), getAllowInternalSSL(tunnel));
ed.putString(res.getString(R.string.TUNNEL_OPT_JUMP_LIST), getJumpList(tunnel));
}
@Override
protected void advancedClientProxy() {
ed.putBoolean(res.getString(R.string.TUNNEL_OPT_LOCAL_AUTH), !"false".equals(getProxyAuth(tunnel)));
ed.putString(res.getString(R.string.TUNNEL_OPT_LOCAL_USERNAME), "");
ed.putString(res.getString(R.string.TUNNEL_OPT_LOCAL_PASSWORD), "");
ed.putBoolean(res.getString(R.string.TUNNEL_OPT_OUTPROXY_AUTH), getOutproxyAuth(tunnel));
ed.putString(res.getString(R.string.TUNNEL_OPT_OUTPROXY_USERNAME), getOutproxyUsername(tunnel));
ed.putString(res.getString(R.string.TUNNEL_OPT_OUTPROXY_PASSWORD), getOutproxyPassword(tunnel));
}
@Override
protected void advancedOther() {
ed.putInt(res.getString(R.string.TUNNEL_OPT_SIGTYPE), getSigType(tunnel, mType));
ed.putString(res.getString(R.string.TUNNEL_OPT_CUSTOM_OPTIONS), getCustomOptionsString(tunnel));
}
}
public static TunnelConfig createConfigFromPreferences(Context ctx, TunnelControllerGroup tcg, int tunnel) {
return new TunnelUtil(tcg).createConfigFromPreferences(ctx, tunnel);
}
public TunnelConfig createConfigFromPreferences(Context ctx, int tunnel) {
Resources res = ctx.getResources();
// Get the current preferences for this tunnel
SharedPreferences prefs = ctx.getSharedPreferences(
getPreferencesFilename(tunnel), Context.MODE_PRIVATE);
// Create the TunnelConfig
TunnelConfig cfg = new TunnelConfig();
// Update the TunnelConfig from the preferences
cfg.setType(prefs.getString(res.getString(R.string.TUNNEL_TYPE), null));
String type = cfg.getType();
new TunnelConfigFromPreferences(cfg, prefs, res, _group, tunnel, type).runLogic();
return cfg;
}
class TunnelConfigFromPreferences extends TunnelLogic {
TunnelConfig cfg;
SharedPreferences prefs;
Resources res;
TunnelControllerGroup tcg;
int tunnel;
public TunnelConfigFromPreferences(TunnelConfig cfg, SharedPreferences prefs, Resources res,
TunnelControllerGroup tcg, int tunnel, String type) {
super(type);
this.cfg = cfg;
this.prefs = prefs;
this.res = res;
this.tcg = tcg;
this.tunnel = tunnel;
}
@Override
protected void general() {
cfg.setName(prefs.getString(res.getString(R.string.TUNNEL_NAME), null));
cfg.setDescription(prefs.getString(res.getString(R.string.TUNNEL_DESCRIPTION), null));
cfg.setStartOnLoad(prefs.getBoolean(res.getString(R.string.TUNNEL_START_ON_LOAD),
res.getBoolean(R.bool.DEFAULT_START_ON_LOAD)));
if (!isClient(mType) || prefs.getBoolean(res.getString(R.string.TUNNEL_OPT_PERSISTENT_KEY),
res.getBoolean(R.bool.DEFAULT_PERSISTENT_KEY)))
cfg.setPrivKeyFile(prefs.getString(res.getString(R.string.TUNNEL_PRIV_KEY_FILE),
getPrivateKeyFile(tcg, tunnel)));
}
@Override
protected void generalClient() {
// See advancedClient() for persistent key handling
}
@Override
protected void generalClientStreamr(boolean isStreamr) {
if (isStreamr)
cfg.setTargetHost(prefs.getString(res.getString(R.string.TUNNEL_TARGET_HOST), null));
else
cfg.setShared(prefs.getBoolean(res.getString(R.string.TUNNEL_SHARED_CLIENT),
res.getBoolean(R.bool.DEFAULT_SHARED_CLIENTS)));
}
@Override
protected void generalClientPort() {
cfg.setPort(prefs.getInt(res.getString(R.string.TUNNEL_LISTEN_PORT), -1));
}
@Override
protected void generalClientPortStreamr(boolean isStreamr) {
if (!isStreamr)
cfg.setReachableBy(prefs.getString(res.getString(R.string.TUNNEL_INTERFACE), "127.0.0.1"));
}
@Override
protected void generalClientProxy(boolean isProxy) {
if (isProxy)
cfg.setProxyList(prefs.getString(res.getString(R.string.TUNNEL_PROXIES), null));
else
cfg.setTargetDestination(prefs.getString(res.getString(R.string.TUNNEL_DEST), null));
}
@Override
protected void generalClientProxyHttp(boolean isHttp) {
if (isHttp)
cfg.setSslProxies(prefs.getString(res.getString(R.string.TUNNEL_HTTPCLIENT_SSL_OUTPROXIES), null));
}
@Override
protected void generalClientStandardOrIrc(boolean isStandardOrIrc) {
if (isStandardOrIrc)
cfg.setUseSSL(prefs.getBoolean(res.getString(R.string.TUNNEL_USE_SSL), false));
}
@Override
protected void generalClientIrc() {
cfg.setDCC(prefs.getBoolean(res.getString(R.string.TUNNEL_IRCCLIENT_ENABLE_DCC), false));
}
@Override
protected void generalServerHttp() {
cfg.setSpoofedHost(prefs.getString(res.getString(R.string.TUNNEL_SPOOFED_HOST), null));
}
@Override
protected void generalServerHttpBidirOrStreamr(boolean isStreamr) {
cfg.setReachableBy(prefs.getString(res.getString(R.string.TUNNEL_INTERFACE), "127.0.0.1"));
if (!isStreamr)
cfg.setPort(prefs.getInt(res.getString(R.string.TUNNEL_LISTEN_PORT), -1));
}
@Override
protected void generalServerPort() {
cfg.setTargetPort(prefs.getInt(res.getString(R.string.TUNNEL_TARGET_PORT), -1));
}
@Override
protected void generalServerPortStreamr(boolean isStreamr) {
if (!isStreamr) {
cfg.setTargetHost(prefs.getString(res.getString(R.string.TUNNEL_TARGET_HOST), "127.0.0.1"));
cfg.setUseSSL(prefs.getBoolean(res.getString(R.string.TUNNEL_USE_SSL), false));
}
}
@Override
protected void advanced() {
cfg.setTunnelDepth(prefs.getInt(res.getString(R.string.TUNNEL_OPT_LENGTH),
res.getInteger(R.integer.DEFAULT_TUNNEL_LENGTH)));
cfg.setTunnelVariance(prefs.getInt(res.getString(R.string.TUNNEL_OPT_VARIANCE),
res.getInteger(R.integer.DEFAULT_TUNNEL_VARIANCE)));
cfg.setTunnelQuantity(prefs.getInt(res.getString(R.string.TUNNEL_OPT_QUANTITY),
res.getInteger(R.integer.DEFAULT_TUNNEL_QUANTITY)));
cfg.setTunnelBackupQuantity(prefs.getInt(res.getString(R.string.TUNNEL_OPT_BACKUP_QUANTITY),
res.getInteger(R.integer.DEFAULT_TUNNEL_BACKUP_QUANTITY)));
}
@Override
protected void advancedStreamr(boolean isStreamr) {
if (!isStreamr)
cfg.setProfile(prefs.getString(res.getString(R.string.TUNNEL_OPT_PROFILE), "bulk"));
}
@Override
protected void advancedServerOrStreamrClient(boolean isServerOrStreamrClient) {
if (!isServerOrStreamrClient)
cfg.setConnectDelay(prefs.getBoolean(res.getString(R.string.TUNNEL_OPT_DELAY_CONNECT), false));
}
@Override
protected void advancedServer() {
//cfg.setEncrypt(prefs.getBoolean(res.getString(R.string.TUNNEL_OPT_ENCRYPT), false));
//cfg.setEncryptKey(prefs.getString(res.getString(R.string.TUNNEL_OPT_ENCRYPT_KEY), ""));
cfg.setAccessMode(prefs.getInt(res.getString(R.string.TUNNEL_OPT_ACCESS_MODE), 0));
cfg.setAccessList(prefs.getString(res.getString(R.string.TUNNEL_OPT_ACCESS_LIST), ""));
cfg.setUniqueLocal(prefs.getBoolean(res.getString(R.string.TUNNEL_OPT_UNIQUE_LOCAL), false));
cfg.setMultihome(prefs.getBoolean(res.getString(R.string.TUNNEL_OPT_MULTIHOME), false));
cfg.setLimitMinute(prefs.getInt(res.getString(R.string.TUNNEL_OPT_LIMIT_MINUTE), 0));
cfg.setLimitHour(prefs.getInt(res.getString(R.string.TUNNEL_OPT_LIMIT_HOUR), 0));
cfg.setLimitDay(prefs.getInt(res.getString(R.string.TUNNEL_OPT_LIMIT_DAY), 0));
cfg.setTotalMinute(prefs.getInt(res.getString(R.string.TUNNEL_OPT_TOTAL_MINUTE), 0));
cfg.setTotalHour(prefs.getInt(res.getString(R.string.TUNNEL_OPT_TOTAL_HOUR), 0));
cfg.setTotalDay(prefs.getInt(res.getString(R.string.TUNNEL_OPT_TOTAL_DAY), 0));
cfg.setMaxStreams(prefs.getInt(res.getString(R.string.TUNNEL_OPT_MAX_STREAMS), 0));
}
@Override
protected void advancedServerHttp(boolean isHttp) {
if (isHttp) {
cfg.setRejectInproxy(prefs.getBoolean(res.getString(R.string.TUNNEL_OPT_REJECT_INPROXY), false));
cfg.setPostCheckTime(prefs.getInt(res.getString(R.string.TUNNEL_OPT_POST_CHECK_TIME), 0));
cfg.setPostMax(prefs.getInt(res.getString(R.string.TUNNEL_OPT_POST_MAX), 0));
cfg.setPostBanTime(prefs.getInt(res.getString(R.string.TUNNEL_OPT_POST_BAN_TIME), 0));
cfg.setPostTotalMax(prefs.getInt(res.getString(R.string.TUNNEL_OPT_POST_TOTAL_MAX), 0));
cfg.setPostTotalBanTime(prefs.getInt(res.getString(R.string.TUNNEL_OPT_POST_TOTAL_BAN_TIME), 0));
}
}
@Override
protected void advancedIdle() {
cfg.setReduce(prefs.getBoolean(res.getString(R.string.TUNNEL_OPT_REDUCE_IDLE),
res.getBoolean(R.bool.DEFAULT_REDUCE_ON_IDLE)));
cfg.setReduceCount(prefs.getInt(res.getString(R.string.TUNNEL_OPT_REDUCE_QUANTITY),
res.getInteger(R.integer.DEFAULT_REDUCE_COUNT)));
cfg.setReduceTime(prefs.getInt(res.getString(R.string.TUNNEL_OPT_REDUCE_TIME),
res.getInteger(R.integer.DEFAULT_REDUCE_TIME)));
}
@Override
protected void advancedIdleServerOrStreamrClient(boolean isServerOrStreamrClient) {
if (!isServerOrStreamrClient)
cfg.setDelayOpen(prefs.getBoolean(res.getString(R.string.TUNNEL_OPT_DELAY_OPEN),
res.getBoolean(R.bool.DEFAULT_DELAY_OPEN)));
}
@Override
protected void advancedClient() {
cfg.setClose(prefs.getBoolean(res.getString(R.string.TUNNEL_OPT_CLOSE_IDLE),
res.getBoolean(R.bool.DEFAULT_CLOSE_ON_IDLE)));
cfg.setCloseTime(prefs.getInt(res.getString(R.string.TUNNEL_OPT_CLOSE_TIME),
res.getInteger(R.integer.DEFAULT_CLOSE_TIME)));
cfg.setNewDest(prefs.getBoolean(res.getString(R.string.TUNNEL_OPT_PERSISTENT_KEY),
res.getBoolean(R.bool.DEFAULT_PERSISTENT_KEY)) ? 2 :
prefs.getBoolean(res.getString(R.string.TUNNEL_OTP_NEW_KEYS), res.getBoolean(R.bool.DEFAULT_NEW_KEYS)) ? 1 : 0);
}
@Override
protected void advancedClientHttp() {
cfg.setAllowUserAgent(prefs.getBoolean(res.getString(R.string.TUNNEL_OPT_HTTPCLIENT_PASS_UA), false));
cfg.setAllowReferer(prefs.getBoolean(res.getString(R.string.TUNNEL_OPT_HTTPCLIENT_PASS_REFERER), false));
cfg.setAllowAccept(prefs.getBoolean(res.getString(R.string.TUNNEL_OPT_HTTPCLIENT_PASS_ACCEPT), false));
cfg.setAllowInternalSSL(prefs.getBoolean(res.getString(R.string.TUNNEL_OPT_HTTPCLIENT_ALLOW_SSL), false));
cfg.setJumpList(prefs.getString(res.getString(R.string.TUNNEL_OPT_JUMP_LIST),
res.getString(R.string.DEFAULT_JUMP_LIST)));
}
@Override
protected void advancedClientProxy() {
cfg.setProxyAuth(prefs.getBoolean(res.getString(R.string.TUNNEL_OPT_LOCAL_AUTH), false) ? "digest" : "false");
String username = prefs.getString(res.getString(R.string.TUNNEL_OPT_LOCAL_USERNAME), "");
if (!username.isEmpty()) {
cfg.setProxyUsername(username);
cfg.setProxyPassword(prefs.getString(res.getString(R.string.TUNNEL_OPT_LOCAL_PASSWORD), ""));
}
cfg.setOutproxyAuth(prefs.getBoolean(res.getString(R.string.TUNNEL_OPT_OUTPROXY_AUTH), false));
cfg.setOutproxyUsername(prefs.getString(res.getString(R.string.TUNNEL_OPT_OUTPROXY_USERNAME), ""));
cfg.setOutproxyPassword(prefs.getString(res.getString(R.string.TUNNEL_OPT_OUTPROXY_PASSWORD), ""));
}
@Override
protected void advancedOther() {
cfg.setSigType(Integer.toString(prefs.getInt(res.getString(R.string.TUNNEL_OPT_SIGTYPE),
res.getInteger(R.integer.DEFAULT_SIGTYPE))));
cfg.setCustomOptions(prefs.getString(res.getString(R.string.TUNNEL_OPT_CUSTOM_OPTIONS), null));
}
}
public static TunnelConfig createConfigFromWizard(
Context ctx, TunnelControllerGroup tcg, Bundle data) {
return new TunnelUtil(tcg).createConfigFromWizard(ctx, data);
}
public TunnelConfig createConfigFromWizard(Context ctx, Bundle data) {
// Get the Bundle keys
Resources res = ctx.getResources();
// Create the TunnelConfig
TunnelConfig cfg = new TunnelConfig();
// Update the TunnelConfig from the tunnel wizard settings
String kClientServer = res.getString(R.string.i2ptunnel_wizard_k_client_server);
String kType = res.getString(R.string.i2ptunnel_wizard_k_type);
String clientServer = data.getBundle(kClientServer).getString(Page.SIMPLE_DATA_KEY);
String typeName = data.getBundle(clientServer + ":" + kType).getString(Page.SIMPLE_DATA_KEY);
String type = getTypeFromName(typeName, ctx);
cfg.setType(type);
new TunnelConfigFromWizard(cfg, data, res, _group, type).runLogic();
return cfg;
}
class TunnelConfigFromWizard extends TunnelLogic {
TunnelConfig cfg;
Bundle data;
Resources res;
TunnelControllerGroup tcg;
public TunnelConfigFromWizard(TunnelConfig cfg, Bundle data, Resources res,
TunnelControllerGroup tcg, String type) {
super(type);
this.cfg = cfg;
this.data = data;
this.res = res;
this.tcg = tcg;
}
@Override
protected void general() {
cfg.setName(data.getBundle(res.getString(R.string.i2ptunnel_wizard_k_name)).getString(Page.SIMPLE_DATA_KEY));
cfg.setDescription(data.getBundle(res.getString(R.string.i2ptunnel_wizard_k_desc)).getString(Page.SIMPLE_DATA_KEY));
cfg.setStartOnLoad(data.getBundle(res.getString(R.string.i2ptunnel_wizard_k_auto_start)).getBoolean(Page.SIMPLE_DATA_KEY));
if (!isClient(mType) || res.getBoolean(R.bool.DEFAULT_PERSISTENT_KEY))
cfg.setPrivKeyFile(getPrivateKeyFile(tcg, -1));
}
@Override
protected void generalClient() {
// See advancedClient() for persistent key handling
}
@Override
protected void generalClientStreamr(boolean isStreamr) {
if (isStreamr)
cfg.setTargetHost(data.getBundle(res.getString(R.string.i2ptunnel_wizard_k_target_host)).getString(Page.SIMPLE_DATA_KEY));
else
cfg.setShared(res.getBoolean(R.bool.DEFAULT_SHARED_CLIENTS));
// Only set default tunnel parameters if this is not going to be a shared tunnel
if (isStreamr || res.getBoolean(R.bool.DEFAULT_SHARED_CLIENTS)) {
cfg.setTunnelDepth(res.getInteger(R.integer.DEFAULT_TUNNEL_LENGTH));
cfg.setTunnelVariance(res.getInteger(R.integer.DEFAULT_TUNNEL_VARIANCE));
cfg.setTunnelQuantity(res.getInteger(R.integer.DEFAULT_TUNNEL_QUANTITY));
cfg.setTunnelBackupQuantity(res.getInteger(R.integer.DEFAULT_TUNNEL_BACKUP_QUANTITY));
}
}
@Override
protected void generalClientPort() {
cfg.setPort(Integer.parseInt(data.getBundle(
res.getString(R.string.i2ptunnel_wizard_k_binding_port)).getString(Page.SIMPLE_DATA_KEY)));
}
@Override
protected void generalClientPortStreamr(boolean isStreamr) {
if (!isStreamr)
cfg.setReachableBy(data.getBundle(res.getString(R.string.i2ptunnel_wizard_k_reachable_on)).getString(Page.SIMPLE_DATA_KEY));
}
@Override
protected void generalClientProxy(boolean isProxy) {
if (isProxy)
cfg.setProxyList(data.getBundle(res.getString(R.string.i2ptunnel_wizard_k_outproxies)).getString(Page.SIMPLE_DATA_KEY));
else
cfg.setTargetDestination(data.getBundle(res.getString(R.string.i2ptunnel_wizard_k_dest)).getString(Page.SIMPLE_DATA_KEY));
}
@Override
protected void generalClientProxyHttp(boolean isHttp) {
if (isHttp)
cfg.setSslProxies(null);
}
@Override
protected void generalClientStandardOrIrc(boolean isStandardOrIrc) {
if (isStandardOrIrc)
cfg.setUseSSL(false);
}
@Override
protected void generalClientIrc() {
cfg.setDCC(false);
}
@Override
protected void generalServerHttp() {
cfg.setSpoofedHost(null);
}
@Override
protected void generalServerHttpBidirOrStreamr(boolean isStreamr) {
cfg.setReachableBy(data.getBundle(res.getString(R.string.i2ptunnel_wizard_k_reachable_on)).getString(Page.SIMPLE_DATA_KEY));
if (!isStreamr)
cfg.setPort(Integer.parseInt(data.getBundle(
res.getString(R.string.i2ptunnel_wizard_k_binding_port)).getString(Page.SIMPLE_DATA_KEY)));
}
@Override
protected void generalServerPort() {
cfg.setTargetPort(Integer.parseInt(data.getBundle(
res.getString(R.string.i2ptunnel_wizard_k_target_port)).getString(Page.SIMPLE_DATA_KEY)));
}
@Override
protected void generalServerPortStreamr(boolean isStreamr) {
if (!isStreamr) {
cfg.setTargetHost(data.getBundle(res.getString(R.string.i2ptunnel_wizard_k_target_host)).getString(Page.SIMPLE_DATA_KEY));
cfg.setUseSSL(false);
}
}
@Override
protected void advanced() {
// Tunnel parameters handled in generalClientStreamr()
}
@Override
protected void advancedStreamr(boolean isStreamr) {
if (!isStreamr)
cfg.setProfile("bulk");
}
@Override
protected void advancedServerOrStreamrClient(boolean isServerOrStreamrClient) {
if (!isServerOrStreamrClient)
cfg.setConnectDelay(false);
}
@Override
protected void advancedServer() {
cfg.setEncrypt(false);
cfg.setAccessMode(0);
cfg.setUniqueLocal(false);
cfg.setMultihome(false);
cfg.setLimitMinute(0);
cfg.setLimitHour(0);
cfg.setLimitDay(0);
cfg.setTotalMinute(0);
cfg.setTotalHour(0);
cfg.setTotalDay(0);
cfg.setMaxStreams(0);
}
@Override
protected void advancedServerHttp(boolean isHttp) {
if (isHttp) {
cfg.setRejectInproxy(false);
cfg.setPostCheckTime(0);
cfg.setPostMax(0);
cfg.setPostBanTime(0);
cfg.setPostTotalMax(0);
cfg.setPostTotalBanTime(0);
}
}
@Override
protected void advancedIdle() {
cfg.setReduce(res.getBoolean(R.bool.DEFAULT_REDUCE_ON_IDLE));
cfg.setReduceCount(res.getInteger(R.integer.DEFAULT_REDUCE_COUNT));
cfg.setReduceTime(res.getInteger(R.integer.DEFAULT_REDUCE_TIME));
}
@Override
protected void advancedIdleServerOrStreamrClient(boolean isServerOrStreamrClient) {
if (!isServerOrStreamrClient)
cfg.setDelayOpen(res.getBoolean(R.bool.DEFAULT_DELAY_OPEN));
}
@Override
protected void advancedClient() {
cfg.setClose(res.getBoolean(R.bool.DEFAULT_CLOSE_ON_IDLE));
cfg.setCloseTime(res.getInteger(R.integer.DEFAULT_CLOSE_TIME));
cfg.setNewDest(res.getBoolean(R.bool.DEFAULT_PERSISTENT_KEY) ? 2 :
res.getBoolean(R.bool.DEFAULT_NEW_KEYS) ? 1 : 0);
}
@Override
protected void advancedClientHttp() {
cfg.setAllowUserAgent(false);
cfg.setAllowReferer(false);
cfg.setAllowAccept(false);
cfg.setAllowInternalSSL(false);
cfg.setJumpList(res.getString(R.string.DEFAULT_JUMP_LIST));
}
@Override
protected void advancedClientProxy() {
cfg.setProxyAuth("false");
cfg.setOutproxyAuth(false);
}
@Override
protected void advancedOther() {
cfg.setSigType(Integer.toString(res.getInteger(R.integer.DEFAULT_SIGTYPE)));
}
}
}

View File

@ -0,0 +1,60 @@
package net.i2p.android.preferences;
import android.os.Bundle;
import android.preference.Preference;
import android.support.v4.app.Fragment;
import android.support.v4.preference.PreferenceFragment;
import net.i2p.android.router.R;
import net.i2p.android.router.SettingsActivity;
public class AdvancedPreferenceFragment extends PreferenceFragment {
private static final String PREFERENCE_CATEGORY_TRANSPORTS = "preference_category_transports";
private static final String PREFERENCE_CATEGORY_EXPL_TUNNELS = "preference_category_expl_tunnels";
@Override
public void onCreate(Bundle paramBundle) {
super.onCreate(paramBundle);
addPreferencesFromResource(R.xml.settings_advanced);
findPreference(PREFERENCE_CATEGORY_TRANSPORTS)
.setOnPreferenceClickListener(new CategoryClickListener(PREFERENCE_CATEGORY_TRANSPORTS));
findPreference(PREFERENCE_CATEGORY_EXPL_TUNNELS)
.setOnPreferenceClickListener(new CategoryClickListener(PREFERENCE_CATEGORY_EXPL_TUNNELS));
}
@Override
public void onResume() {
super.onResume();
((SettingsActivity) getActivity()).getSupportActionBar().setTitle(R.string.settings_label_advanced);
}
private class CategoryClickListener implements Preference.OnPreferenceClickListener {
private String category;
public CategoryClickListener(String category) {
this.category = category;
}
@Override
public boolean onPreferenceClick(Preference preference) {
Fragment fragment;
switch (category) {
case PREFERENCE_CATEGORY_TRANSPORTS:
fragment = new TransportsPreferenceFragment();
break;
case PREFERENCE_CATEGORY_EXPL_TUNNELS:
fragment = new ExploratoryPoolPreferenceFragment();
break;
default:
throw new AssertionError();
}
getActivity().getSupportFragmentManager().beginTransaction()
.replace(R.id.fragment, fragment)
.addToBackStack(null)
.commit();
return true;
}
}
}

View File

@ -0,0 +1,36 @@
package net.i2p.android.preferences;
import android.os.Bundle;
import net.i2p.android.router.R;
import net.i2p.android.router.SettingsActivity;
public class AppearancePreferenceFragment extends I2PreferenceFragment {
@Override
public void onCreate(Bundle paramBundle) {
super.onCreate(paramBundle);
addPreferencesFromResource(R.xml.settings_appearance);
}
@Override
public void onStart() {
super.onStart();
getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(
(SettingsActivity) getActivity()
);
}
@Override
public void onResume() {
super.onResume();
((SettingsActivity) getActivity()).getSupportActionBar().setTitle(R.string.settings_label_appearance);
}
@Override
public void onStop() {
super.onStop();
getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(
(SettingsActivity) getActivity()
);
}
}

View File

@ -0,0 +1,20 @@
package net.i2p.android.preferences;
import android.os.Bundle;
import net.i2p.android.router.R;
import net.i2p.android.router.SettingsActivity;
public class ExploratoryPoolPreferenceFragment extends I2PreferenceFragment {
@Override
public void onCreate(Bundle paramBundle) {
super.onCreate(paramBundle);
addPreferencesFromResource(R.xml.settings_expl_tunnels);
}
@Override
public void onResume() {
super.onResume();
((SettingsActivity) getActivity()).getSupportActionBar().setTitle(R.string.settings_label_exploratory_pool);
}
}

View File

@ -0,0 +1,108 @@
package net.i2p.android.preferences;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.CheckBoxPreference;
import android.preference.PreferenceCategory;
import android.preference.PreferenceManager;
import android.preference.PreferenceScreen;
import net.i2p.android.router.R;
import net.i2p.android.router.SettingsActivity;
import net.i2p.android.router.service.StatSummarizer;
import net.i2p.android.router.util.Util;
import net.i2p.router.RouterContext;
import net.i2p.stat.FrequencyStat;
import net.i2p.stat.Rate;
import net.i2p.stat.RateStat;
import net.i2p.stat.StatManager;
import java.util.Map;
import java.util.SortedSet;
public class GraphsPreferenceFragment extends I2PreferenceFragment {
public static final String GRAPH_PREFERENCES_SEEN = "graphPreferencesSeen";
@Override
public void onCreate(Bundle paramBundle) {
super.onCreate(paramBundle);
addPreferencesFromResource(R.xml.settings_graphs);
setupGraphSettings();
}
@Override
public void onResume() {
super.onResume();
((SettingsActivity) getActivity()).getSupportActionBar().setTitle(R.string.label_graphs);
}
private void setupGraphSettings() {
PreferenceScreen ps = getPreferenceScreen();
RouterContext ctx = Util.getRouterContext();
if (ctx == null) {
PreferenceCategory noRouter = new PreferenceCategory(getActivity());
noRouter.setTitle(R.string.router_not_running);
ps.addPreference(noRouter);
} else if (StatSummarizer.instance() == null) {
PreferenceCategory noStats = new PreferenceCategory(getActivity());
noStats.setTitle(R.string.stats_not_ready);
ps.addPreference(noStats);
} else {
StatManager mgr = ctx.statManager();
Map<String, SortedSet<String>> all = mgr.getStatsByGroup();
for (String group : all.keySet()) {
SortedSet<String> stats = all.get(group);
if (stats.size() == 0) continue;
PreferenceCategory groupPrefs = new PreferenceCategory(getActivity());
groupPrefs.setKey("stat.groups." + group);
groupPrefs.setTitle(group);
ps.addPreference(groupPrefs);
for (String stat : stats) {
String key;
String description;
boolean canBeGraphed = false;
boolean currentIsGraphed = false;
RateStat rs = mgr.getRate(stat);
if (rs != null) {
description = rs.getDescription();
long period = rs.getPeriods()[0]; // should be the minimum
key = stat + "." + period;
if (period <= 10*60*1000) {
Rate r = rs.getRate(period);
canBeGraphed = r != null;
if (canBeGraphed) {
currentIsGraphed = r.getSummaryListener() != null;
}
}
} else {
FrequencyStat fs = mgr.getFrequency(stat);
if (fs != null) {
key = stat;
description = fs.getDescription();
// FrequencyStats cannot be graphed, but can be logged.
// XXX: Should log settings be here as well, or in a
// separate settings menu?
} else {
Util.e("Stat does not exist?! [" + stat + "]");
continue;
}
}
CheckBoxPreference statPref = new CheckBoxPreference(getActivity());
statPref.setKey("stat.summaries." + key);
statPref.setTitle(stat);
statPref.setSummary(description);
statPref.setEnabled(canBeGraphed);
statPref.setChecked(currentIsGraphed);
groupPrefs.addPreference(statPref);
}
}
// The user has now seen the current (possibly default) configuration
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
if (!prefs.getBoolean(GRAPH_PREFERENCES_SEEN, false))
prefs.edit()
.putBoolean(GRAPH_PREFERENCES_SEEN, true)
.apply();
}
}
}

View File

@ -0,0 +1,72 @@
package net.i2p.android.preferences;
import android.support.v4.preference.PreferenceFragment;
import android.widget.Toast;
import net.i2p.I2PAppContext;
import net.i2p.android.router.R;
import net.i2p.android.router.util.Util;
import net.i2p.router.RouterContext;
import java.util.List;
import java.util.Properties;
import java.util.Set;
/**
* A PreferenceFragment that handles saving router settings.
*/
public class I2PreferenceFragment extends PreferenceFragment {
@Override
public void onPause() {
List<Properties> lProps = Util.getPropertiesFromPreferences(getActivity());
Properties props = lProps.get(0);
Properties propsToRemove = lProps.get(1);
Properties logSettings = lProps.get(2);
Set toRemove = propsToRemove.keySet();
boolean restartRequired = Util.checkAndCorrectRouterConfig(getActivity(), props, toRemove);
// Apply new config if we are running.
RouterContext rCtx = Util.getRouterContext();
if (rCtx != null) {
rCtx.router().saveConfig(props, toRemove);
// Merge in new log settings
saveLoggingChanges(rCtx, logSettings);
} else {
// Merge in new config settings, write the file.
Util.mergeResourceToFile(getActivity(),
Util.getFileDir(getActivity()),
"router.config", R.raw.router_config, props, toRemove);
// Merge in new log settings
saveLoggingChanges(I2PAppContext.getGlobalContext(), logSettings);
}
// Store the settings in Android
super.onPause();
if (restartRequired)
Toast.makeText(getActivity(), R.string.settings_router_restart_required, Toast.LENGTH_LONG).show();
}
private void saveLoggingChanges(I2PAppContext ctx, Properties logSettings) {
boolean shouldSave = false;
for (Object key : logSettings.keySet()) {
if ("logger.defaultLevel".equals(key)) {
String defaultLevel = (String) logSettings.get(key);
String oldDefault = ctx.logManager().getDefaultLimit();
if (!defaultLevel.equals(oldDefault)) {
shouldSave = true;
ctx.logManager().setDefaultLimit(defaultLevel);
}
}
}
if (shouldSave) {
ctx.logManager().saveConfig();
}
}
}

View File

@ -0,0 +1,54 @@
package net.i2p.android.preferences;
import android.os.Bundle;
import android.preference.PreferenceScreen;
import net.i2p.android.router.R;
import net.i2p.android.router.SettingsActivity;
import net.i2p.android.router.util.Util;
import net.i2p.router.RouterContext;
import net.i2p.util.LogManager;
public class LoggingPreferenceFragment extends I2PreferenceFragment {
@Override
public void onCreate(Bundle paramBundle) {
super.onCreate(paramBundle);
addPreferencesFromResource(R.xml.settings_logging);
setupLoggingSettings();
}
@Override
public void onResume() {
super.onResume();
((SettingsActivity) getActivity()).getSupportActionBar().setTitle(R.string.settings_label_logging);
}
private void setupLoggingSettings() {
PreferenceScreen ps = getPreferenceScreen();
RouterContext ctx = Util.getRouterContext();
if (ctx != null) {
LogManager mgr = ctx.logManager();
// Log level overrides
/*
StringBuilder buf = new StringBuilder(32*1024);
Properties limits = mgr.getLimits();
TreeSet<String> sortedLogs = new TreeSet<String>();
for (Iterator iter = limits.keySet().iterator(); iter.hasNext(); ) {
String prefix = (String)iter.next();
sortedLogs.add(prefix);
}
for (Iterator iter = sortedLogs.iterator(); iter.hasNext(); ) {
String prefix = (String)iter.next();
String level = limits.getProperty(prefix);
buf.append(prefix).append('=').append(level).append('\n');
}
*/
/* Don't show, there are no settings that require the router
} else {
PreferenceCategory noRouter = new PreferenceCategory(getActivity());
noRouter.setTitle(R.string.router_not_running);
ps.addPreference(noRouter);
*/
}
}
}

View File

@ -0,0 +1,20 @@
package net.i2p.android.preferences;
import android.os.Bundle;
import net.i2p.android.router.R;
import net.i2p.android.router.SettingsActivity;
public class NetworkPreferenceFragment extends I2PreferenceFragment {
@Override
public void onCreate(Bundle paramBundle) {
super.onCreate(paramBundle);
addPreferencesFromResource(R.xml.settings_net);
}
@Override
public void onResume() {
super.onResume();
((SettingsActivity) getActivity()).getSupportActionBar().setTitle(R.string.settings_label_bandwidth_net);
}
}

View File

@ -0,0 +1,122 @@
package net.i2p.android.preferences;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.CheckBoxPreference;
import android.preference.Preference;
import android.preference.PreferenceManager;
import android.preference.PreferenceScreen;
import android.widget.Toast;
import net.i2p.android.router.R;
import net.i2p.android.router.SettingsActivity;
import net.i2p.android.router.util.PortPreference;
import net.i2p.android.router.util.Util;
import net.i2p.router.RouterContext;
public class TransportsPreferenceFragment extends I2PreferenceFragment {
@Override
public void onCreate(Bundle paramBundle) {
super.onCreate(paramBundle);
// Load any properties that the router might have changed on us.
loadProperties();
addPreferencesFromResource(R.xml.settings_transports);
setupTransportSettings();
}
@Override
public void onResume() {
super.onResume();
((SettingsActivity) getActivity()).getSupportActionBar().setTitle(R.string.settings_label_transports);
}
private void loadProperties() {
Context context= getActivity();
RouterContext ctx = Util.getRouterContext();
if (ctx != null) {
final String udpPortKey = context.getString(R.string.PROP_UDP_INTERNAL_PORT);
final String ntcpPortKey = context.getString(R.string.PROP_I2NP_NTCP_PORT);
final String ntcpAutoPortKey = context.getString(R.string.PROP_I2NP_NTCP_AUTO_PORT);
int udpPort = ctx.getProperty(udpPortKey, -1);
int ntcpPort = ctx.getProperty(ntcpPortKey, -1);
boolean ntcpAutoPort = ctx.getBooleanPropertyDefaultTrue(ntcpAutoPortKey);
if (ntcpPort < 0 && ntcpAutoPort)
ntcpPort = udpPort;
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
if (prefs.getInt(udpPortKey, -1) != udpPort ||
prefs.getInt(ntcpPortKey, -1) != ntcpPort) {
SharedPreferences.Editor editor = prefs.edit();
editor.putInt(udpPortKey, udpPort);
editor.putInt(ntcpPortKey, ntcpPort);
// commit() instead of apply() because this needs to happen
// before AdvancedPreferenceFragment loads its Preferences.
editor.commit();
}
}
}
private void setupTransportSettings() {
final Context context= getActivity();
PreferenceScreen ps = getPreferenceScreen();
final String udpEnableKey = context.getString(R.string.PROP_ENABLE_UDP);
final String ntcpEnableKey = context.getString(R.string.PROP_ENABLE_NTCP);
final String udpPortKey = context.getString(R.string.PROP_UDP_INTERNAL_PORT);
final String ntcpPortKey = context.getString(R.string.PROP_I2NP_NTCP_PORT);
final String ntcpAutoPortKey = context.getString(R.string.PROP_I2NP_NTCP_AUTO_PORT);
final CheckBoxPreference udpEnable = (CheckBoxPreference) ps.findPreference(udpEnableKey);
final CheckBoxPreference ntcpEnable = (CheckBoxPreference) ps.findPreference(ntcpEnableKey);
final PortPreference udpPort = (PortPreference) ps.findPreference(udpPortKey);
final PortPreference ntcpPort = (PortPreference) ps.findPreference(ntcpPortKey);
final CheckBoxPreference ntcpAutoPort = (CheckBoxPreference) ps.findPreference(ntcpAutoPortKey);
udpEnable.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
final Boolean checked = (Boolean) newValue;
if (checked || ntcpEnable.isChecked())
return true;
else {
Toast.makeText(context, R.string.settings_need_transport_enabled, Toast.LENGTH_LONG).show();
return false;
}
}
});
ntcpEnable.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
final Boolean checked = (Boolean) newValue;
if (checked || udpEnable.isChecked())
return true;
else {
Toast.makeText(context, R.string.settings_need_transport_enabled, Toast.LENGTH_LONG).show();
return false;
}
}
});
udpPort.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
if (ntcpAutoPort.isChecked())
ntcpPort.setText((String) newValue);
return true;
}
});
ntcpAutoPort.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
final Boolean checked = (Boolean) newValue;
if (checked)
ntcpPort.setText(udpPort.getText());
return true;
}
});
}
}

View File

@ -0,0 +1,128 @@
package net.i2p.android.router;
import android.content.Intent;
import android.os.Bundle;
import android.preference.PreferenceManager;
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;
import net.i2p.android.ext.floatingactionbutton.FloatingActionsMenu;
import net.i2p.android.router.dialog.AboutDialog;
import net.i2p.android.router.dialog.TextResourceDialog;
import net.i2p.android.router.log.LogActivity;
import net.i2p.android.router.netdb.NetDbActivity;
import net.i2p.android.router.stats.PeersActivity;
import net.i2p.android.router.stats.RateGraphActivity;
import net.i2p.android.router.util.Util;
public class ConsoleContainer extends Fragment {
MainFragment mMainFragment = null;
FloatingActionsMenu mConsoleMenu;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.container_console, container, false);
// Start with the home view
if (savedInstanceState == null && getChildFragmentManager().findFragmentById(R.id.main_fragment) == null) {
mMainFragment = new MainFragment();
mMainFragment.setArguments(getActivity().getIntent().getExtras());
getChildFragmentManager().beginTransaction()
.add(R.id.main_fragment, mMainFragment).commit();
}
mConsoleMenu = (FloatingActionsMenu) v.findViewById(R.id.console_action_menu);
mConsoleMenu.findViewById(R.id.action_news).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent news = new Intent(getActivity(), NewsActivity.class);
startActivity(news);
}
});
mConsoleMenu.findViewById(R.id.action_logs).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent log = new Intent(getActivity(), LogActivity.class);
startActivity(log);
}
});
mConsoleMenu.findViewById(R.id.action_graphs).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent graphs = new Intent(getActivity(), RateGraphActivity.class);
startActivity(graphs);
}
});
mConsoleMenu.findViewById(R.id.action_peers).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent peers = new Intent(getActivity(), PeersActivity.class);
startActivity(peers);
}
});
mConsoleMenu.findViewById(R.id.action_netdb).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent netdb = new Intent(getActivity(), NetDbActivity.class);
startActivity(netdb);
}
});
setMenuVisibility();
return v;
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.activity_main_actions, menu);
}
@Override
public void onPrepareOptionsMenu(Menu menu) {
setMenuVisibility();
}
private void setMenuVisibility() {
boolean advanced = PreferenceManager.getDefaultSharedPreferences(getActivity()).getBoolean(
"i2pandroid.main.showStats", false);
boolean routerRunning = Util.getRouterContext() != null;
mConsoleMenu.findViewById(R.id.action_logs).setVisibility(routerRunning ? View.VISIBLE : View.GONE);
mConsoleMenu.findViewById(R.id.action_graphs).setVisibility(routerRunning ? View.VISIBLE : View.GONE);
mConsoleMenu.findViewById(R.id.action_peers).setVisibility(advanced && routerRunning ? View.VISIBLE : View.GONE);
mConsoleMenu.findViewById(R.id.action_netdb).setVisibility(advanced && routerRunning ? View.VISIBLE : View.GONE);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_about:
AboutDialog dialog = new AboutDialog();
dialog.show(getFragmentManager(), "about");
return true;
case R.id.menu_help_release_notes:
TextResourceDialog rDdialog = new TextResourceDialog();
Bundle args = new Bundle();
args.putString(TextResourceDialog.TEXT_DIALOG_TITLE,
getResources().getString(R.string.label_release_notes));
args.putInt(TextResourceDialog.TEXT_RESOURCE_ID, R.raw.releasenotes_txt);
rDdialog.setArguments(args);
rDdialog.show(getFragmentManager(), "release_notes");
return true;
default:
return super.onOptionsItemSelected(item);
}
}
}

View File

@ -0,0 +1,5 @@
package net.i2p.android.router;
public interface I2PConstants {
String ANDROID_PREF_PREFIX = "i2pandroid.";
}

View File

@ -0,0 +1,94 @@
package net.i2p.android.router;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import net.i2p.android.router.util.Util;
import net.i2p.router.CommSystemFacade;
import net.i2p.router.NetworkDatabaseFacade;
import net.i2p.router.Router;
import net.i2p.router.RouterContext;
import net.i2p.router.TunnelManagerFacade;
import net.i2p.router.peermanager.ProfileOrganizer;
import net.i2p.router.transport.FIFOBandwidthLimiter;
import net.i2p.stat.StatManager;
public class I2PFragmentBase extends Fragment {
private boolean mOnActivityCreated;
public static final String PREF_INSTALLED_VERSION = "app.version";
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mOnActivityCreated = true;
if (getRouterContext() != null)
onRouterConnectionReady();
else
onRouterConnectionNotReady();
}
public void onRouterBind() {
if (mOnActivityCreated)
onRouterConnectionReady();
}
/** callback from I2PFragmentBase, override as necessary */
public void onRouterConnectionReady() {}
/** callback from I2PFragmentBase, override as necessary */
public void onRouterConnectionNotReady() {}
protected RouterContext getRouterContext() {
return Util.getRouterContext();
}
protected Router getRouter() {
RouterContext ctx = getRouterContext();
if (ctx == null)
return null;
return ctx.router();
}
protected NetworkDatabaseFacade getNetDb() {
RouterContext ctx = getRouterContext();
if (ctx == null)
return null;
return ctx.netDb();
}
protected ProfileOrganizer getProfileOrganizer() {
RouterContext ctx = getRouterContext();
if (ctx == null)
return null;
return ctx.profileOrganizer();
}
protected TunnelManagerFacade getTunnelManager() {
RouterContext ctx = getRouterContext();
if (ctx == null)
return null;
return ctx.tunnelManager();
}
protected CommSystemFacade getCommSystem() {
RouterContext ctx = getRouterContext();
if (ctx == null)
return null;
return ctx.commSystem();
}
protected FIFOBandwidthLimiter getBandwidthLimiter() {
RouterContext ctx = getRouterContext();
if (ctx == null)
return null;
return ctx.bandwidthLimiter();
}
protected StatManager getStatManager() {
RouterContext ctx = getRouterContext();
if (ctx == null)
return null;
return ctx.statManager();
}
}

View File

@ -0,0 +1,24 @@
package net.i2p.android.router;
import android.os.Bundle;
import android.support.v7.widget.Toolbar;
import net.i2p.android.I2PActivityBase;
public class LicenseActivity extends I2PActivityBase {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_onepane);
Toolbar toolbar = (Toolbar) findViewById(R.id.main_toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
// Start with the base view
if (savedInstanceState == null) {
LicenseFragment f = new LicenseFragment();
f.setArguments(getIntent().getExtras());
getSupportFragmentManager().beginTransaction()
.add(R.id.main_fragment, f).commit();
}
}
}

View File

@ -0,0 +1,43 @@
package net.i2p.android.router;
import android.os.Bundle;
import android.support.v4.app.ListFragment;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import net.i2p.android.router.dialog.TextResourceDialog;
public class LicenseFragment extends ListFragment {
private static final String[] names = {
"Android Application License", "Apache 2.0",
"Router License Overview", "Blockfile", "Crypto Filters", "ElGamal / DSA",
"GPLv2", "LGPLv2.1", "GPLv3", "LGPLv3", "FatCowIcons",
"Ministreaming",
"InstallCert", "SHA-256", "SNTP", "Addressbook"};
private static final int[] files = {
R.raw.license_app_txt, R.raw.license_apache20_txt,
R.raw.licenses_txt, R.raw.license_blockfile_txt, R.raw.license_bsd_txt, R.raw.license_elgamaldsa_txt,
R.raw.license_gplv2_txt, R.raw.license_lgplv2_1_txt, R.raw.license_gplv3_txt, R.raw.license_lgplv3_txt,
R.raw.license_fatcowicons_txt, R.raw.license_bsd_txt,
R.raw.license_installcert_txt, R.raw.license_sha256_txt, R.raw.license_sntp_txt, R.raw.license_addressbook_txt};
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setListAdapter(new ArrayAdapter<>(getActivity(), android.R.layout.simple_list_item_1, names));
}
@Override
public void onListItemClick(ListView parent, View view, int pos, long id) {
TextResourceDialog dialog = new TextResourceDialog();
Bundle args = new Bundle();
args.putString(TextResourceDialog.TEXT_DIALOG_TITLE, names[pos]);
args.putInt(TextResourceDialog.TEXT_RESOURCE_ID, files[pos]);
dialog.setArguments(args);
dialog.show(getActivity().getSupportFragmentManager(), "license");
}
}

View File

@ -0,0 +1,657 @@
package net.i2p.android.router;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Typeface;
import android.os.Bundle;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v7.app.AlertDialog;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ScrollView;
import android.widget.TableLayout;
import android.widget.TableRow;
import android.widget.TextView;
import android.widget.ToggleButton;
import net.i2p.android.I2PActivityBase;
import net.i2p.android.help.BrowserConfigActivity;
import net.i2p.android.router.dialog.FirstStartDialog;
import net.i2p.android.router.service.RouterService;
import net.i2p.android.router.service.State;
import net.i2p.android.router.util.Connectivity;
import net.i2p.android.router.util.LongToggleButton;
import net.i2p.android.router.util.Util;
import net.i2p.data.DataHelper;
import net.i2p.data.Destination;
import net.i2p.data.Hash;
import net.i2p.data.LeaseSet;
import net.i2p.router.RouterContext;
import net.i2p.router.TunnelPoolSettings;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class MainFragment extends I2PFragmentBase {
private Handler _handler;
private Runnable _updater;
private Runnable _oneShotUpdate;
private String _savedStatus;
private ImageView mConsoleLights;
private LongToggleButton mOnOffButton;
private LinearLayout vGracefulButtons;
private ScrollView mScrollView;
private View vStatusContainer;
private ImageView vNetStatusLevel;
private TextView vNetStatusText;
private View vNonNetStatus;
private TextView vUptime;
private TextView vActive;
private TextView vKnown;
private TableLayout vTunnels;
private LinearLayout vAdvStatus;
private TextView vAdvStatusText;
private static final String PREF_CONFIGURE_BROWSER = "app.dialog.configureBrowser";
private static final String PREF_FIRST_START = "app.router.firstStart";
private static final String PREF_SHOW_STATS = "i2pandroid.main.showStats";
protected static final String PROP_NEW_INSTALL = "i2p.newInstall";
protected static final String PROP_NEW_VERSION = "i2p.newVersion";
RouterControlListener mCallback;
// Container Activity must implement this interface
public interface RouterControlListener {
boolean shouldShowOnOff();
boolean shouldBeOn();
void onStartRouterClicked();
boolean onStopRouterClicked();
/**
* @since 0.9.19
*/
boolean isGracefulShutdownInProgress();
/**
* @since 0.9.19
*/
boolean onGracefulShutdownClicked();
/**
* @since 0.9.19
*/
boolean onCancelGracefulShutdownClicked();
}
@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 {
mCallback = (RouterControlListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement RouterControlListener");
}
}
/**
* Called when the fragment is first created.
*/
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Init stuff here so settings work.
if (savedInstanceState != null) {
lastRouterState = savedInstanceState.getParcelable("lastState");
String saved = savedInstanceState.getString("status");
if (saved != null) {
_savedStatus = saved;
}
}
_handler = new Handler();
_updater = new Updater();
_oneShotUpdate = new OneShotUpdate();
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_main, container, false);
mConsoleLights = (ImageView) v.findViewById(R.id.console_lights);
mOnOffButton = (LongToggleButton) v.findViewById(R.id.router_onoff_button);
vGracefulButtons = (LinearLayout) v.findViewById(R.id.router_graceful_buttons);
mScrollView = (ScrollView) v.findViewById(R.id.main_scrollview);
vStatusContainer = v.findViewById(R.id.status_container);
vNetStatusLevel = (ImageView) v.findViewById(R.id.console_net_status_level);
vNetStatusText = (TextView) v.findViewById(R.id.console_net_status_text);
vNonNetStatus = v.findViewById(R.id.console_non_net_status_container);
vUptime = (TextView) v.findViewById(R.id.console_uptime);
vActive = (TextView) v.findViewById(R.id.console_active);
vKnown = (TextView) v.findViewById(R.id.console_known);
vTunnels = (TableLayout) v.findViewById(R.id.main_tunnels);
vAdvStatus = (LinearLayout) v.findViewById(R.id.console_advanced_status);
vAdvStatusText = (TextView) v.findViewById(R.id.console_advanced_status_text);
updateState(lastRouterState);
mOnOffButton.setOnLongClickListener(new View.OnLongClickListener() {
public boolean onLongClick(View view) {
boolean on = ((ToggleButton) view).isChecked();
if (on) {
mCallback.onStartRouterClicked();
updateOneShot();
checkFirstStart();
} else if (mCallback.onGracefulShutdownClicked())
updateOneShot();
return true;
}
});
Button gb = (Button) v.findViewById(R.id.button_shutdown_now);
gb.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View view) {
if (mCallback.isGracefulShutdownInProgress())
if (mCallback.onStopRouterClicked())
updateOneShot();
return true;
}
});
gb = (Button) v.findViewById(R.id.button_cancel_graceful);
gb.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View view) {
if (mCallback.isGracefulShutdownInProgress())
if (mCallback.onCancelGracefulShutdownClicked())
updateOneShot();
return true;
}
});
return v;
}
@Override
public void onStart() {
super.onStart();
_handler.removeCallbacks(_updater);
_handler.removeCallbacks(_oneShotUpdate);
if (_savedStatus != null) {
TextView tv = (TextView) getActivity().findViewById(R.id.console_advanced_status_text);
tv.setText(_savedStatus);
}
checkDialog();
_handler.postDelayed(_updater, 100);
LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(getActivity());
IntentFilter filter = new IntentFilter();
filter.addAction(RouterService.LOCAL_BROADCAST_STATE_NOTIFICATION);
filter.addAction(RouterService.LOCAL_BROADCAST_STATE_CHANGED);
lbm.registerReceiver(onStateChange, filter);
lbm.sendBroadcast(new Intent(RouterService.LOCAL_BROADCAST_REQUEST_STATE));
}
private State lastRouterState;
private BroadcastReceiver onStateChange = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
State state = intent.getParcelableExtra(RouterService.LOCAL_BROADCAST_EXTRA_STATE);
if (lastRouterState == null || lastRouterState != state) {
updateState(state);
// If we have stopped, clear the status info immediately
if (Util.isStopped(state)) {
updateOneShot();
}
lastRouterState = state;
}
}
};
@Override
public void onStop() {
super.onStop();
_handler.removeCallbacks(_updater);
_handler.removeCallbacks(_oneShotUpdate);
LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(onStateChange);
}
@Override
public void onResume() {
super.onResume();
updateOneShot();
}
@Override
public void onSaveInstanceState(Bundle outState) {
if (lastRouterState != null)
outState.putParcelable("lastState", lastRouterState);
if (_savedStatus != null)
outState.putString("status", _savedStatus);
super.onSaveInstanceState(outState);
}
private void updateOneShot() {
_handler.postDelayed(_oneShotUpdate, 10);
}
private class OneShotUpdate implements Runnable {
public void run() {
updateVisibility();
try {
updateStatus();
} catch (NullPointerException npe) {
// RouterContext wasn't quite ready
Util.w("Status was updated before RouterContext was ready", npe);
}
}
}
private class Updater implements Runnable {
private int counter;
private final int delay = 1000;
private final int toloop = delay / 500;
public void run() {
updateVisibility();
if (counter++ % toloop == 0) {
try {
updateStatus();
} catch (NullPointerException npe) {
// RouterContext wasn't quite ready
Util.w("Status was updated before RouterContext was ready", npe);
}
}
//_handler.postDelayed(this, 2500);
_handler.postDelayed(this, delay);
}
}
private void updateVisibility() {
boolean showOnOff = mCallback.shouldShowOnOff();
mOnOffButton.setVisibility(showOnOff ? View.VISIBLE : View.GONE);
boolean isOn = mCallback.shouldBeOn();
mOnOffButton.setChecked(isOn);
boolean isGraceful = mCallback.isGracefulShutdownInProgress();
vGracefulButtons.setVisibility(isGraceful ? View.VISIBLE : View.GONE);
if (isOn && isGraceful) {
RouterContext ctx = getRouterContext();
if (ctx != null) {
TextView tv = (TextView) vGracefulButtons.findViewById(R.id.router_graceful_status);
long ms = ctx.router().getShutdownTimeRemaining();
if (ms > 1000) {
tv.setText(getActivity().getResources().getString(R.string.button_router_graceful,
DataHelper.formatDuration(ms)));
} else {
tv.setText(getActivity().getString(R.string.notification_status_stopping));
}
}
}
}
public void updateState(State newState) {
if (newState == State.INIT ||
newState == State.STOPPED ||
newState == State.MANUAL_STOPPED ||
newState == State.MANUAL_QUITTED ||
newState == State.NETWORK_STOPPED) {
mConsoleLights.setImageResource(R.drawable.routerlogo_0);
} else if (newState == State.STARTING ||
//newState == State.GRACEFUL_SHUTDOWN || // Don't change lights for graceful
newState == State.STOPPING ||
newState == State.MANUAL_STOPPING ||
newState == State.MANUAL_QUITTING ||
newState == State.NETWORK_STOPPING) {
mConsoleLights.setImageResource(R.drawable.routerlogo_1);
} else if (newState == State.RUNNING) {
mConsoleLights.setImageResource(R.drawable.routerlogo_2);
} else if (newState == State.ACTIVE) {
mConsoleLights.setImageResource(R.drawable.routerlogo_3);
} else if (newState == State.WAITING) {
mConsoleLights.setImageResource(R.drawable.routerlogo_4);
} // Ignore unknown states.
}
private void updateStatus() {
RouterContext ctx = getRouterContext();
if (!Connectivity.isConnected(getActivity())) {
// Manually set state, RouterService won't be running
updateState(State.WAITING);
vNetStatusText.setText(R.string.no_internet);
vStatusContainer.setVisibility(View.VISIBLE);
vNonNetStatus.setVisibility(View.GONE);
} else if (lastRouterState != null &&
!Util.isStopping(lastRouterState) &&
!Util.isStopped(lastRouterState) &&
ctx != null) {
Util.NetStatus netStatus = Util.getNetStatus(getActivity(), ctx);
switch (netStatus.level) {
case ERROR:
vNetStatusLevel.setImageDrawable(getResources().getDrawable(R.drawable.ic_error_red_24dp));
vNetStatusLevel.setVisibility(View.VISIBLE);
break;
case WARN:
vNetStatusLevel.setImageDrawable(getResources().getDrawable(R.drawable.ic_warning_amber_24dp));
vNetStatusLevel.setVisibility(View.VISIBLE);
break;
case INFO:
default:
vNetStatusLevel.setVisibility(View.GONE);
}
vNetStatusText.setText(getString(R.string.settings_label_network) + ": " + netStatus.status);
String uptime = DataHelper.formatDuration(ctx.router().getUptime());
int active = ctx.commSystem().countActivePeers();
int known = Math.max(ctx.netDb().getKnownRouters() - 1, 0);
vUptime.setText("" + uptime);
vActive.setText("" + active);
vKnown.setText("" + known);
// Load running tunnels
loadDestinations(ctx);
if (PreferenceManager.getDefaultSharedPreferences(getActivity()).getBoolean(PREF_SHOW_STATS, false)) {
int inEx = ctx.tunnelManager().getFreeTunnelCount();
int outEx = ctx.tunnelManager().getOutboundTunnelCount();
int inCl = ctx.tunnelManager().getInboundClientTunnelCount();
int outCl = ctx.tunnelManager().getOutboundClientTunnelCount();
int part = ctx.tunnelManager().getParticipatingCount();
double dLag = ctx.statManager().getRate("jobQueue.jobLag").getRate(60000).getAverageValue();
String jobLag = DataHelper.formatDuration((long) dLag);
String msgDelay = DataHelper.formatDuration(ctx.throttle().getMessageDelay());
String tunnelStatus = ctx.throttle().getTunnelStatus();
//ctx.commSystem().getReachabilityStatus();
String status =
"Exploratory Tunnels in/out: " + inEx + " / " + outEx
+ "\nClient Tunnels in/out: " + inCl + " / " + outCl;
// Need to see if we have the participation option set to on.
// I thought there was a router method for that? I guess not! WHY NOT?
// It would be easier if we had a number to test status.
String participate = "\nParticipation: " + tunnelStatus + " (" + part + ")";
String details =
"\nMemory: " + DataHelper.formatSize(Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory())
+ "B / " + DataHelper.formatSize(Runtime.getRuntime().maxMemory()) + 'B'
+ "\nJob Lag: " + jobLag
+ "\nMsg Delay: " + msgDelay;
_savedStatus = status + participate + details;
vAdvStatusText.setText(_savedStatus);
vAdvStatus.setVisibility(View.VISIBLE);
} else {
vAdvStatus.setVisibility(View.GONE);
}
vStatusContainer.setVisibility(View.VISIBLE);
vNonNetStatus.setVisibility(View.VISIBLE);
// Usage stats in bottom toolbar
double inBw = ctx.bandwidthLimiter().getReceiveBps();
double outBw = ctx.bandwidthLimiter().getSendBps();
double inData = ctx.bandwidthLimiter().getTotalAllocatedInboundBytes();
double outData = ctx.bandwidthLimiter().getTotalAllocatedOutboundBytes();
((TextView) getActivity().findViewById(R.id.console_download_stats)).setText(
Util.formatSize(inBw) + "Bps / " + Util.formatSize(inData) + "B");
((TextView) getActivity().findViewById(R.id.console_upload_stats)).setText(
Util.formatSize(outBw) + "Bps / " + Util.formatSize(outData) + "B");
getActivity().findViewById(R.id.console_usage_stats).setVisibility(View.VISIBLE);
} else {
// network but no router context
vStatusContainer.setVisibility(View.GONE);
getActivity().findViewById(R.id.console_usage_stats).setVisibility(View.INVISIBLE);
/**
* **
* RouterService svc = _routerService; String status = "connected? "
* + Util.isConnected(this) + "\nMemory: " +
* DataHelper.formatSize(Runtime.getRuntime().totalMemory() -
* Runtime.getRuntime().freeMemory()) + "B / " +
* DataHelper.formatSize(Runtime.getRuntime().maxMemory()) + 'B' +
* "\nhave ctx? " + (ctx != null) + "\nhave svc? " + (svc != null) +
* "\nis bound? " + _isBound + "\nsvc state: " + (svc == null ?
* "null" : svc.getState()) + "\ncan start? " + (svc == null ?
* "null" : svc.canManualStart()) + "\ncan stop? " + (svc == null ?
* "null" : svc.canManualStop()); tv.setText(status);
* tv.setVisibility(View.VISIBLE);
***
*/
}
}
/**
* Based on net.i2p.router.web.SummaryHelper.getDestinations()
*
* @param ctx The RouterContext
*/
private void loadDestinations(RouterContext ctx) {
vTunnels.removeAllViews();
List<Destination> clients = null;
if (ctx.clientManager() != null)
clients = new ArrayList<Destination>(ctx.clientManager().listClients());
if (clients != null && !clients.isEmpty()) {
Collections.sort(clients, new AlphaComparator(ctx));
for (Destination client : clients) {
String name = getName(ctx, client);
Hash h = client.calculateHash();
TableRow dest = new TableRow(getActivity());
dest.setPadding(16, 4, 0, 4);
// Client or server
TextView type = new TextView(getActivity());
type.setTextColor(getResources().getColor(android.R.color.primary_text_light));
type.setTypeface(Typeface.DEFAULT_BOLD);
type.setGravity(Gravity.CENTER);
if (ctx.clientManager().shouldPublishLeaseSet(h))
type.setText(R.string.char_server_tunnel);
else
type.setText(R.string.char_client_tunnel);
dest.addView(type);
// Name
TextView destName = new TextView(getActivity());
destName.setPadding(16, 0, 0, 0);
destName.setGravity(Gravity.CENTER_VERTICAL);
destName.setText(name);
dest.addView(destName);
// Status
LeaseSet ls = ctx.netDb().lookupLeaseSetLocally(h);
if (ls != null && ctx.tunnelManager().getOutboundClientTunnelCount(h) > 0) {
long timeToExpire = ls.getEarliestLeaseDate() - ctx.clock().now();
if (timeToExpire < 0) {
// red or yellow light
type.setBackgroundResource(R.drawable.tunnel_yellow);
} else {
// green light
type.setBackgroundResource(R.drawable.tunnel_green);
}
} else {
// yellow light
type.setBackgroundResource(R.drawable.tunnel_yellow);
}
vTunnels.addView(dest);
}
} else {
TableRow empty = new TableRow(getActivity());
TextView emptyText = new TextView(getActivity());
emptyText.setText(R.string.no_tunnels_running);
empty.addView(emptyText);
vTunnels.addView(empty);
}
}
private static final String SHARED_CLIENTS = "shared clients";
/**
* compare translated nicknames - put "shared clients" first in the sort
*/
private class AlphaComparator implements Comparator<Destination> {
private String xsc;
private RouterContext _ctx;
public AlphaComparator(RouterContext ctx) {
_ctx = ctx;
xsc = _(ctx, SHARED_CLIENTS);
}
public int compare(Destination lhs, Destination rhs) {
String lname = getName(_ctx, lhs);
String rname = getName(_ctx, rhs);
if (lname.equals(xsc))
return -1;
if (rname.equals(xsc))
return 1;
return Collator.getInstance().compare(lname, rname);
}
}
/**
* translate here so collation works above
*/
private String getName(RouterContext ctx, Destination d) {
TunnelPoolSettings in = ctx.tunnelManager().getInboundSettings(d.calculateHash());
String name = (in != null ? in.getDestinationNickname() : null);
if (name == null) {
TunnelPoolSettings out = ctx.tunnelManager().getOutboundSettings(d.calculateHash());
name = (out != null ? out.getDestinationNickname() : null);
}
if (name == null)
name = d.calculateHash().toBase64().substring(0, 6);
else
name = _(ctx, name);
return name;
}
private String _(RouterContext ctx, String s) {
if (SHARED_CLIENTS.equals(s))
return getString(R.string.shared_clients);
else
return s;
}
private void checkDialog() {
final I2PActivityBase ab = (I2PActivityBase) getActivity();
String language = PreferenceManager.getDefaultSharedPreferences(ab).getString(
getString(R.string.PREF_LANGUAGE), null
);
if (language == null) {
AlertDialog.Builder b = new AlertDialog.Builder(getActivity());
b.setTitle(R.string.choose_language)
.setItems(R.array.language_names, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// Save the language choice
String language = getResources().getStringArray(R.array.languages)[which];
PreferenceManager.getDefaultSharedPreferences(getActivity())
.edit()
.putString(getString(R.string.PREF_LANGUAGE), language)
.commit();
// Close the dialog
dialog.dismiss();
// Broadcast the change to RouterService just in case the router is running
Intent intent = new Intent(RouterService.LOCAL_BROADCAST_LOCALE_CHANGED);
LocalBroadcastManager.getInstance(getActivity()).sendBroadcast(intent);
// Update the parent
ab.notifyLocaleChanged();
// Run checkDialog() again to show the next dialog
// (if the change doesn't restart the Activity)
checkDialog();
}
})
.setCancelable(false)
.show();
} else if (ab.getPref(PREF_CONFIGURE_BROWSER, true)) {
AlertDialog.Builder b = new AlertDialog.Builder(getActivity());
b.setTitle(R.string.configure_browser_title)
.setMessage(R.string.configure_browser_for_i2p)
.setCancelable(false)
.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int i) {
dialog.dismiss();
ab.setPref(PREF_CONFIGURE_BROWSER, false);
Intent hi = new Intent(getActivity(), BrowserConfigActivity.class);
startActivity(hi);
}
})
.setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int i) {
dialog.cancel();
ab.setPref(PREF_CONFIGURE_BROWSER, false);
}
})
.show();
}
/*VersionDialog dialog = new VersionDialog();
String oldVersion = ((I2PActivityBase) getActivity()).getPref(PREF_INSTALLED_VERSION, "??");
if(oldVersion.equals("??")) {
// TODO Don't show this dialog until it is reworked
Bundle args = new Bundle();
args.putInt(VersionDialog.DIALOG_TYPE, VersionDialog.DIALOG_NEW_INSTALL);
dialog.setArguments(args);
dialog.show(getActivity().getSupportFragmentManager(), "newinstall");
} else {
// TODO Don't show dialog on new version until we have something new to tell them
String currentVersion = Util.getOurVersion(getActivity());
if(!oldVersion.equals(currentVersion)) {
Bundle args = new Bundle();
args.putInt(VersionDialog.DIALOG_TYPE, VersionDialog.DIALOG_NEW_VERSION);
dialog.setArguments(args);
dialog.show(getActivity().getSupportFragmentManager(), "newversion");
}
}*/
}
private void checkFirstStart() {
I2PActivityBase ab = (I2PActivityBase) getActivity();
boolean firstStart = ab.getPref(PREF_FIRST_START, true);
if (firstStart) {
FirstStartDialog dialog = new FirstStartDialog();
dialog.show(getActivity().getSupportFragmentManager(), "firststart");
ab.setPref(PREF_FIRST_START, false);
}
}
}

View File

@ -0,0 +1,26 @@
package net.i2p.android.router;
import android.os.Bundle;
import android.support.v7.widget.Toolbar;
import net.i2p.android.I2PActivityBase;
public class NewsActivity extends I2PActivityBase {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_onepane);
Toolbar toolbar = (Toolbar) findViewById(R.id.main_toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
// Start with the base view
if (savedInstanceState == null) {
NewsFragment f = new NewsFragment();
f.setArguments(getIntent().getExtras());
getSupportFragmentManager().beginTransaction()
.add(R.id.main_fragment, f).commit();
}
}
}

View File

@ -0,0 +1,95 @@
package net.i2p.android.router;
import android.content.res.Resources;
import android.os.Bundle;
import android.text.Html;
import android.text.SpannableStringBuilder;
import android.text.method.LinkMovementMethod;
import android.text.style.URLSpan;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import net.i2p.android.apps.NewsFetcher;
import net.i2p.android.router.util.Util;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
public class NewsFragment extends I2PFragmentBase {
private long _lastChanged;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_news, container, false);
}
@Override
public void onResume() {
super.onResume();
NewsFetcher nf = NewsFetcher.getInstance();
if (nf != null) {
// Always update the status
TextView tv = (TextView) getActivity().findViewById(R.id.news_status);
tv.setText(nf.status().replace("&nbsp;", " "));
tv.setVisibility(View.VISIBLE);
}
// Only update the content if we need to
File newsFile = new File(Util.getFileDir(getActivity()), "docs/news.xml");
boolean newsExists = newsFile.exists();
if (_lastChanged > 0 && ((!newsExists) || newsFile.lastModified() < _lastChanged))
return;
_lastChanged = System.currentTimeMillis();
InputStream in = null;
ByteArrayOutputStream out = new ByteArrayOutputStream(2048);
byte buf[] = new byte[1024];
try {
if (newsExists) {
in = new FileInputStream(newsFile);
} else {
in = getResources().openRawResource(R.raw.initialnews_html);
}
int read;
while ( (read = in.read(buf)) != -1)
out.write(buf, 0, read);
} catch (IOException ioe) {
System.err.println("news error " + ioe);
} catch (Resources.NotFoundException nfe) {
} finally {
if (in != null) try { in.close(); } catch (IOException ioe) {}
}
String news = "";
try {
news = out.toString("UTF-8");
} catch (UnsupportedEncodingException uee) {
}
// Get SpannableStringBuilder object from HTML code
CharSequence sequence = Html.fromHtml(news);
SpannableStringBuilder strBuilder = new SpannableStringBuilder(sequence);
// Get an array of URLSpan from SpannableStringBuilder object
URLSpan[] urlSpans = strBuilder.getSpans(0, strBuilder.length(), URLSpan.class);
// Remove URLSpans with relative paths, which can't be clicked on
for (final URLSpan span : urlSpans) {
if (span.getURL().startsWith("/"))
strBuilder.removeSpan(span);
}
TextView tv = (TextView) getActivity().findViewById(R.id.news_content);
tv.setText(strBuilder);
tv.setMovementMethod(LinkMovementMethod.getInstance());
}
}

View File

@ -0,0 +1,154 @@
package net.i2p.android.router;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.Preference;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v4.preference.PreferenceFragment;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import net.i2p.android.I2PActivity;
import net.i2p.android.preferences.AdvancedPreferenceFragment;
import net.i2p.android.preferences.AppearancePreferenceFragment;
import net.i2p.android.preferences.GraphsPreferenceFragment;
import net.i2p.android.preferences.LoggingPreferenceFragment;
import net.i2p.android.preferences.NetworkPreferenceFragment;
import net.i2p.android.router.addressbook.AddressbookSettingsActivity;
import net.i2p.android.router.service.RouterService;
import net.i2p.android.util.LocaleManager;
public class SettingsActivity extends AppCompatActivity implements
SharedPreferences.OnSharedPreferenceChangeListener {
public static final String PREFERENCE_CATEGORY = "preference_category";
public static final String PREFERENCE_CATEGORY_NETWORK = "preference_category_network";
public static final String PREFERENCE_CATEGORY_GRAPHS = "preference_category_graphs";
public static final String PREFERENCE_CATEGORY_LOGGING = "preference_category_logging";
public static final String PREFERENCE_CATEGORY_ADDRESSBOOK = "preference_category_addressbook";
public static final String PREFERENCE_CATEGORY_APPEARANCE = "preference_category_appearance";
public static final String PREFERENCE_CATEGORY_ADVANCED = "preference_category_advanced";
private final LocaleManager localeManager = new LocaleManager();
@Override
protected void onCreate(Bundle savedInstanceState) {
localeManager.onCreate(this);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_single_fragment);
Toolbar toolbar = (Toolbar) findViewById(R.id.main_toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
Fragment fragment;
String category = getIntent().getStringExtra(PREFERENCE_CATEGORY);
if (category != null)
fragment = getFragmentForCategory(category);
else
fragment = new SettingsFragment();
getSupportFragmentManager().beginTransaction()
.replace(R.id.fragment, fragment)
.commit();
}
@Override
public void onResume() {
super.onResume();
localeManager.onResume(this);
}
@Override
public boolean onSupportNavigateUp() {
FragmentManager fragmentManager = getSupportFragmentManager();
if (fragmentManager.getBackStackEntryCount() > 0) {
fragmentManager.popBackStack();
} else {
Intent intent = new Intent(this, I2PActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
finish();
}
return true;
}
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
if (key.equals(getResources().getString(R.string.PREF_LANGUAGE))) {
localeManager.onResume(this);
Intent intent = new Intent(RouterService.LOCAL_BROADCAST_LOCALE_CHANGED);
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
}
public static class SettingsFragment extends PreferenceFragment {
@Override
public void onCreate(Bundle paramBundle) {
super.onCreate(paramBundle);
addPreferencesFromResource(R.xml.settings);
this.findPreference(PREFERENCE_CATEGORY_NETWORK)
.setOnPreferenceClickListener(new CategoryClickListener(PREFERENCE_CATEGORY_NETWORK));
this.findPreference(PREFERENCE_CATEGORY_GRAPHS)
.setOnPreferenceClickListener(new CategoryClickListener(PREFERENCE_CATEGORY_GRAPHS));
this.findPreference(PREFERENCE_CATEGORY_LOGGING)
.setOnPreferenceClickListener(new CategoryClickListener(PREFERENCE_CATEGORY_LOGGING));
this.findPreference(PREFERENCE_CATEGORY_ADDRESSBOOK)
.setOnPreferenceClickListener(new CategoryClickListener(PREFERENCE_CATEGORY_ADDRESSBOOK));
this.findPreference(PREFERENCE_CATEGORY_APPEARANCE)
.setOnPreferenceClickListener(new CategoryClickListener(PREFERENCE_CATEGORY_APPEARANCE));
this.findPreference(PREFERENCE_CATEGORY_ADVANCED)
.setOnPreferenceClickListener(new CategoryClickListener(PREFERENCE_CATEGORY_ADVANCED));
}
@Override
public void onResume() {
super.onResume();
((SettingsActivity) getActivity()).getSupportActionBar().setTitle(R.string.menu_settings);
}
private class CategoryClickListener implements Preference.OnPreferenceClickListener {
private String category;
public CategoryClickListener(String category) {
this.category = category;
}
@Override
public boolean onPreferenceClick(Preference preference) {
if (PREFERENCE_CATEGORY_ADDRESSBOOK.equals(category)) {
Intent i = new Intent(getActivity(), AddressbookSettingsActivity.class);
startActivity(i);
return true;
}
Fragment fragment = getFragmentForCategory(category);
getActivity().getSupportFragmentManager().beginTransaction()
.replace(R.id.fragment, fragment)
.addToBackStack(null)
.commit();
return true;
}
}
}
private static Fragment getFragmentForCategory(String category) {
switch (category) {
case PREFERENCE_CATEGORY_NETWORK:
return new NetworkPreferenceFragment();
case PREFERENCE_CATEGORY_GRAPHS:
return new GraphsPreferenceFragment();
case PREFERENCE_CATEGORY_LOGGING:
return new LoggingPreferenceFragment();
case PREFERENCE_CATEGORY_APPEARANCE:
return new AppearancePreferenceFragment();
case PREFERENCE_CATEGORY_ADVANCED:
return new AdvancedPreferenceFragment();
default:
throw new AssertionError();
}
}
}

View File

@ -0,0 +1,31 @@
package net.i2p.android.router.addressbook;
import net.i2p.data.Destination;
public class AddressEntry {
private final String mHostName;
private final Destination mDest;
public AddressEntry(String hostName, Destination dest) {
mHostName = hostName;
mDest = dest;
}
public String getHostName() {
return mHostName;
}
public Destination getDestination() {
return mDest;
}
/**
* See item 8 from Josh Bloch's "Effective Java".
*
* @return the hashcode of this AddressEntry
*/
@Override
public int hashCode() {
return 37 * mHostName.hashCode() + mDest.hashCode();
}
}

View File

@ -0,0 +1,144 @@
package net.i2p.android.router.addressbook;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import net.i2p.android.router.R;
import net.i2p.android.util.AlphanumericHeaderAdapter;
import java.util.List;
public class AddressEntryAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> implements
AlphanumericHeaderAdapter.SortedAdapter {
private Context mCtx;
private AddressbookFragment.OnAddressSelectedListener mListener;
private List<AddressEntry> mAddresses;
public static class SimpleViewHolder extends RecyclerView.ViewHolder {
public SimpleViewHolder(View itemView) {
super(itemView);
}
}
public static class AddressViewHolder extends RecyclerView.ViewHolder {
public TextView hostName;
public AddressViewHolder(View itemView) {
super(itemView);
hostName = (TextView) itemView.findViewById(R.id.host_name);
}
}
public AddressEntryAdapter(Context context,
AddressbookFragment.OnAddressSelectedListener listener) {
super();
mCtx = context;
mListener = listener;
setHasStableIds(true);
}
public void setAddresses(List<AddressEntry> addresses) {
mAddresses = addresses;
notifyDataSetChanged();
}
public AddressEntry getAddress(int position) {
if (mAddresses == null || mAddresses.isEmpty() ||
position < 0 || position >= mAddresses.size())
return null;
return mAddresses.get(position);
}
@NonNull
@Override
public String getSortString(int position) {
AddressEntry address = getAddress(position);
if (address == null)
return "";
return address.getHostName();
}
@Override
public int getItemViewType(int position) {
if (mAddresses == null)
return R.string.router_not_running;
else if (mAddresses.isEmpty())
return R.layout.listitem_empty;
else
return R.layout.listitem_address;
}
// Create new views (invoked by the layout manager)
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
int vt = viewType;
if (viewType == R.string.router_not_running)
vt = R.layout.listitem_empty;
View v = LayoutInflater.from(parent.getContext())
.inflate(vt, parent, false);
switch (viewType) {
case R.layout.listitem_address:
return new AddressViewHolder(v);
default:
return new SimpleViewHolder(v);
}
}
// Replace the contents of a view (invoked by the layout manager)
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
switch (holder.getItemViewType()) {
case R.string.router_not_running:
((TextView) holder.itemView).setText(
mCtx.getString(R.string.router_not_running));
break;
case R.layout.listitem_empty:
((TextView) holder.itemView).setText(
mCtx.getString(R.string.addressbook_is_empty));
break;
case R.layout.listitem_address:
final AddressEntry address = getAddress(position);
AddressViewHolder avh = (AddressViewHolder) holder;
avh.hostName.setText(address.getHostName());
avh.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mListener.onAddressSelected(address.getHostName());
}
});
break;
default:
break;
}
}
// Return the size of the dataset (invoked by the layout manager)
@Override
public int getItemCount() {
if (mAddresses == null || mAddresses.isEmpty())
return 1;
return mAddresses.size();
}
public long getItemId(int position) {
AddressEntry address = getAddress(position);
if (address == null)
return Integer.MAX_VALUE;
return address.hashCode();
}
}

View File

@ -0,0 +1,173 @@
package net.i2p.android.router.addressbook;
import android.content.Context;
import android.support.v4.content.AsyncTaskLoader;
import net.i2p.android.router.util.NamingServiceUtil;
import net.i2p.android.router.util.Util;
import net.i2p.client.naming.NamingService;
import net.i2p.client.naming.NamingServiceListener;
import net.i2p.data.Destination;
import net.i2p.router.RouterContext;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.TreeMap;
public class AddressEntryLoader extends AsyncTaskLoader<List<AddressEntry>> implements
NamingServiceListener {
private String mBook;
private String mFilter;
private List<AddressEntry> mData;
public AddressEntryLoader(Context context, String book, String filter) {
super(context);
mBook = book;
mFilter = filter;
}
@Override
public List<AddressEntry> loadInBackground() {
RouterContext routerContext = Util.getRouterContext();
if (routerContext == null)
return null;
// get the names
NamingService ns = NamingServiceUtil.getNamingService(routerContext, mBook);
Util.d("NamingService: " + ns.getName());
// After router shutdown we get nothing... why?
List<AddressEntry> ret = new ArrayList<>();
Map<String, Destination> names = new TreeMap<>();
Properties searchProps = new Properties();
// Needed for HostsTxtNamingService
searchProps.setProperty("file", mBook);
if (mFilter != null && mFilter.length() > 0)
searchProps.setProperty("search", mFilter);
names.putAll(ns.getEntries(searchProps));
for (String hostName : names.keySet())
ret.add(new AddressEntry(hostName, names.get(hostName)));
return ret;
}
@Override
public void deliverResult(List<AddressEntry> data) {
if (isReset()) {
// The Loader has been reset; ignore the result and invalidate the data.
if (data != null) {
releaseResources(data);
return;
}
}
// Hold a reference to the old data so it doesn't get garbage collected.
// We must protect it until the new data has been delivered.
List<AddressEntry> oldData = mData;
mData = data;
if (isStarted()) {
// If the Loader is in a started state, have the superclass deliver the
// results to the client.
super.deliverResult(data);
}
// Invalidate the old data as we don't need it any more.
if (oldData != null && oldData != data) {
releaseResources(oldData);
}
}
@Override
protected void onStartLoading() {
if (mData != null) {
// Deliver any previously loaded data immediately.
deliverResult(mData);
}
// Begin monitoring the underlying data source.
RouterContext routerContext = Util.getRouterContext();
if (routerContext != null) {
NamingService ns = NamingServiceUtil.getNamingService(routerContext, mBook);
ns.registerListener(this);
}
if (takeContentChanged() || mData == null) {
// When the observer detects a change, it should call onContentChanged()
// on the Loader, which will cause the next call to takeContentChanged()
// to return true. If this is ever the case (or if the current data is
// null), we force a new load.
forceLoad();
}
}
@Override
protected void onStopLoading() {
// The Loader is in a stopped state, so we should attempt to cancel the
// current load (if there is one).
cancelLoad();
// Note that we leave the observer as is. Loaders in a stopped state
// should still monitor the data source for changes so that the Loader
// will know to force a new load if it is ever started again.
}
@Override
protected void onReset() {
// Ensure the loader has been stopped.
onStopLoading();
// At this point we can release the resources associated with 'mData'.
if (mData != null) {
releaseResources(mData);
mData = null;
}
// The Loader is being reset, so we should stop monitoring for changes.
RouterContext routerContext = Util.getRouterContext();
if (routerContext != null) {
NamingService ns = NamingServiceUtil.getNamingService(routerContext, mBook);
ns.unregisterListener(this);
}
}
@Override
public void onCanceled(List<AddressEntry> data) {
// Attempt to cancel the current asynchronous load.
super.onCanceled(data);
// The load has been canceled, so we should release the resources
// associated with 'data'.
releaseResources(data);
}
private void releaseResources(List<AddressEntry> data) {
// For a simple List, there is nothing to do. For something like a Cursor, we
// would close it in this method. All resources associated with the Loader
// should be released here.
}
// NamingServiceListener
@Override
public void configurationChanged(NamingService ns) {
onContentChanged();
}
@Override
public void entryAdded(NamingService ns, String hostname, Destination dest, Properties options) {
onContentChanged();
}
@Override
public void entryChanged(NamingService ns, String hostname, Destination dest, Properties options) {
onContentChanged();
}
@Override
public void entryRemoved(NamingService ns, String hostname) {
onContentChanged();
}
}

View File

@ -0,0 +1,45 @@
package net.i2p.android.router.addressbook;
import android.app.Activity;
import android.app.Dialog;
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.v7.app.AlertDialog;
import net.i2p.android.wizard.model.AbstractWizardModel;
import net.i2p.android.wizard.ui.AbstractWizardActivity;
public class AddressbookAddWizardActivity extends AbstractWizardActivity {
@Override
protected AbstractWizardModel onCreateModel() {
return new AddressbookAddWizardModel(this);
}
@Override
protected DialogFragment onGetFinishWizardDialog() {
return new DialogFragment() {
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
return new AlertDialog.Builder(getActivity())
.setMessage("Add to private addressbook?")
.setPositiveButton("Add",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
Intent result = new Intent();
setResult(Activity.RESULT_OK, result);
result.putExtra(AddressbookContainer.ADD_WIZARD_DATA, mWizardModel.save());
dialog.dismiss();
finish();
}
})
.setNegativeButton(android.R.string.cancel, null)
.create();
}
};
}
}

View File

@ -0,0 +1,31 @@
package net.i2p.android.router.addressbook;
import android.content.Context;
import android.content.res.Resources;
import net.i2p.android.router.R;
import net.i2p.android.wizard.model.AbstractWizardModel;
import net.i2p.android.wizard.model.I2PB64DestinationPage;
import net.i2p.android.wizard.model.PageList;
import net.i2p.android.wizard.model.SingleTextFieldPage;
public class AddressbookAddWizardModel extends AbstractWizardModel {
public AddressbookAddWizardModel(Context context) {
super(context);
}
@Override
protected PageList onNewRootPageList() {
Resources res = mContext.getResources();
return new PageList(
new SingleTextFieldPage(this, res.getString(R.string.addressbook_add_wizard_k_name))
.setDescription(res.getString(R.string.addressbook_add_wizard_desc_name))
.setRequired(true),
new I2PB64DestinationPage(this, res.getString(R.string.addressbook_add_wizard_k_destination))
.setDescription(res.getString(R.string.addressbook_add_wizard_desc_destination))
.setRequired(true)
);
}
}

View File

@ -0,0 +1,250 @@
package net.i2p.android.router.addressbook;
import android.app.Activity;
import android.app.SearchManager;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.view.MenuItemCompat;
import android.support.v4.view.ViewPager;
import android.support.v7.widget.SearchView;
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 com.viewpagerindicator.TitlePageIndicator;
import net.i2p.android.router.R;
import net.i2p.android.router.util.NamingServiceUtil;
import net.i2p.android.router.util.Util;
import net.i2p.client.naming.NamingService;
public class AddressbookContainer extends Fragment
implements AddressbookFragment.OnAddressSelectedListener,
SearchView.OnQueryTextListener {
public static final int ADD_WIZARD_REQUEST = 1;
public static final String ADD_WIZARD_DATA = "add_wizard_data";
/**
* Whether or not the container is in two-pane mode, i.e. running on a tablet
* device.
*/
private boolean mTwoPane;
ViewPager mViewPager;
FragmentPagerAdapter mFragPagerAdapter;
private static final String FRAGMENT_ROUTER = "router_fragment";
private static final String FRAGMENT_PRIVATE = "private_fragment";
private static final int FRAGMENT_ID_ROUTER = 0;
private static final int FRAGMENT_ID_PRIVATE = 1;
AddressbookFragment mRouterFrag;
AddressbookFragment mPrivateFrag;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.container_addressbook, container, false);
if (v.findViewById(R.id.right_fragment) != null) {
// The detail container view will be present only in the
// large-screen layouts (res/values-large and
// res/values-sw600dp). If this view is present, then the
// activity should be in two-pane mode.
mTwoPane = true;
}
if (savedInstanceState != null) {
mRouterFrag = (AddressbookFragment) getChildFragmentManager().getFragment(
savedInstanceState, FRAGMENT_ROUTER);
mPrivateFrag = (AddressbookFragment) getChildFragmentManager().getFragment(
savedInstanceState, FRAGMENT_PRIVATE);
} else if (mTwoPane) {
// TODO if these were instantiated in the background, wouldn't savedInstanceState != null?
mRouterFrag = (AddressbookFragment) getChildFragmentManager().findFragmentById(R.id.left_fragment);
mPrivateFrag = (AddressbookFragment) getChildFragmentManager().findFragmentById(R.id.right_fragment);
// Set up the two pages
FragmentTransaction ft = getChildFragmentManager().beginTransaction();
if (mRouterFrag == null) {
mRouterFrag = AddressbookFragment.newInstance(AddressbookFragment.ROUTER_BOOK);
ft.add(R.id.left_fragment, mRouterFrag);
}
if (mPrivateFrag == null) {
mPrivateFrag = AddressbookFragment.newInstance(AddressbookFragment.PRIVATE_BOOK);
ft.add(R.id.right_fragment, mPrivateFrag);
}
ft.commit();
}
if (!mTwoPane) {
mViewPager = (ViewPager) v.findViewById(R.id.pager);
TitlePageIndicator pageIndicator = (TitlePageIndicator) v.findViewById(R.id.page_indicator);
mFragPagerAdapter = new AddressbookPagerAdapter(getActivity(), getChildFragmentManager());
mViewPager.setAdapter(mFragPagerAdapter);
pageIndicator.setViewPager(mViewPager);
}
return v;
}
public class AddressbookPagerAdapter extends FragmentPagerAdapter {
private static final int NUM_ITEMS = 2;
private Context mContext;
public AddressbookPagerAdapter(Context context, FragmentManager fm) {
super(fm);
mContext = context;
}
@Override
public int getCount() {
return NUM_ITEMS;
}
@Override
public Fragment getItem(int position) {
switch (position) {
case FRAGMENT_ID_ROUTER:
return (mRouterFrag = AddressbookFragment.newInstance(AddressbookFragment.ROUTER_BOOK));
case FRAGMENT_ID_PRIVATE:
return (mPrivateFrag = AddressbookFragment.newInstance(AddressbookFragment.PRIVATE_BOOK));
default:
return null;
}
}
@Override
public CharSequence getPageTitle(int position) {
switch (position) {
case FRAGMENT_ID_ROUTER:
return mContext.getString(R.string.label_router);
case FRAGMENT_ID_PRIVATE:
return mContext.getString(R.string.label_private);
default:
return null;
}
}
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.container_addressbook_actions, menu);
SearchManager searchManager = (SearchManager) getActivity().getSystemService(Context.SEARCH_SERVICE);
MenuItem searchItem = menu.findItem(R.id.action_search_addressbook);
SearchView searchView = (SearchView) MenuItemCompat.getActionView(searchItem);
searchView.setSearchableInfo(searchManager.getSearchableInfo(getActivity().getComponentName()));
searchView.setOnQueryTextListener(this);
}
@Override
public void setMenuVisibility(boolean menuVisible) {
super.setMenuVisibility(menuVisible);
setChildMenuVisibility(mRouterFrag, FRAGMENT_ID_ROUTER, menuVisible);
setChildMenuVisibility(mPrivateFrag, FRAGMENT_ID_PRIVATE, menuVisible);
}
private void setChildMenuVisibility(Fragment fragment, int itemNumber, boolean menuVisible) {
if (fragment != null) {
if (mViewPager != null)
menuVisible = menuVisible && mViewPager.getCurrentItem() == itemNumber;
fragment.setMenuVisibility(menuVisible);
}
}
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
setChildUserVisibleHint(mRouterFrag, FRAGMENT_ID_ROUTER, isVisibleToUser);
setChildUserVisibleHint(mPrivateFrag, FRAGMENT_ID_PRIVATE, isVisibleToUser);
}
private void setChildUserVisibleHint(Fragment fragment, int itemNumber, boolean isVisibleToUser) {
if (fragment != null) {
if (mViewPager != null)
isVisibleToUser = isVisibleToUser && mViewPager.getCurrentItem() == itemNumber;
fragment.setUserVisibleHint(isVisibleToUser);
}
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
// Since the pager fragments don't have known tags or IDs, the only way to persist the
// reference is to use putFragment/getFragment. Remember, we're not persisting the exact
// Fragment instance. This mechanism simply gives us a way to persist access to the
// 'current' fragment instance for the given fragment (which changes across orientation
// changes).
//
// The outcome of all this is that the "Refresh" menu button refreshes the stream across
// orientation changes.
if (mRouterFrag != null)
getChildFragmentManager().putFragment(outState, FRAGMENT_ROUTER, mRouterFrag);
if (mPrivateFrag != null)
getChildFragmentManager().putFragment(outState, FRAGMENT_PRIVATE, mPrivateFrag);
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == ADD_WIZARD_REQUEST &&
resultCode == Activity.RESULT_OK) {
// Save the new entry
Bundle entryData = data.getExtras().getBundle(ADD_WIZARD_DATA);
NamingService ns = NamingServiceUtil.getNamingService(Util.getRouterContext(),
AddressbookFragment.PRIVATE_BOOK);
NamingServiceUtil.addFromWizard(getActivity(), ns, entryData, false);
// The loader will be notified by the NamingService
}
}
// AddressbookFragment.OnAddressSelectedListener
public void onAddressSelected(CharSequence host) {
if (Intent.ACTION_PICK.equals(getActivity().getIntent().getAction())) {
Intent result = new Intent();
result.setData(Uri.parse("http://" + host));
getActivity().setResult(Activity.RESULT_OK, result);
getActivity().finish();
} else {
Intent i = new Intent(Intent.ACTION_VIEW);
i.setData(Uri.parse("http://" + host));
startActivity(i);
}
}
// SearchView.OnQueryTextListener
public boolean onQueryTextChange(String newText) {
filterAddresses(newText);
return true;
}
public boolean onQueryTextSubmit(String query) {
filterAddresses(query);
return true;
}
private void filterAddresses(String query) {
if (mRouterFrag != null)
mRouterFrag.filterAddresses(query);
if (mPrivateFrag != null)
mPrivateFrag.filterAddresses(query);
}
}

View File

@ -0,0 +1,267 @@
package net.i2p.android.router.addressbook;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.Loader;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.text.TextUtils;
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.ImageButton;
import android.widget.Toast;
import com.eowise.recyclerview.stickyheaders.StickyHeadersBuilder;
import com.eowise.recyclerview.stickyheaders.StickyHeadersItemDecoration;
import com.pnikosis.materialishprogress.ProgressWheel;
import net.i2p.addressbook.Daemon;
import net.i2p.android.router.R;
import net.i2p.android.router.service.RouterService;
import net.i2p.android.router.service.State;
import net.i2p.android.router.util.Util;
import net.i2p.android.util.AlphanumericHeaderAdapter;
import net.i2p.android.util.FragmentUtils;
import net.i2p.android.widget.DividerItemDecoration;
import net.i2p.android.widget.LoadingRecyclerView;
import net.i2p.router.RouterContext;
import java.util.ArrayList;
import java.util.List;
public class AddressbookFragment extends Fragment implements
LoaderManager.LoaderCallbacks<List<AddressEntry>> {
public static final String BOOK_NAME = "book_name";
public static final String ROUTER_BOOK = "hosts.txt";
public static final String PRIVATE_BOOK = "privatehosts.txt";
private static final int ROUTER_LOADER_ID = 1;
private static final int PRIVATE_LOADER_ID = 2;
private OnAddressSelectedListener mCallback;
private LoadingRecyclerView mRecyclerView;
private AddressEntryAdapter mAdapter;
private String mBook;
private String mCurFilter;
private ImageButton mAddToAddressbook;
// Container Activity must implement this interface
public interface OnAddressSelectedListener {
void onAddressSelected(CharSequence host);
}
public static AddressbookFragment newInstance(String book) {
AddressbookFragment f = new AddressbookFragment();
Bundle args = new Bundle();
args.putString(AddressbookFragment.BOOK_NAME, book);
f.setArguments(args);
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
mCallback = FragmentUtils.getParent(this, OnAddressSelectedListener.class);
if (mCallback == null)
throw new ClassCastException("Parent must implement OnAddressSelectedListener");
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_list_with_add, container, false);
mRecyclerView = (LoadingRecyclerView) v.findViewById(R.id.list);
View empty = v.findViewById(R.id.empty);
ProgressWheel loading = (ProgressWheel) v.findViewById(R.id.loading);
mRecyclerView.setLoadingView(empty, loading);
mAddToAddressbook = (ImageButton) v.findViewById(R.id.promoted_action);
mAddToAddressbook.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent wi = new Intent(getActivity(), AddressbookAddWizardActivity.class);
getParentFragment().startActivityForResult(wi, AddressbookContainer.ADD_WIZARD_REQUEST);
}
});
return v;
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mBook = getArguments().getString(BOOK_NAME);
mRecyclerView.setHasFixedSize(true);
mRecyclerView.addItemDecoration(new DividerItemDecoration(getActivity(), DividerItemDecoration.VERTICAL_LIST));
// use a linear layout manager
RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getActivity());
mRecyclerView.setLayoutManager(mLayoutManager);
// Set the adapter for the list view
mAdapter = new AddressEntryAdapter(getActivity(), mCallback);
mRecyclerView.setAdapter(mAdapter);
// Build item decoration and add it to the RecyclerView
StickyHeadersItemDecoration decoration = new StickyHeadersBuilder()
.setAdapter(mAdapter)
.setRecyclerView(mRecyclerView)
.setStickyHeadersAdapter(new AlphanumericHeaderAdapter(mAdapter))
.build();
mRecyclerView.addItemDecoration(decoration);
// Initialize the adapter in case the RouterService has not been created
if (Util.getRouterContext() == null)
mAdapter.setAddresses(null);
}
@Override
public void onStart() {
super.onStart();
LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(getActivity());
IntentFilter filter = new IntentFilter();
filter.addAction(RouterService.LOCAL_BROADCAST_STATE_NOTIFICATION);
filter.addAction(RouterService.LOCAL_BROADCAST_STATE_CHANGED);
lbm.registerReceiver(onStateChange, filter);
}
private State lastRouterState = null;
private BroadcastReceiver onStateChange = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
State state = intent.getParcelableExtra(RouterService.LOCAL_BROADCAST_EXTRA_STATE);
if (lastRouterState == null || lastRouterState != state) {
updateState(state);
lastRouterState = state;
}
}
};
public void updateState(State state) {
int loaderId = PRIVATE_BOOK.equals(mBook) ?
PRIVATE_LOADER_ID : ROUTER_LOADER_ID;
if (state == State.STOPPING || state == State.STOPPED ||
state == State.MANUAL_STOPPING ||
state == State.MANUAL_STOPPED ||
state == State.MANUAL_QUITTING ||
state == State.MANUAL_QUITTED)
getLoaderManager().destroyLoader(loaderId);
else {
mRecyclerView.setLoading(true);
getLoaderManager().initLoader(loaderId, null, this);
}
}
@Override
public void onResume() {
super.onResume();
// Triggers loader init via updateState() if the router is running
LocalBroadcastManager.getInstance(getActivity()).sendBroadcast(new Intent(RouterService.LOCAL_BROADCAST_REQUEST_STATE));
}
@Override
public void onStop() {
super.onStop();
LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(onStateChange);
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.fragment_addressbook_actions, menu);
}
@Override
public void onPrepareOptionsMenu(Menu menu) {
RouterContext rCtx = Util.getRouterContext();
if (mAddToAddressbook != null)
mAddToAddressbook.setVisibility(rCtx == null ? View.GONE : View.VISIBLE);
// Only show "Reload subscriptions" for router addressbook
menu.findItem(R.id.action_reload_subscriptions).setVisible(
rCtx != null && !PRIVATE_BOOK.equals(mBook));
// Only allow adding to private book
if (!PRIVATE_BOOK.equals(mBook) && mAddToAddressbook != null) {
mAddToAddressbook.setVisibility(View.GONE);
mAddToAddressbook = null;
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle presses on the action bar items
switch (item.getItemId()) {
case R.id.action_reload_subscriptions:
Daemon.wakeup();
Toast.makeText(getActivity(), "Reloading subscriptions...",
Toast.LENGTH_SHORT).show();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
public void filterAddresses(String query) {
mCurFilter = !TextUtils.isEmpty(query) ? query : null;
if (Util.getRouterContext() != null && mAdapter != null) {
mRecyclerView.setLoading(true);
getLoaderManager().restartLoader(PRIVATE_BOOK.equals(mBook) ?
PRIVATE_LOADER_ID : ROUTER_LOADER_ID, null, this);
}
}
// LoaderManager.LoaderCallbacks<List<AddressEntry>>
public Loader<List<AddressEntry>> onCreateLoader(int id, Bundle args) {
return new AddressEntryLoader(getActivity(), mBook, mCurFilter);
}
public void onLoadFinished(Loader<List<AddressEntry>> loader,
List<AddressEntry> data) {
if (loader.getId() == (PRIVATE_BOOK.equals(mBook) ?
PRIVATE_LOADER_ID : ROUTER_LOADER_ID)) {
mAdapter.setAddresses(data);
}
}
public void onLoaderReset(Loader<List<AddressEntry>> loader) {
if (loader.getId() == (PRIVATE_BOOK.equals(mBook) ?
PRIVATE_LOADER_ID : ROUTER_LOADER_ID)) {
if (Util.getRouterContext() == null)
mAdapter.setAddresses(null);
else
mAdapter.setAddresses(new ArrayList<AddressEntry>());
}
}
}

View File

@ -0,0 +1,97 @@
package net.i2p.android.router.addressbook;
import android.content.Context;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import net.i2p.android.router.R;
import net.i2p.android.util.LocaleManager;
import net.i2p.util.FileUtil;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
public class AddressbookSettingsActivity extends AppCompatActivity {
private EditText text_content_subscriptions;
private Button btn_save_subscriptions;
private String filename = "/addressbook/subscriptions.txt";
private File i2pDir;
private final LocaleManager localeManager = new LocaleManager();
@Override
public void onCreate(Bundle savedInstanceState) {
localeManager.onCreate(this);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_addressbook_settings);
// Set the action bar
Toolbar toolbar = (Toolbar) findViewById(R.id.main_toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
text_content_subscriptions = (EditText) findViewById(R.id.subscriptions_content);
btn_save_subscriptions = (Button) findViewById(R.id.button_save_subscriptions);
init_actions();
i2pDir = new File(getFilesDir(), filename);
load();
}
private void init_actions() {
btn_save_subscriptions.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
Context context = getApplicationContext();
CharSequence text;
if (save()) {
text = "subscriptions.txt successfully saved!";
} else {
text = "there was a problem saving subscriptions.txt! Try fix permissions or reinstall i2p.";
}
Toast.makeText(context, text, Toast.LENGTH_SHORT).show();
}
});
}
private boolean load() {
String res = FileUtil.readTextFile(i2pDir.getAbsolutePath(), -1, true);
if (res.length() > 0) {
text_content_subscriptions.setText(res);
return true;
}
Context context = getApplicationContext();
CharSequence text = "Sorry, could not load subscriptions.txt!";
Toast.makeText(context, text, Toast.LENGTH_SHORT).show();
return false;
}
private boolean save() {
//
String content = text_content_subscriptions.getText().toString();
FileOutputStream out = null;
try {
out = new FileOutputStream(i2pDir);
byte[] contentInBytes = content.getBytes();
out.write(contentInBytes);
out.close();
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
} finally {
if (out != null) try {out.close(); } catch (IOException ioe) {}
}
}
@Override
public void onResume() {
super.onResume();
localeManager.onResume(this);
}
}

View File

@ -0,0 +1,58 @@
package net.i2p.android.router.dialog;
import android.app.Dialog;
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.v7.app.AlertDialog;
import android.text.util.Linkify;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;
import net.i2p.android.router.LicenseActivity;
import net.i2p.android.router.R;
import net.i2p.android.router.util.I2Patterns;
import net.i2p.android.router.util.Util;
public class AboutDialog extends DialogFragment {
@NonNull
@Override
public Dialog onCreateDialog(Bundle SavedInstanceState) {
LayoutInflater li = LayoutInflater.from(getActivity());
View view = li.inflate(R.layout.fragment_dialog_about, null);
final String currentVersion = Util.getOurVersion(getActivity());
TextView tv = (TextView)view.findViewById(R.id.about_version);
tv.setText(currentVersion);
tv = (TextView)view.findViewById(R.id.url_project);
Linkify.addLinks(tv, I2Patterns.I2P_WEB_URL, "http://");
tv = (TextView)view.findViewById(R.id.url_android_bugs);
Linkify.addLinks(tv, I2Patterns.I2P_WEB_URL, "http://");
tv = (TextView)view.findViewById(R.id.url_android_volunteer);
Linkify.addLinks(tv, I2Patterns.I2P_WEB_URL, "http://");
tv = (TextView)view.findViewById(R.id.url_donate);
Linkify.addLinks(tv, I2Patterns.I2P_WEB_URL, "http://");
AlertDialog.Builder b = new AlertDialog.Builder(getActivity());
b.setTitle(R.string.menu_about)
.setView(view)
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int i) {
dialog.dismiss();
}
})
.setNeutralButton(R.string.label_licenses, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
Intent lic = new Intent(getActivity(), LicenseActivity.class);
startActivity(lic);
}
});
return b.create();
}
}

View File

@ -0,0 +1,40 @@
package net.i2p.android.router.dialog;
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.support.v7.app.AlertDialog;
import android.text.util.Linkify;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;
import net.i2p.android.router.R;
import net.i2p.android.router.util.I2Patterns;
public class FirstStartDialog extends DialogFragment {
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
LayoutInflater li = LayoutInflater.from(getActivity());
View view = li.inflate(R.layout.fragment_dialog_first_start, null);
TextView tv = (TextView)view.findViewById(R.id.url_faq);
Linkify.addLinks(tv, I2Patterns.I2P_WEB_URL, "http://");
tv = (TextView)view.findViewById(R.id.url_irc_i2p);
Linkify.addLinks(tv, I2Patterns.IRC_URL, "irc://");
AlertDialog.Builder b = new AlertDialog.Builder(getActivity());
b.setTitle(R.string.first_start_title)
.setView(view)
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int i) {
dialog.dismiss();
}
});
return b.create();
}
}

View File

@ -0,0 +1,82 @@
package net.i2p.android.router.dialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.res.Resources;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.DialogFragment;
import android.support.v7.app.AlertDialog;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;
import net.i2p.android.router.R;
import net.i2p.android.router.util.Util;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
/**
* Display a raw text resource.
* The resource ID must be passed as an extra in the intent.
*/
public class TextResourceDialog extends DialogFragment {
public static final String TEXT_DIALOG_TITLE = "text_title";
public final static String TEXT_RESOURCE_ID = "text_resource_id";
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
AlertDialog.Builder b = new AlertDialog.Builder(getActivity());
LayoutInflater inflater = LayoutInflater.from(getActivity());
View v = inflater.inflate(R.layout.fragment_dialog_text_resource, null, false);
TextView tv = (TextView) v.findViewById(R.id.text_resource_text);
String title = getArguments().getString(TEXT_DIALOG_TITLE);
if (title != null)
b.setTitle(title);
int id = getArguments().getInt(TEXT_RESOURCE_ID, R.raw.releasenotes_txt);
if (id == R.raw.releasenotes_txt)
tv.setText("Release Notes for Release " + Util.getOurVersion(getActivity()) + "\n\n" +
getResourceAsString(id));
else
tv.setText(getResourceAsString(id));
b.setView(v)
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
dialogInterface.dismiss();
}
});
return b.create();
}
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;
while ((read = in.read(buf)) != -1)
out.write(buf, 0, read);
} catch (IOException | Resources.NotFoundException re) {
System.err.println("resource error " + re);
} finally {
if (in != null) try {
in.close();
} catch (IOException ioe) {
}
}
try {
return out.toString("UTF-8");
} catch (UnsupportedEncodingException uee) {
}
return "";
}
}

Some files were not shown because too many files have changed in this diff Show More