Compare commits

..

46 Commits

Author SHA1 Message Date
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
94 changed files with 1731 additions and 494 deletions

3
TODO
View File

@ -1,6 +1,6 @@
# Fixes
- Better addressbook column widths
- Better twopane column widths
<zzz> on the i2ptunnel and addressbook pages on the tablet, the columns are too skinny, they aren't as wide as the tab
<zzz> only a few addressbook entries wrap but on i2ptunnel everything is wrapped and most of the screen is empty
@ -10,7 +10,6 @@
<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
- Display release notes directly on new router version
- Fill out help pages
- Proper browser configuration page
- Rewrite release notes to be release-specific
- Fix release notes UI, either make back button use clear or add buttons
- NetDB tablet view fixes

View File

@ -5,6 +5,8 @@ android {
compileSdkVersion Integer.parseInt(project.ANDROID_BUILD_SDK_VERSION)
buildToolsVersion project.ANDROID_BUILD_TOOLS_VERSION
defaultConfig {
versionCode 4745223
versionName '0.9.16-rc1'
minSdkVersion 9
targetSdkVersion Integer.parseInt(project.ANDROID_BUILD_TARGET_SDK_VERSION)
}
@ -37,19 +39,21 @@ android {
dependencies {
compile project(':routerjars')
compile project(':client')
compile 'com.android.support:support-v4:21.0.0'
compile 'com.android.support:appcompat-v7:21.0.0'
compile 'com.android.support:recyclerview-v7:21.0.0'
compile 'com.android.support:cardview-v7:21.0.0'
compile 'com.android.support:support-v4:21.0.2'
compile 'com.android.support:appcompat-v7:21.0.2'
compile 'com.android.support:recyclerview-v7:21.0.2'
compile 'com.android.support:cardview-v7:21.0.2'
compile 'net.i2p.android.ext:floatingactionbutton:1.1.0'
compile files('libs/androidplot-core-0.6.1.jar')
}
dependencyVerification {
verify = [
'com.android.support:support-v4:199ef7bb169386c80b4836354df6747ce2ae3d24434db923c22439e47106a1e2',
'com.android.support:appcompat-v7:45e999dda55fe81d9cc1c7342b7b70480ff3f307baa8da0df767f92fc5c52cd1',
'com.android.support:recyclerview-v7:ab2390d688601b65e2f3a0718b3d25487e61546c4e20f81eb0b033f30ca15b31',
'com.android.support:cardview-v7:7b724eb46efc98eee70c333cd0e9c34ca89b1a4456c3e40cfcc33501c43570bf',
'com.android.support:support-v4:126a4c291f41f75f3fff4968e9d397bc8454cdff4d8f994cbe0524e3bad76e72',
'com.android.support:appcompat-v7:b760fd3d0b0b0547a1bcef9031b40939f31049ba955f04c8fdc5aa09a25d19e9',
'com.android.support:recyclerview-v7:71ef0f5659b3019dc33c5ffb346ea01df1f66735506f38d43fd783fbcb0370ce',
'com.android.support:cardview-v7:cb4d7ee9ebb6edffa7203eff0d207b4e88425599a8ed37d94b650bc84390c4eb',
'net.i2p.android.ext:floatingactionbutton:84cf5b67a66337bef59b46f57468c730387ca766b5a5f06ca852ba46cabbc0fb',
]
}

View File

@ -1,17 +1,11 @@
<?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"
android:versionCode="4745222"
android:versionName="0.9.15.1">
android:installLocation="auto">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-sdk
android:minSdkVersion="9"
android:targetSdkVersion="19" />
<application
android:icon="@drawable/ic_launcher_itoopie"
android:label="@string/app_name"
@ -59,6 +53,14 @@
android:name="android.support.PARENT_ACTIVITY"
android:value="net.i2p.android.router.MainActivity" />
</activity>
<activity
android:name="net.i2p.android.help.BrowserConfigActivity"
android:label="Browser Configuration"
android:parentActivityName=".MainActivity">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="net.i2p.android.router.MainActivity" />
</activity>
<activity
android:name=".LicenseActivity"
android:label="I2P License Information"
@ -94,7 +96,7 @@
</activity>
<activity
android:name=".addressbook.AddressbookSettingsActivity"
android:label="I2P Addressbook Settings"
android:label="Addressbook Settings"
android:launchMode="singleTop"
android:parentActivityName=".addressbook.AddressbookActivity">
<meta-data

View File

@ -0,0 +1,82 @@
package net.i2p.android.help;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.graphics.drawable.Drawable;
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(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 static interface OnBrowserSelectedListener {
public 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,94 @@
package net.i2p.android.help;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.widget.Toolbar;
import android.view.MenuItem;
import net.i2p.android.router.R;
import java.lang.reflect.Field;
public class BrowserConfigActivity extends ActionBarActivity implements
BrowserAdapter.OnBrowserSelectedListener {
/**
* Whether or not the activity is in two-pane mode, i.e. running on a tablet
* device.
*/
private boolean mTwoPane;
@Override
public void onCreate(Bundle savedInstanceState) {
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 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,187 @@
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 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);
// 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<Browser>();
Map<String, String> recommendedMap = new HashMap<String, String>();
for (int i = 0; i < recommended.size(); i++) {
recommendedMap.put(recommended.get(i), recommendedLabels.get(i));
}
Map<String, String> supportedMap = new HashMap<String, String>();
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

@ -2,27 +2,17 @@ package net.i2p.android.help;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.ActionBar;
import android.support.v7.app.ActionBarActivity;
import android.view.LayoutInflater;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ScrollView;
import android.widget.SpinnerAdapter;
import android.widget.TextView;
import net.i2p.android.router.LicenseActivity;
import net.i2p.android.router.R;
import net.i2p.android.router.dialog.TextResourceDialog;
import org.sufficientlysecure.htmltextview.HtmlTextView;
public class HelpActivity extends ActionBarActivity {
public class HelpActivity extends ActionBarActivity 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;
@ -40,30 +30,10 @@ public class HelpActivity extends ActionBarActivity {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_help);
final ActionBar actionBar = getSupportActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
SpinnerAdapter spinnerAdapter = ArrayAdapter.createFromResource(this,
R.array.help_categories, android.R.layout.simple_spinner_dropdown_item);
ActionBar.OnNavigationListener navigationListener = new ActionBar.OnNavigationListener() {
@Override
public boolean onNavigationItemSelected(int i, long l) {
showCategory(i);
return true;
}
};
actionBar.setListNavigationCallbacks(spinnerAdapter, navigationListener);
if (savedInstanceState == null) {
int category = getIntent().getIntExtra(CATEGORY, CAT_MAIN);
// TODO remove when addressbook and I2PTunnel help added
if (category > CAT_CONFIGURE_BROWSER)
category = CAT_MAIN;
actionBar.setSelectedNavigationItem(category);
showCategory(category);
}
// 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
@ -72,59 +42,16 @@ public class HelpActivity extends ActionBarActivity {
// activity should be in two-pane mode.
mTwoPane = true;
}
}
private void showCategory(int category) {
Fragment f;
switch (category) {
case CAT_CONFIGURE_BROWSER:
//f = new BrowserConfigFragment();
f = HelpHtmlFragment.newInstance(R.raw.help_configure_browser);
break;
case CAT_ADDRESSBOOK:
f = HelpHtmlFragment.newInstance(R.raw.help_addressbook);
break;
case CAT_I2PTUNNEL:
f = HelpHtmlFragment.newInstance(R.raw.help_i2ptunnel);
break;
case CAT_MAIN:
default:
f = HelpHtmlFragment.newInstance(R.raw.help_main);
break;
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction()
.add(R.id.main_fragment, new HelpListFragment())
.commit();
}
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.main_fragment, f);
if (mTwoPane)
ft.remove(getSupportFragmentManager().findFragmentById(R.id.detail_fragment));
ft.commit();
}
public static 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;
}
int category = getIntent().getIntExtra(CATEGORY, -1);
if (category >= 0)
showCategory(category);
}
@Override
@ -136,21 +63,63 @@ public class HelpActivity extends ActionBarActivity {
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
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);
case android.R.id.home:
onBackPressed();
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);
}
}
// HelpListFragment.OnEntrySelectedListener
@Override
public void onEntrySelected(int entry) {
if (entry == CAT_CONFIGURE_BROWSER) {
Intent i = new Intent(this, BrowserConfigActivity.class);
startActivity(i);
} else
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 {
public 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

@ -96,11 +96,14 @@ public class TunnelDetailFragment extends Fragment {
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());
TextView targetIfacePort = (TextView) v.findViewById(R.id.tunnel_target_interface_port);
targetIfacePort.setText(mTunnel.getIfacePort());
targetIfacePort.setText(mTunnel.getTunnelLink(false));
TextView accessIfacePort = (TextView) v.findViewById(R.id.tunnel_access_interface_port);
accessIfacePort.setText(mTunnel.getIfacePort());
accessIfacePort.setText(mTunnel.getTunnelLink(false));
CheckBox autoStart = (CheckBox) v.findViewById(R.id.tunnel_autostart);
autoStart.setChecked(mTunnel.startAutomatically());

View File

@ -90,6 +90,16 @@ public class TunnelEntry {
else return NOT_RUNNING;
}
public boolean isRunning() {
switch (getStatus()) {
case STANDBY:
case RUNNING:
return true;
default:
return false;
}
}
public boolean isClient() {
return TunnelUtil.isClient(mController.getType());
}
@ -100,18 +110,42 @@ public class TunnelEntry {
return Boolean.parseBoolean(mController.getSharedClient());
}
/**
* Call this to see if it is okay to linkify getClientLink()
* @return true if getClientLink() can be linkified, false otherwise.
*/
public boolean isClientLinkValid() {
return ("ircclient".equals(mController.getType())) &&
mController.getListenOnInterface() != null &&
mController.getListenPort() != null;
}
/**
* @return valid host:port only if isClientLinkValid() is true
*/
public String getClientLink(boolean linkify) {
String host = getClientInterface();
String port = getClientPort();
String link = host + ":" + port;
if (linkify) {
if ("ircclient".equals(mController.getType()))
link = "irc://" + link;
}
return link;
}
public String getClientInterface() {
String rv;
if ("streamrclient".equals(mController.getType()))
return mController.getTargetHost();
rv = mController.getTargetHost();
else
return mController.getListenOnInterface();
rv = mController.getListenOnInterface();
return rv != null ? rv : "";
}
public String getClientPort() {
String rv = mController.getListenPort();
if (rv != null)
return rv;
return "";
return rv != null ? rv : "";
}
public String getClientDestination() {
@ -128,10 +162,10 @@ public class TunnelEntry {
/* Server tunnel data */
/**
* Call this to see if it is okay to linkify getServerTarget()
* @return true if getServerTarget() can be linkified, false otherwise.
* Call this to see if it is okay to linkify getServerLink()
* @return true if getServerLink() can be linkified, false otherwise.
*/
public boolean isServerTargetLinkValid() {
public boolean isServerLinkValid() {
return ("httpserver".equals(mController.getType()) ||
"httpbidirserver".equals(mController.getType())) &&
mController.getTargetHost() != null &&
@ -139,9 +173,9 @@ public class TunnelEntry {
}
/**
* @return valid host:port only if isServerTargetLinkValid() is true
* @return valid host:port only if isServerLinkValid() is true
*/
public String getServerTarget() {
public String getServerLink(boolean linkify) {
String host;
if ("streamrserver".equals(getInternalType()))
host = mController.getListenOnInterface();
@ -152,7 +186,13 @@ public class TunnelEntry {
if (port == null) port = "";
if (host.indexOf(':') >= 0)
host = '[' + host + ']';
return host + ":" + port;
String link = host + ":" + port;
if (linkify) {
if ("httpserver".equals(mController.getType()) ||
"httpbidirserver".equals(mController.getType()))
link = "http://" + link;
}
return link;
}
public String getDestinationBase64() {
@ -183,18 +223,14 @@ public class TunnelEntry {
/* Other output formats */
public String getIfacePort() {
if (isClient()) {
String host;
if ("streamrclient".equals(getInternalType()))
host = mController.getTargetHost();
else
host = mController.getListenOnInterface();
String port = mController.getListenPort();
if (host == null) host = "";
if (port == null) port = "";
return host + ":" + port;
} else return getServerTarget();
public boolean isTunnelLinkValid() {
if (isClient()) return isClientLinkValid();
else return isServerLinkValid();
}
public String getTunnelLink(boolean linkify) {
if (isClient()) return getClientLink(linkify);
else return getServerLink(linkify);
}
public String getDetails() {
@ -209,16 +245,29 @@ public class TunnelEntry {
public Drawable getStatusIcon() {
switch (getStatus()) {
case STANDBY:
return mContext.getResources()
.getDrawable(R.drawable.ic_schedule_black_24dp);
case STARTING:
return mContext.getResources()
.getDrawable(R.drawable.local_inprogress);
case RUNNING:
return mContext.getResources()
.getDrawable(R.drawable.local_up);
case NOT_RUNNING:
default:
return mContext.getResources()
.getDrawable(R.drawable.local_down);
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

@ -1,9 +1,9 @@
package net.i2p.android.i2ptunnel;
import java.util.List;
import net.i2p.android.router.R;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@ -11,6 +11,10 @@ import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import net.i2p.android.router.R;
import java.util.List;
public class TunnelEntryAdapter extends ArrayAdapter<TunnelEntry> {
private final LayoutInflater mInflater;
@ -31,22 +35,36 @@ public class TunnelEntryAdapter extends ArrayAdapter<TunnelEntry> {
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = mInflater.inflate(R.layout.listitem_i2ptunnel, parent, false);
TunnelEntry tunnel = getItem(position);
final TunnelEntry tunnel = getItem(position);
ImageView status = (ImageView) v.findViewById(R.id.tunnel_status);
status.setImageDrawable(tunnel.getStatusIcon());
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN)
status.setBackgroundDrawable(tunnel.getStatusBackground());
else
status.setBackground(tunnel.getStatusBackground());
TextView name = (TextView) v.findViewById(R.id.tunnel_name);
name.setText(tunnel.getName());
TextView type = (TextView) v.findViewById(R.id.tunnel_type);
type.setText(tunnel.getType());
TextView type = (TextView) v.findViewById(R.id.tunnel_description);
type.setText(tunnel.getDescription());
TextView ifacePort = (TextView) v.findViewById(R.id.tunnel_interface_port);
ifacePort.setText(tunnel.getIfacePort());
ifacePort.setText(tunnel.getTunnelLink(false));
TextView details = (TextView) v.findViewById(R.id.tunnel_details);
details.setText(tunnel.getDetails());
ImageView status = (ImageView) v.findViewById(R.id.tunnel_status);
status.setImageDrawable(tunnel.getStatusIcon());
if (tunnel.isRunning() && tunnel.isTunnelLinkValid()) {
View open = v.findViewById(R.id.tunnel_open);
open.setVisibility(View.VISIBLE);
open.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent i = new Intent(Intent.ACTION_VIEW);
i.setData(Uri.parse(tunnel.getTunnelLink(true)));
getContext().startActivity(i);
}
});
}
return v;
}

View File

@ -1,27 +1,32 @@
package net.i2p.android.i2ptunnel;
import java.util.List;
import net.i2p.android.help.HelpActivity;
import net.i2p.android.i2ptunnel.util.TunnelConfig;
import net.i2p.android.router.I2PFragmentBase;
import net.i2p.android.router.R;
import net.i2p.android.router.I2PFragmentBase.RouterContextProvider;
import net.i2p.i2ptunnel.TunnelControllerGroup;
import net.i2p.router.RouterContext;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.ListFragment;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.Loader;
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.FrameLayout;
import android.widget.ImageButton;
import android.widget.ListView;
import android.widget.Toast;
import net.i2p.android.help.HelpActivity;
import net.i2p.android.i2ptunnel.util.TunnelConfig;
import net.i2p.android.router.I2PFragmentBase;
import net.i2p.android.router.I2PFragmentBase.RouterContextProvider;
import net.i2p.android.router.R;
import net.i2p.i2ptunnel.TunnelControllerGroup;
import net.i2p.router.RouterContext;
import java.util.List;
public class TunnelListFragment extends ListFragment implements
I2PFragmentBase.RouterContextUser,
LoaderManager.LoaderCallbacks<List<TunnelEntry>> {
@ -50,6 +55,8 @@ public class TunnelListFragment extends ListFragment implements
private int mActivatedPosition = ListView.INVALID_POSITION;
private boolean mActivateOnItemClick = false;
private ImageButton mNewTunnel;
// Container Activity must implement this interface
public interface OnTunnelSelectedListener {
public void onTunnelSelected(int tunnelId);
@ -85,6 +92,27 @@ public class TunnelListFragment extends ListFragment implements
setHasOptionsMenu(true);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Create the list fragment's content view by calling the super method
final View listFragmentView = super.onCreateView(inflater, container, savedInstanceState);
View v = inflater.inflate(R.layout.fragment_list_with_add, container, false);
FrameLayout listContainer = (FrameLayout) v.findViewById(R.id.list_container);
listContainer.addView(listFragmentView);
mNewTunnel = (ImageButton) v.findViewById(R.id.promoted_action);
mNewTunnel.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent wi = new Intent(getActivity(), TunnelWizardActivity.class);
startActivityForResult(wi, TUNNEL_WIZARD_REQUEST);
}
});
return v;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
@ -162,7 +190,7 @@ public class TunnelListFragment extends ListFragment implements
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.fragment_i2ptunnel_list_actions, menu);
if (getRouterContext() == null) {
menu.findItem(R.id.action_add_tunnel).setVisible(false);
mNewTunnel.setVisibility(View.GONE);
menu.findItem(R.id.action_start_all_tunnels).setVisible(false);
menu.findItem(R.id.action_stop_all_tunnels).setVisible(false);
menu.findItem(R.id.action_restart_all_tunnels).setVisible(false);
@ -174,26 +202,22 @@ public class TunnelListFragment extends ListFragment implements
// Handle presses on the action bar items
List<String> msgs;
switch (item.getItemId()) {
case R.id.action_add_tunnel:
Intent wi = new Intent(getActivity(), TunnelWizardActivity.class);
startActivityForResult(wi, TUNNEL_WIZARD_REQUEST);
return true;
case R.id.action_start_all_tunnels:
msgs = mGroup.startAllControllers();
break;
case R.id.action_stop_all_tunnels:
msgs = mGroup.stopAllControllers();
break;
case R.id.action_restart_all_tunnels:
msgs = mGroup.restartAllControllers();
break;
case R.id.action_i2ptunnel_help:
Intent hi = new Intent(getActivity(), HelpActivity.class);
hi.putExtra(HelpActivity.CATEGORY, HelpActivity.CAT_I2PTUNNEL);
startActivity(hi);
return true;
default:
return super.onOptionsItemSelected(item);
case R.id.action_start_all_tunnels:
msgs = mGroup.startAllControllers();
break;
case R.id.action_stop_all_tunnels:
msgs = mGroup.stopAllControllers();
break;
case R.id.action_restart_all_tunnels:
msgs = mGroup.restartAllControllers();
break;
case R.id.action_i2ptunnel_help:
Intent hi = new Intent(getActivity(), HelpActivity.class);
hi.putExtra(HelpActivity.CATEGORY, HelpActivity.CAT_I2PTUNNEL);
startActivity(hi);
return true;
default:
return super.onOptionsItemSelected(item);
}
// TODO: Do something with the other messages
if (msgs.size() > 0)
@ -251,7 +275,7 @@ public class TunnelListFragment extends ListFragment implements
}
public void onLoadFinished(Loader<List<TunnelEntry>> loader,
List<TunnelEntry> data) {
List<TunnelEntry> data) {
if (loader.getId() == (mClientTunnels ?
CLIENT_LOADER_ID : SERVER_LOADER_ID)) {
mAdapter.setData(data);

View File

@ -174,8 +174,10 @@ public abstract class I2PActivityBase extends ActionBarActivity implements
private void selectItem(int pos) {
switch (pos) {
case 1:
Intent news = new Intent(I2PActivityBase.this, NewsActivity.class);
startActivity(news);
if (!(this instanceof NewsActivity)) {
Intent news = new Intent(I2PActivityBase.this, NewsActivity.class);
startActivity(news);
}
break;
case 2:
Intent ab = new Intent(I2PActivityBase.this, AddressbookActivity.class);
@ -186,8 +188,10 @@ public abstract class I2PActivityBase extends ActionBarActivity implements
startActivity(itb);
break;
case 4:
Intent log = new Intent(I2PActivityBase.this, LogActivity.class);
startActivity(log);
if (!(this instanceof LogActivity)) {
Intent log = new Intent(I2PActivityBase.this, LogActivity.class);
startActivity(log);
}
break;
case 5:
Intent wp = new Intent(I2PActivityBase.this, WebActivity.class);
@ -195,16 +199,20 @@ public abstract class I2PActivityBase extends ActionBarActivity implements
startActivity(wp);
break;
case 6:
Intent active = new Intent(I2PActivityBase.this, RateGraphActivity.class);
startActivity(active);
if (!(this instanceof RateGraphActivity)) {
Intent active = new Intent(I2PActivityBase.this, RateGraphActivity.class);
startActivity(active);
}
break;
case 7:
Intent peers = new Intent(I2PActivityBase.this, PeersActivity.class);
startActivity(peers);
break;
case 8:
Intent netdb = new Intent(I2PActivityBase.this, NetDbActivity.class);
startActivity(netdb);
if (!(this instanceof NetDbActivity)) {
Intent netdb = new Intent(I2PActivityBase.this, NetDbActivity.class);
startActivity(netdb);
}
break;
default:
Intent main = new Intent(I2PActivityBase.this, MainActivity.class);
@ -318,8 +326,11 @@ public abstract class I2PActivityBase extends ActionBarActivity implements
public boolean onOptionsItemSelected(MenuItem item) {
// The action bar home/up action should open or close the drawer.
// ActionBarDrawerToggle will take care of this.
if (mDrawerToggle.onOptionsItemSelected(item)) {
if (mDrawerToggle.onOptionsItemSelected(item))
return true;
else if (item.getItemId() == android.R.id.home) {
// This happens when mDrawerToggle.setDrawerIndicatorEnabled(false)
onBackPressed();
}
// Handle action buttons and overflow

View File

@ -144,7 +144,6 @@ public class MainActivity extends I2PActivityBase implements
case R.id.menu_help:
Intent hi = new Intent(MainActivity.this, HelpActivity.class);
hi.putExtra(HelpActivity.CATEGORY, HelpActivity.CAT_MAIN);
startActivity(hi);
return true;

View File

@ -9,6 +9,10 @@ import android.preference.PreferenceActivity;
import android.preference.PreferenceCategory;
import android.preference.PreferenceFragment;
import android.preference.PreferenceScreen;
import android.support.v7.widget.Toolbar;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import net.i2p.I2PAppContext;
@ -33,6 +37,8 @@ public class SettingsActivity extends PreferenceActivity {
private static final String ACTION_PREFS_LOGGING = "net.i2p.android.router.PREFS_LOGGING";
private static final String ACTION_PREFS_ADVANCED = "net.i2p.android.router.PREFS_ADVANCED";
private Toolbar mToolbar;
@SuppressWarnings("deprecation")
@Override
protected void onCreate(Bundle savedInstanceState) {
@ -55,6 +61,8 @@ public class SettingsActivity extends PreferenceActivity {
// Load the legacy preferences headers
addPreferencesFromResource(R.xml.settings_headers_legacy);
}
mToolbar.setTitle(getTitle());
}
protected static void setupGraphSettings(Context context, PreferenceScreen ps, RouterContext ctx) {
@ -155,6 +163,27 @@ public class SettingsActivity extends PreferenceActivity {
loadHeadersFromResource(R.xml.settings_headers, target);
}
@Override
public void setContentView(int layoutResID) {
ViewGroup contentView = (ViewGroup) LayoutInflater.from(this).inflate(
R.layout.activity_settings,
(ViewGroup) getWindow().getDecorView().getRootView(), false);
mToolbar = (Toolbar) contentView.findViewById(R.id.main_toolbar);
mToolbar.setNavigationIcon(getResources().getDrawable(R.drawable.ic_arrow_back_white_24dp));
mToolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onBackPressed();
}
});
ViewGroup contentWrapper = (ViewGroup) contentView.findViewById(R.id.content_wrapper);
LayoutInflater.from(this).inflate(layoutResID, contentWrapper, true);
getWindow().setContentView(contentView);
}
@Override
protected void onPause() {
List<Properties> lProps = Util.getPropertiesFromPreferences(this);

View File

@ -14,7 +14,7 @@ public class AddressEntryAdapter extends ArrayAdapter<AddressEntry> {
private final LayoutInflater mInflater;
public AddressEntryAdapter(Context context) {
super(context, R.layout.addressbook_list_item);
super(context, R.layout.listitem_text);
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
@ -29,7 +29,7 @@ public class AddressEntryAdapter extends ArrayAdapter<AddressEntry> {
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = mInflater.inflate(R.layout.addressbook_list_item, parent, false);
View v = mInflater.inflate(R.layout.listitem_text, parent, false);
AddressEntry address = getItem(position);
TextView text = (TextView) v.findViewById(R.id.text);

View File

@ -18,8 +18,6 @@ import android.widget.Spinner;
import net.i2p.android.router.I2PActivityBase;
import net.i2p.android.router.R;
import net.i2p.android.router.web.WebActivity;
import net.i2p.android.router.web.WebFragment;
public class AddressbookActivity extends I2PActivityBase
implements AddressbookFragment.OnAddressSelectedListener,
@ -37,7 +35,7 @@ public class AddressbookActivity extends I2PActivityBase
@Override
protected boolean canUseTwoPanes() {
return true;
return false;
}
@Override
@ -114,12 +112,8 @@ public class AddressbookActivity extends I2PActivityBase
setResult(Activity.RESULT_OK, result);
finish();
} else {
//Intent i = new Intent(Intent.ACTION_VIEW);
//i.setData(Uri.parse("http://" + host));
// XXX: Temporarily reverting to inbuilt browser
// until an alternative browser is ready.
Intent i = new Intent(this, WebActivity.class);
i.putExtra(WebFragment.HTML_URI, "http://" + host + '/');
Intent i = new Intent(Intent.ACTION_VIEW);
i.setData(Uri.parse("http://" + host));
startActivity(i);
}
}

View File

@ -7,25 +7,29 @@ import android.support.v4.app.ListFragment;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.Loader;
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.FrameLayout;
import android.widget.ImageButton;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import java.util.List;
import net.i2p.addressbook.Daemon;
import net.i2p.android.help.HelpActivity;
import net.i2p.android.router.I2PFragmentBase;
import net.i2p.android.router.R;
import net.i2p.android.router.I2PFragmentBase.RouterContextProvider;
import net.i2p.android.router.R;
import net.i2p.android.router.util.NamingServiceUtil;
import net.i2p.client.naming.NamingService;
import net.i2p.router.RouterContext;
import java.util.List;
public class AddressbookFragment extends ListFragment implements
I2PFragmentBase.RouterContextUser,
LoaderManager.LoaderCallbacks<List<AddressEntry>> {
@ -46,6 +50,8 @@ public class AddressbookFragment extends ListFragment implements
private String mBook;
private String mCurFilter;
private ImageButton mAddToAddressbook;
// Set in onActivityResult()
private Intent mAddWizardData;
@ -84,6 +90,27 @@ public class AddressbookFragment extends ListFragment implements
setHasOptionsMenu(true);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Create the list fragment's content view by calling the super method
final View listFragmentView = super.onCreateView(inflater, container, savedInstanceState);
View v = inflater.inflate(R.layout.fragment_list_with_add, container, false);
FrameLayout listContainer = (FrameLayout) v.findViewById(R.id.list_container);
listContainer.addView(listFragmentView);
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);
startActivityForResult(wi, ADD_WIZARD_REQUEST);
}
});
return v;
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
@ -111,8 +138,8 @@ public class AddressbookFragment extends ListFragment implements
// Show actions
if (mSearchAddressbook != null)
mSearchAddressbook.setVisible(true);
if (mAddToAddressbook != null)
mAddToAddressbook.setVisible(false);
if (mAddToAddressbook != null && mAddToAddressbook.getVisibility() != View.VISIBLE)
mAddToAddressbook.setVisibility(View.VISIBLE);
if (mAddWizardData != null) {
// Save the new entry
@ -140,24 +167,22 @@ public class AddressbookFragment extends ListFragment implements
}
private MenuItem mSearchAddressbook;
private MenuItem mAddToAddressbook;
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.fragment_addressbook_actions, menu);
mSearchAddressbook = menu.findItem(R.id.action_search_addressbook);
mAddToAddressbook = menu.findItem(R.id.action_add_to_addressbook);
// Hide until needed
if (getRouterContext() == null) {
mSearchAddressbook.setVisible(false);
mAddToAddressbook.setVisible(false);
mAddToAddressbook.setVisibility(View.GONE);
}
// Only allow adding to private book
if (!PRIVATE_BOOK.equals(mBook)) {
mAddToAddressbook.setVisible(false);
mAddToAddressbook.setVisibility(View.GONE);
mAddToAddressbook = null;
}
}
@ -167,26 +192,22 @@ public class AddressbookFragment extends ListFragment implements
// Handle presses on the action bar items
switch (item.getItemId()) {
case R.id.action_add_to_addressbook:
Intent wi = new Intent(getActivity(), AddressbookAddWizardActivity.class);
startActivityForResult(wi, ADD_WIZARD_REQUEST);
return true;
case R.id.action_reload_subscriptions:
Daemon.wakeup();
Toast.makeText(getActivity(), "Reloading subscriptions...",
Toast.LENGTH_SHORT).show();
return true;
case R.id.action_addressbook_settings:
Intent si = new Intent(getActivity(), AddressbookSettingsActivity.class);
startActivity(si);
return true;
case R.id.action_addressbook_help:
Intent hi = new Intent(getActivity(), HelpActivity.class);
hi.putExtra(HelpActivity.CATEGORY, HelpActivity.CAT_ADDRESSBOOK);
startActivity(hi);
return true;
default:
return super.onOptionsItemSelected(item);
case R.id.action_reload_subscriptions:
Daemon.wakeup();
Toast.makeText(getActivity(), "Reloading subscriptions...",
Toast.LENGTH_SHORT).show();
return true;
case R.id.action_addressbook_settings:
Intent si = new Intent(getActivity(), AddressbookSettingsActivity.class);
startActivity(si);
return true;
case R.id.action_addressbook_help:
Intent hi = new Intent(getActivity(), HelpActivity.class);
hi.putExtra(HelpActivity.CATEGORY, HelpActivity.CAT_ADDRESSBOOK);
startActivity(hi);
return true;
default:
return super.onOptionsItemSelected(item);
}
}
@ -228,7 +249,7 @@ public class AddressbookFragment extends ListFragment implements
}
public void onLoadFinished(Loader<List<AddressEntry>> loader,
List<AddressEntry> data) {
List<AddressEntry> data) {
if (loader.getId() == (PRIVATE_BOOK.equals(mBook) ?
PRIVATE_LOADER_ID : ROUTER_LOADER_ID)) {
mAdapter.setData(data);

View File

@ -1,20 +1,22 @@
package net.i2p.android.router.addressbook;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.view.Menu;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import net.i2p.android.router.R;
import net.i2p.util.FileUtil;
public class AddressbookSettingsActivity extends Activity {
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
public class AddressbookSettingsActivity extends ActionBarActivity {
private EditText text_content_subscriptions;
private Button btn_save_subscriptions;
@ -25,6 +27,12 @@ public class AddressbookSettingsActivity extends Activity {
public void onCreate(Bundle savedInstanceState) {
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();
@ -32,12 +40,6 @@ public class AddressbookSettingsActivity extends Activity {
load();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_addressbook_settings, menu);
return true;
}
private void init_actions() {
btn_save_subscriptions.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {

View File

@ -11,6 +11,7 @@ import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;
import net.i2p.android.help.BrowserConfigActivity;
import net.i2p.android.help.HelpActivity;
import net.i2p.android.router.R;
import net.i2p.android.router.util.I2Patterns;
@ -26,8 +27,7 @@ public class ConfigureBrowserDialog extends DialogFragment {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
dialogInterface.dismiss();
Intent hi = new Intent(getActivity(), HelpActivity.class);
hi.putExtra(HelpActivity.CATEGORY, HelpActivity.CAT_CONFIGURE_BROWSER);
Intent hi = new Intent(getActivity(), BrowserConfigActivity.class);
startActivity(hi);
}
})

View File

@ -0,0 +1,125 @@
package net.i2p.android.router.util;
import android.content.Context;
import android.support.v4.content.AsyncTaskLoader;
public abstract class BetterAsyncTaskLoader<T> extends AsyncTaskLoader<T> {
protected T mData;
public BetterAsyncTaskLoader(Context context) {
super(context);
}
/**
* Called when there is new data to deliver to the client. The
* super class will take care of delivering it; the implementation
* here just adds a little more logic.
*/
@Override
public void deliverResult(T data) {
if (isReset()) {
// An async query came in while the loader is stopped. We
// don't need the result.
if (data != null) {
releaseResources(data);
}
}
// 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.
T oldData = mData;
mData = data;
if (isStarted()) {
// If the Loader is currently started, we can immediately
// deliver its results.
super.deliverResult(data);
}
// Invalidate the old data as we don't need it any more.
if (oldData != null && oldData != data) {
releaseResources(oldData);
}
}
/**
* Handles a request to start the Loader.
*/
@Override
protected void onStartLoading() {
if (mData != null) {
// Deliver any previously loaded data immediately.
deliverResult(mData);
}
// Start watching for changes
onStartMonitoring();
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();
}
}
/**
* Handles a request to stop the Loader.
*/
@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.
}
/**
* Handles a request to completely reset the Loader.
*/
@Override
protected void onReset() {
super.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;
}
// Stop monitoring for changes.
onStopMonitoring();
}
/**
* Handles a request to cancel a load.
*/
@Override
public void onCanceled(T 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);
}
protected abstract void onStartMonitoring();
protected abstract void onStopMonitoring();
/**
* Helper function to take care of releasing resources associated
* with an actively loaded data set.
* 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.
*/
protected abstract void releaseResources(T data);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 287 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 276 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 650 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 331 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 640 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 240 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 234 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 454 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 260 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 444 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 336 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 348 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 832 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 418 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 793 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 410 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 480 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 541 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

View File

@ -1,48 +1,59 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:fillViewport="true"
android:padding="10px"
android:scrollbarStyle="outsideInset"
>
<LinearLayout
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v7.widget.Toolbar
android:id="@+id/main_toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:minHeight="?attr/actionBarSize"
app:theme="@style/ThemeOverlay.AppCompat.ActionBar" />
<TextView
android:id="@+id/textView1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Addressbook Settings"
android:textAppearance="?android:attr/textAppearanceLarge" />
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="@dimen/activity_vertical_margin"
android:layout_marginEnd="@dimen/activity_horizontal_margin"
android:layout_marginLeft="@dimen/activity_horizontal_margin"
android:layout_marginRight="@dimen/activity_horizontal_margin"
android:layout_marginStart="@dimen/activity_horizontal_margin"
android:layout_marginTop="@dimen/activity_vertical_margin"
android:fillViewport="true"
android:scrollbarStyle="outsideInset">
<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Subscriptions"
android:textAppearance="?android:attr/textAppearanceMedium" />
<EditText
android:id="@+id/subscriptions_content"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:ems="10"
android:inputType="textMultiLine"
android:maxLines="@integer/min_lines"
android:minLines="@integer/min_lines" >
<requestFocus />
</EditText>
<Button
android:id="@+id/button_save_subscriptions"
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Save subscriptions.txt" />
android:orientation="vertical">
</LinearLayout>
<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Subscriptions"
android:textAppearance="?android:attr/textAppearanceMedium" />
</ScrollView>
<EditText
android:id="@+id/subscriptions_content"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:ems="10"
android:inputType="textMultiLine">
<requestFocus />
</EditText>
<Button
android:id="@+id/button_save_subscriptions"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Save subscriptions.txt" />
</LinearLayout>
</ScrollView>
</LinearLayout>

View File

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/main_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent">
</FrameLayout>

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v7.widget.Toolbar
android:id="@+id/main_toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:minHeight="?attr/actionBarSize"
app:theme="@style/ThemeOverlay.AppCompat.ActionBar">
</android.support.v7.widget.Toolbar>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/main_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent">
</FrameLayout>
</LinearLayout>

View File

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v7.widget.Toolbar
android:id="@+id/main_toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:minHeight="?attr/actionBarSize"
app:theme="@style/ThemeOverlay.AppCompat.ActionBar">
</android.support.v7.widget.Toolbar>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:baselineAligned="false"
android:orientation="horizontal">
<!--
This layout is a two-pane layout for the master/detail
flow within a DrawerLayout. See res/values-large/refs.xml
and res/values-sw600dp/refs.xml for layout aliases
that replace the single-pane version of the layout with
this two-pane version.
-->
<!-- The main fragment view -->
<FrameLayout
android:id="@+id/main_fragment"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1" />
<!-- The detail fragment view -->
<FrameLayout
android:id="@+id/detail_fragment"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="2" />
</LinearLayout>
</LinearLayout>

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v7.widget.Toolbar
android:id="@+id/main_toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:minHeight="?attr/actionBarSize"
app:theme="@style/ThemeOverlay.AppCompat.ActionBar" />
<FrameLayout
android:id="@+id/content_wrapper"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
</LinearLayout>

View File

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/text"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="6dp"
android:textSize="16sp" >
</TextView>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/browser_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/list_vertical_padding"
android:paddingTop="@dimen/list_vertical_padding"
android:scrollbars="vertical" />

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
android:layout_height="match_parent">
<TextView
android:id="@+id/tunnel_name"
@ -17,16 +17,24 @@
android:id="@+id/tunnel_description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_below="@+id/tunnel_type"
android:layout_alignParentLeft="true"
android:layout_below="@+id/tunnel_name"
android:text="Tunnel description" />
<TextView
android:id="@+id/tunnel_details"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_below="@+id/tunnel_description"
android:text="Tunnel details" />
<TextView
android:id="@+id/tunnel_target_interface_port"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_below="@+id/tunnel_description"
android:layout_below="@+id/tunnel_type"
android:gravity="right"
android:text="Interface:port" />
@ -35,23 +43,15 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_below="@+id/tunnel_name"
android:layout_below="@+id/tunnel_details"
android:text="@string/i2ptunnel_view_type" />
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_below="@+id/textView2"
android:text="@string/i2ptunnel_view_desc" />
<TextView
android:id="@+id/tunnel_type"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_below="@+id/tunnel_name"
android:layout_below="@+id/tunnel_details"
android:text="Tunnel type" />
<TextView
@ -59,7 +59,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_below="@+id/textView1"
android:layout_below="@+id/textView2"
android:text="@string/i2ptunnel_view_target" />
<TextView

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="@+id/list_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<net.i2p.android.ext.floatingactionbutton.AddFloatingActionButton
android:id="@+id/promoted_action"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_marginBottom="@dimen/listitem_horizontal_margin"
android:layout_marginEnd="@dimen/listitem_horizontal_margin"
android:layout_marginRight="@dimen/listitem_horizontal_margin"
app:fab_colorNormal="@color/accent"
app:fab_colorPressed="@color/accent_dark" />
</RelativeLayout>

View File

@ -2,21 +2,26 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="10dp">
android:layout_marginBottom="@dimen/activity_vertical_margin"
android:layout_marginEnd="@dimen/activity_horizontal_margin"
android:layout_marginLeft="@dimen/activity_horizontal_margin"
android:layout_marginRight="@dimen/activity_horizontal_margin"
android:layout_marginStart="@dimen/activity_horizontal_margin"
android:layout_marginTop="@dimen/activity_vertical_margin">
<TextView
android:id="@+id/news_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_above="@+id/news_status"/>
android:layout_above="@+id/news_status"
android:layout_alignParentTop="true" />
<TextView
android:id="@+id/news_status"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="end"
android:layout_alignParentBottom="true"
android:gravity="end"
android:visibility="gone" />
</RelativeLayout>

View File

@ -0,0 +1,43 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="@dimen/listitem_height_one_line_avatar"
android:layout_marginEnd="@dimen/listitem_horizontal_margin"
android:layout_marginRight="@dimen/listitem_horizontal_margin">
<ImageView
android:id="@+id/browser_icon"
android:layout_width="@dimen/listitem_picture_size"
android:layout_height="@dimen/listitem_picture_size"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
android:layout_marginLeft="@dimen/listitem_horizontal_margin"
android:layout_marginStart="@dimen/listitem_horizontal_margin"
android:scaleType="fitCenter" />
<TextView
android:id="@+id/browser_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
android:layout_marginLeft="@dimen/listitem_text_left_margin"
android:layout_marginStart="@dimen/listitem_text_left_margin"
android:layout_toLeftOf="@+id/browser_status_icon"
android:layout_toStartOf="@+id/browser_status_icon"
android:textAppearance="@style/TextAppearance.AppCompat.Primary" />
<ImageView
android:id="@+id/browser_status_icon"
android:layout_width="@dimen/listitem_picture_size"
android:layout_height="@dimen/listitem_picture_size"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginLeft="@dimen/listitem_icon_left_margin"
android:layout_marginStart="@dimen/listitem_icon_left_margin"
android:scaleType="center"
android:visibility="gone" />
</RelativeLayout>

View File

@ -1,49 +1,81 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="5dp" >
android:layout_width="match_parent"
android:layout_height="@dimen/listitem_height_two_lines"
android:paddingEnd="@dimen/listitem_horizontal_margin"
android:paddingRight="@dimen/listitem_horizontal_margin">
<!-- The name of the tunnel -->
<TextView android:id="@+id/tunnel_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="3dp"
android:textSize="16sp"
<!-- Tunnel status -->
<ImageView
android:id="@+id/tunnel_status"
android:layout_width="@dimen/listitem_icon_size"
android:layout_height="@dimen/listitem_icon_size"
android:layout_alignParentLeft="true"
android:layout_marginRight="5dp"
android:text="Tunnel name" />
<!-- The type of tunnel -->
<TextView android:id="@+id/tunnel_type"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="@id/tunnel_name"
android:text="Tunnel type" />
<!-- Additional tunnel details -->
<TextView android:id="@+id/tunnel_details"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/tunnel_type"
android:text="Tunnel details" />
<!-- Interface:port the tunnel listens on or points to -->
<TextView android:id="@+id/tunnel_interface_port"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/tunnel_name"
android:layout_alignParentRight="true"
android:layout_alignTop="@id/tunnel_name"
android:gravity="right"
android:text="Interface:port" />
<!-- Status star -->
<ImageView android:id="@+id/tunnel_status"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
android:layout_marginLeft="@dimen/listitem_horizontal_margin"
android:layout_marginStart="@dimen/listitem_horizontal_margin"
android:contentDescription="Status" />
<!-- The name of the tunnel -->
<TextView
android:id="@+id/tunnel_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_marginLeft="@dimen/listitem_text_left_margin"
android:layout_marginStart="@dimen/listitem_text_left_margin"
android:layout_marginTop="@dimen/listitem_text_top_margin_two_lines"
android:text="Tunnel name"
android:textAppearance="@style/TextAppearance.AppCompat.Primary" />
<!-- Open link -->
<ImageView
android:id="@+id/tunnel_open"
android:layout_width="@dimen/listitem_icon_size"
android:layout_height="@dimen/listitem_icon_size"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginLeft="@dimen/listitem_horizontal_margin"
android:layout_marginStart="@dimen/listitem_horizontal_margin"
android:contentDescription="Open"
android:src="@drawable/ic_open_in_browser_white_24dp"
android:visibility="gone" />
<!-- Interface:port the tunnel listens on or points to -->
<TextView
android:id="@+id/tunnel_interface_port"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignTop="@id/tunnel_name"
android:layout_marginLeft="4dp"
android:layout_marginStart="4dp"
android:layout_toEndOf="@id/tunnel_name"
android:layout_toLeftOf="@id/tunnel_open"
android:layout_toRightOf="@id/tunnel_name"
android:layout_toStartOf="@id/tunnel_open"
android:ellipsize="start"
android:gravity="right"
android:maxLines="1"
android:text="Interface:port"
android:textAppearance="@style/TextAppearance.AppCompat.Secondary" />
<!-- The tunnel description -->
<TextView
android:id="@+id/tunnel_description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/tunnel_name"
android:layout_alignParentBottom="true"
android:layout_alignStart="@+id/tunnel_name"
android:layout_marginBottom="@dimen/listitem_text_bottom_margin_two_lines"
android:layout_toLeftOf="@id/tunnel_open"
android:layout_toStartOf="@id/tunnel_open"
android:ellipsize="end"
android:maxLines="1"
android:text="Tunnel description"
android:textAppearance="@style/TextAppearance.AppCompat.Secondary" />
</RelativeLayout>

View File

@ -1,24 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="5dp" >
android:layout_width="match_parent"
android:layout_height="@dimen/listitem_height_two_lines"
android:paddingEnd="@dimen/listitem_horizontal_margin"
android:paddingRight="@dimen/listitem_horizontal_margin">
<!-- The nickname of the LeaseSet -->
<TextView android:id="@+id/ls_nickname"
<TextView
android:id="@+id/ls_nickname"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="3dp"
android:textSize="16sp"
android:layout_alignParentLeft="true"
android:layout_marginRight="5dp"
android:text="LeaseSet nickname" />
android:layout_alignParentStart="true"
android:layout_marginLeft="@dimen/listitem_horizontal_margin"
android:layout_marginStart="@dimen/listitem_horizontal_margin"
android:layout_marginTop="@dimen/listitem_text_top_margin_two_lines"
android:text="LeaseSet nickname"
android:textAppearance="@style/TextAppearance.AppCompat.Primary" />
<!-- The hash of the LeaseSet -->
<TextView android:id="@+id/dbentry_hash"
<TextView
android:id="@+id/dbentry_hash"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="@id/ls_nickname"
android:text="LeaseSet hash" />
android:layout_alignLeft="@+id/ls_nickname"
android:layout_alignParentBottom="true"
android:layout_alignStart="@+id/ls_nickname"
android:layout_marginBottom="@dimen/listitem_text_bottom_margin_two_lines"
android:ellipsize="end"
android:maxLines="1"
android:text="LeaseSet hash"
android:textAppearance="@style/TextAppearance.AppCompat.Secondary" />
</RelativeLayout>

View File

@ -1,25 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="5dp" >
<!-- The hash of the RouterInfo -->
<TextView android:id="@+id/dbentry_hash"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="3dp"
android:textSize="16sp"
android:layout_alignParentLeft="true"
android:layout_marginRight="5dp"
android:text="RouterInfo hash" />
android:layout_width="match_parent"
android:layout_height="@dimen/listitem_height_one_line"
android:layout_marginEnd="@dimen/listitem_horizontal_margin"
android:layout_marginRight="@dimen/listitem_horizontal_margin">
<!-- Country flag -->
<ImageView android:id="@+id/ri_country"
<ImageView
android:id="@+id/ri_country"
android:layout_width="@dimen/listitem_icon_size"
android:layout_height="@dimen/listitem_icon_size"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
android:layout_marginLeft="@dimen/listitem_horizontal_margin"
android:layout_marginStart="@dimen/listitem_horizontal_margin"
android:contentDescription="Country"
android:visibility="gone" />
<!-- The hash of the RouterInfo -->
<TextView
android:id="@+id/dbentry_hash"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
android:contentDescription="Country" />
android:layout_marginLeft="@dimen/listitem_horizontal_margin"
android:layout_marginStart="@dimen/listitem_horizontal_margin"
android:ellipsize="marquee"
android:maxLines="1"
android:text="RouterInfo hash"
android:textAppearance="@style/TextAppearance.AppCompat.Primary" />
</RelativeLayout>

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/text"
android:layout_width="match_parent"
android:layout_height="@dimen/listitem_height_one_line"
android:gravity="center_vertical"
android:paddingEnd="@dimen/listitem_horizontal_margin"
android:paddingLeft="@dimen/listitem_horizontal_margin"
android:paddingRight="@dimen/listitem_horizontal_margin"
android:paddingStart="@dimen/listitem_horizontal_margin"
android:textAppearance="@style/TextAppearance.AppCompat.Primary" />

View File

@ -1,5 +0,0 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/menu_settings"
android:title="@string/menu_settings"
android:orderInCategory="100" />
</menu>

View File

@ -1,11 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:i2pandroid="http://schemas.android.com/apk/res-auto" >
<!-- Add, should appear as action buttons -->
<item android:id="@+id/action_add_to_addressbook"
android:title="@string/action_add"
android:icon="@drawable/ic_add_white_24dp"
i2pandroid:showAsAction="ifRoom" />
<!-- Settings, Help, should always be in the overflow -->
<item android:id="@+id/action_reload_subscriptions"
android:title="@string/action_reload_subscriptions"

View File

@ -1,10 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:i2pandroid="http://schemas.android.com/apk/res-auto" >
<item android:id="@+id/action_add_tunnel"
android:title="@string/action_add"
android:icon="@drawable/ic_add_white_24dp"
i2pandroid:showAsAction="ifRoom" />
<item android:id="@+id/action_start_all_tunnels"
android:title="@string/action_i2ptunnel_start_all"
i2pandroid:showAsAction="never" />

View File

@ -1,12 +1,8 @@
<html>
<head></head>
<body>
<h2>Pre-configured HTTP proxy</h2>
<p>The app starts an HTTP proxy at localhost port 4444. To use it, configure your browser's HTTP proxy setting to use localhost:4444.</p>
<p>The HTTP proxy is tested with the "Orweb" app. It should also work with Firefox 4 Mobile and the ProxyMob Firefox plugin, if you have at least 512 MB of RAM.</p>
<h2>Embedded web browser</h2>
<p>An embedded web browser is provided for convenience that will open .i2p addresses. However, it is not recommended for general use; users should download the Orweb browser, or Firefox Mobile and the ProxyMob Firefox plugin.</p>
<p>An embedded web browser is provided for convenience that will open .i2p addresses. However, it is not recommended for general use.</p>
<p>The browser does not use the outproxy for regular web sites. Javascript is disabled.</p>
<p>The following problems with eepsites are probably not fixable except on Android 3.0 (Honeycomb - i.e. tablets) and higher due to API limitations. The workaround is to use Firefox Mobile 4 and the ProxMob plugin (see below).</p>

View File

@ -1,6 +1,15 @@
<html>
<head></head>
<body>
<h2>What is I2PTunnel?</h2>
<p>Tunnels are the heart of I2P. All data inside the I2P network is sent through tunnels that hide the location of users. If an app has native I2P support, it will create its own tunnels.</p>
<p>I2PTunnel lets you create your own tunnels manually. This is useful for when you want to use an app that doesn't have native I2P support, like:</p>
<ul>
<li>A browser.</li>
<li>An IRC client.</li>
<li>A web server.</li>
</ul>
<h2>Using clients with pre-configured tunnels</h2>
<p>The app starts an HTTP proxy at localhost port 4444 and IRC client tunnels at localhost ports 6668 - 6672. The IRC clients are "shared clients" on the same tunnels. Once you see the tunnel icon turn green on the main console (several minutes after startup), you should be able to connect.</p>
@ -8,9 +17,10 @@
<ol>
<li>Port 6668: IRC2P - irc.postman.i2p, irc.freshcoffee.i2p, and irc.echelon.i2p</li>
<li>Port 6669: irc.welterde.i2p</li>
<li>Port 6670: irc.telecomix.i2p (probably down)</li>
<li>Port 6671: irc.killyourtv.i2p</li>
<li>Port 6672: Nameless IRC - irc.stream.i2p</li>
<li>Port 6670: irc.killyourtv.i2p</li>
</ol>
<h2>What does the clock icon on a yellow background mean?</h2>
<p>When a tunnel's indicator is yellow with a clock icon, the tunnel is in standby mode. This means that I2P has not built the tunnel yet, but will do so automatically when you start using it. This helps to minimize resource use and conserve battery life.</p>
</body>
</html>

View File

@ -0,0 +1,11 @@
<html>
<head></head>
<body>
<h2>How to configure Orweb:</h2>
<ol>
<li>Open Orweb's settings menu.</li>
<li>Change the "Proxy Port" to <code>4444</code>.</li>
<li>Exit Orweb using the back button, then open it again.</li>
</ol>
</body>
</html>

View File

@ -0,0 +1,11 @@
<html>
<head></head>
<body>
<h2>How to configure Orfox:</h2>
<ol>
<li>Type <code>about:config</code> into the URL bar.</li>
<li>Search for <code>network.proxy.http</code>.</li>
<li>Change the value of <code>network.proxy.http_port</code> to <code>4444</code>.</li>
</ol>
</body>
</html>

View File

@ -7,5 +7,10 @@
<h2>How do I use it?</h2>
<p>If you want to view I2P sites, see the "Browser configuration" help category.</p>
<p>With this app installed, other apps that are designed for I2P will use it automatically.</p>
<h2>Pre-configured HTTP proxy</h2>
<p>The app starts an HTTP proxy at localhost port 4444. To use it, configure your browser's HTTP proxy setting to use localhost:4444.</p>
<p>The HTTP proxy is tested with the "Orweb" app. It should also work with Firefox 4 Mobile and the ProxyMob Firefox plugin, if you have at least 512 MB of RAM.</p>
<p>See the "Browser configuration" help page for more info.</p>
</body>
</html>

View File

@ -0,0 +1,12 @@
<html>
<head></head>
<body>
<h2>How to configure Firefox:</h2>
<ol>
<li>Type <code>about:config</code> into the URL bar.</li>
<li>Search for <code>network.proxy.http</code>.</li>
<li>Change the value of <code>network.proxy.http</code> to <code>localhost</code>.</li>
<li>Change the value of <code>network.proxy.http_port</code> to <code>4444</code>.</li>
</ol>
</body>
</html>

View File

@ -0,0 +1,9 @@
<html>
<head></head>
<body>
<h2>This browser is unknown</h2>
<p>We have not tested this browser with I2P, so we don't know anything about it.</p>
<p>But if this browser supports proxies, it will work with I2P.</p>
<p>Configure this browser's HTTP proxy setting to use <code>localhost:4444</code>.</p>
</body>
</html>

View File

@ -0,0 +1,7 @@
<html>
<head></head>
<body>
<h2>Sorry, this browser is unsupported</h2>
<p>This browser can't be used with I2P.</p>
</body>
</html>

View File

@ -27,7 +27,7 @@ tunnel.0.startOnLoad=true
# irc
tunnel.1.name=Irc2P
tunnel.1.description=IRC tunnel to access the Irc2P network
tunnel.1.description=IRC tunnel to the Irc2P network
tunnel.1.type=ircclient
tunnel.1.sharedClient=true
tunnel.1.interface=127.0.0.1
@ -52,7 +52,7 @@ tunnel.1.startOnLoad=true
# irc
tunnel.2.name=IRC welterde
tunnel.2.description=IRC tunnel to access welterde's network
tunnel.2.description=IRC tunnel to welterde's network
tunnel.2.type=ircclient
tunnel.2.sharedClient=true
tunnel.2.interface=127.0.0.1
@ -73,14 +73,14 @@ tunnel.2.option.outbound.length=2
tunnel.2.option.outbound.lengthVariance=0
tunnel.2.startOnLoad=true
# irc
tunnel.3.name=Telecomix IRC
tunnel.3.description=IRC tunnel to access the Telecomix network
# irc irc.killyourtv.i2p
tunnel.3.name=KYTV IRC
tunnel.3.description=IRC tunnel to KillYourTV's network
tunnel.3.type=ircclient
tunnel.3.sharedClient=true
tunnel.3.interface=127.0.0.1
tunnel.3.listenPort=6670
tunnel.3.targetDestination=irc.telecomix.i2p
tunnel.3.targetDestination=irc.killyourtv.i2p
tunnel.3.i2cpHost=127.0.0.1
tunnel.3.i2cpPort=7654
tunnel.3.option.inbound.nickname=shared clients
@ -94,50 +94,4 @@ tunnel.3.option.inbound.length=2
tunnel.3.option.inbound.lengthVariance=0
tunnel.3.option.outbound.length=2
tunnel.3.option.outbound.lengthVariance=0
tunnel.3.startOnLoad=true
# irc irc.killyourtv.i2p
tunnel.4.name=KYTV IRC
tunnel.4.description=IRC tunnel to access KillYourTV's network
tunnel.4.type=ircclient
tunnel.4.sharedClient=true
tunnel.4.interface=127.0.0.1
tunnel.4.listenPort=6671
tunnel.4.targetDestination=irc.killyourtv.i2p
tunnel.4.i2cpHost=127.0.0.1
tunnel.4.i2cpPort=7654
tunnel.4.option.inbound.nickname=shared clients
tunnel.4.option.outbound.nickname=shared clients
tunnel.4.option.i2cp.delayOpen=true
tunnel.4.option.i2cp.reduceIdleTime=600000
tunnel.4.option.i2cp.reduceOnIdle=true
tunnel.4.option.i2cp.reduceQuantity=1
tunnel.4.option.i2p.streaming.connectDelay=1000
tunnel.4.option.inbound.length=2
tunnel.4.option.inbound.lengthVariance=0
tunnel.4.option.outbound.length=2
tunnel.4.option.outbound.lengthVariance=0
tunnel.4.startOnLoad=true
# irc irc.stream.i2p
tunnel.5.name=Nameless IRC
tunnel.5.description=IRC tunnel to access the Nameless network
tunnel.5.type=ircclient
tunnel.5.sharedClient=true
tunnel.5.interface=127.0.0.1
tunnel.5.listenPort=6672
tunnel.5.targetDestination=irc.stream.i2p
tunnel.5.i2cpHost=127.0.0.1
tunnel.5.i2cpPort=7654
tunnel.5.option.inbound.nickname=shared clients
tunnel.5.option.outbound.nickname=shared clients
tunnel.5.option.i2cp.delayOpen=true
tunnel.5.option.i2cp.reduceIdleTime=600000
tunnel.5.option.i2cp.reduceOnIdle=true
tunnel.5.option.i2cp.reduceQuantity=1
tunnel.5.option.i2p.streaming.connectDelay=1000
tunnel.5.option.inbound.length=2
tunnel.5.option.inbound.lengthVariance=0
tunnel.5.option.outbound.length=2
tunnel.5.option.outbound.lengthVariance=0
tunnel.5.startOnLoad=true
tunnel.3.startOnLoad=true

View File

@ -1,2 +1 @@
irc.welterde.i2p=qv0mnQG0CqKM0b4613~8rOKBLA9ZQLCdU0Iiz6Ou8eszJjvjNCHTaa-Rcorz50~7zMu8Lh~OYplf2JatBhWirTsmbVRlOxtAvqYl0oAfY1bUpUu9AeU9wfgj806jw0vIO6JNDpSiRRhGL6HHYLqDvqvE4JgFFpMjF30dIdBxCGsVa1EbwlUUCpgZV1Psl45l~1wkMJ7NsSglHy46l5m9uYXNxu-NERrMN0~mGxnFsAllJZZCKixFQY-mDDiEMksCF7aNueTm~SknvrVQIue9jVf5lZVvxPSmKuRIEGL3bAC-IF3Jhv0NEhuxAYpzKBT1yMupJficIHhcqwk-iUHNnUqgEH8MRQM4SrrcGeBvwZ-daQVOv~ujLijiFl4QrrNLzArgYOxRZMO1Jz3kAgWxULw3RNiszmIcuxYvGT4z7e5YeuroejyE1ExMis-3JBmbjrd2kOKWX5LqgMeAkDjYIsI8QPigxLbC3l7Y5tbyrZA0t~vvOU--2wP6Kg5rb7r1AAAA
irc.telecomix.i2p=ogLZQpnNgs514P0hp-vwPU3iHhKUymyotVxyX7fC8-a4dFAUXx~HUR0ezvkb3RVI3Snvh~yl7QJHzs3hIy2jjZmo~rlZLmtpEVgu1IvrMYusR3KQZ-1Tdfr3JftxA~dr3vmmro3hIhR18xRWA87A~y2VyEGGw4how-EEYS~VT6hnxoJ4FQztvQF0in2A70fCQ1obVYD3lBL~Jn9VV-~tgjohOZHSkIA4yCD80~QfhHa0g4GqJRgQry5fEjAvc1h5owsNyQ8siU3NfldvTd4Tj~dRuD3F91Svk6Wepp~IbPyIKgWPDGWW3RQWFoyDyHjwLI8IdPg0Io8Q4oRgTcA4JJaaHop2WzV7E-thM41h8evo~jO-XDzfW0DFtFTRRK7use5cYLbNlRXVlHQCe7qHALYi3JkH6wBsW5o8irHFMiGYe-YmGEwVRRQ0p2j-tRVJC4jYEOTSTO2Fr~hAUxramtah9wKOd05bSIOYxQxb0~0fGsw3gDMBCZW8PrhFUn3LAAAA

View File

@ -118,6 +118,7 @@
<string name="about_volunteer">Du willst mithelfen, die App besser zu machen? Dann schau in das Android forum:</string>
<string name="about_donate">Wenn du Geld oder Bitcoins spenden wilst, damit wir mehr Android-Geräte zum Testen kaufen können, dann schau auf:</string>
<string name="menu_help">Hilfe</string>
<string name="general">Allgemein</string>
<string name="addressbook_search_header">%s gefunden</string>
<string name="addressbook_add_wizard_k_name">Name</string>
<string name="addressbook_add_wizard_k_destination">Ziel</string>

View File

@ -118,6 +118,7 @@
<string name="about_volunteer">¿Quiere ayudar a hacer mejor la aplicación? Haga de voluntario en el foro de Android:</string>
<string name="about_donate">¿Quiere donar dinero o bitcoins para la compra de más dispositivos Android para el desarrollo y testeo? Vaya a:</string>
<string name="menu_help">Ayuda</string>
<string name="general">General</string>
<string name="addressbook_search_header">%s encontrados</string>
<string name="addressbook_add_wizard_k_name">Nombre</string>
<string name="addressbook_add_wizard_k_destination">Destino</string>

View File

@ -25,7 +25,9 @@
<string name="button_router_off">Presser longtemps pour démarrer I2P</string>
<string name="button_router_on">I2P est en marche (presser longtemps pour arrêter)</string>
<!--Character to indicate a client tunnel. Usually first letter of the word "client".-->
<string name="char_client_tunnel">C</string>
<!--Character to indicate a server tunnel. Usually first letter of the word "server".-->
<string name="char_server_tunnel">S</string>
<string name="no_client_tunnels_running">Aucun tunnel de client n\'est encore en marche.</string>
<string name="configure_browser_title">Configurer le navigateur ?</string>
<string name="configure_browser_for_i2p">Voudriez-vous configurer un navigateur pour voir les sites d\'I2P ? (vous pouvez aussi faire cela plus tard depuis le menu d\'aide).</string>
@ -116,6 +118,7 @@
<string name="about_volunteer">Vous souhaitez aider à améliorer l\'application ? Devenez volontaire sur le forum Android :</string>
<string name="about_donate">Vous souhaitez faire un don d\'argent ou de bitcoins pour acheter davantage d\'équipements Android pour les développements et les tests ? Allez sur :</string>
<string name="menu_help">Aide</string>
<string name="general">Général</string>
<string name="addressbook_search_header">%s trouvé</string>
<string name="addressbook_add_wizard_k_name">Nom</string>
<string name="addressbook_add_wizard_k_destination">Destination</string>

View File

@ -118,6 +118,7 @@
<string name="about_volunteer">이 앱을 개선시키고 싶나요? 안드로이드 포럼에서 기여하세요:</string>
<string name="about_donate">돈이나 비트코인 기부로 개발과 테스팅에 필요한 안드로이드 기기 구입을 돕고 싶나요? 참조하세요:</string>
<string name="menu_help">도움말</string>
<string name="general">일반</string>
<string name="addressbook_search_header">%s 찾음</string>
<string name="addressbook_add_wizard_k_name">이름</string>
<string name="addressbook_add_wizard_k_destination">목적지</string>
@ -158,6 +159,8 @@
<string name="i2ptunnel_wizard_k_outproxies">나가는 프록시</string>
<string name="i2ptunnel_wizard_k_target_host">목표 호스트</string>
<string name="i2ptunnel_wizard_k_target_port">목표 포트</string>
<string name="i2ptunnel_wizard_k_reachable_on">접근가능</string>
<string name="i2ptunnel_wizard_k_binding_port">바인드 포트</string>
<string name="i2ptunnel_wizard_k_auto_start">자동 시작</string>
<string name="next">다음</string>
<string name="prev">이전</string>
@ -171,6 +174,7 @@
<string name="i2ptunnel_wizard_desc_target_host">서비스가 작동중인 IP, 대부분의 경우 같은 기기이기 때문에 127.0.0.1이 자동 입력됨.</string>
<string name="i2ptunnel_wizard_desc_target_port">서비스가 접속을 받아들일 포트.</string>
<string name="i2ptunnel_wizard_desc_reachable_on">이 터널을 접근할 수 있는 컴퓨터 혹은 스마트폰 제한.</string>
<string name="i2ptunnel_wizard_desc_binding_port">이 포트는 로컬에서 접근될 클라이언트 터널입니다. 또한 bidir 서버 터널의 클라이언트 포트이기도 합니다.</string>
<string name="i2ptunnel_wizard_desc_auto_start">라우터가 시작할때 터널도 같이 실행?</string>
<string name="i2ptunnel_wizard_submit_confirm_message">터널을 만들까요?</string>
<string name="i2ptunnel_wizard_submit_confirm_button">터널 </string>

View File

@ -25,7 +25,12 @@
<string name="button_router_off">Hold inne kappen for å starte I2P</string>
<string name="button_router_on">I2P kjører (hold inne knappen for å stoppe)</string>
<!--Character to indicate a client tunnel. Usually first letter of the word "client".-->
<string name="char_client_tunnel">K</string>
<!--Character to indicate a server tunnel. Usually first letter of the word "server".-->
<string name="char_server_tunnel">T</string>
<string name="no_client_tunnels_running">Foreløpig kjører ingen klient-tunneler</string>
<string name="configure_browser_title">Sett opp nettleser?</string>
<string name="configure_browser_for_i2p">Vil du sette opp nettleseren for visning av I2P-sider? (Du kan også gjøre dette senere fra hjelpemenyen.)</string>
<string name="first_start_title">Til lykke med ny installasjon av I2P!</string>
<string name="first_start_welcome"><b> Velkommen til I2P</b> Vennligst <b>ha tålmodighet</b> mens I2P starter opp og finner likemenn.</string>
<string name="first_start_read">Mens du venter, vennligst les versjons-notatene og velkomstsiden.</string>
@ -104,6 +109,7 @@
<string name="settings_label_expl_backupQuantity">Sikkerhetskopi-mengde</string>
<string name="settings_summ_expl_backupQuantity">%s tunneler</string>
<string name="settings_desc_expl_backupQuantity">Hvor mange reservetunneler</string>
<string name="settings_router_restart_required">Gjør en omstart av I2P for å utføre endringer</string>
<string name="menu_about">Om</string>
<string name="about_version">Versjon:</string>
<string name="about_project">Prosjekts-heim:</string>
@ -112,6 +118,7 @@
<string name="about_volunteer">Vil du gjøre dette programmet bedre? Meld deg som frivillig på Android-forumet:</string>
<string name="about_donate">Vil du donere penger eller bitcoin øremerket flere Android-enheter til utvikling og testformål? Gå til:</string>
<string name="menu_help">Hjelp</string>
<string name="general">Generelt</string>
<string name="addressbook_search_header">%s funnet</string>
<string name="addressbook_add_wizard_k_name">Navn</string>
<string name="addressbook_add_wizard_k_destination">Mål-katalog</string>
@ -176,4 +183,10 @@
<string name="i2ptunnel_view_target">Mål:</string>
<string name="i2ptunnel_view_access_point">Tilknytningspunkt:</string>
<string name="i2ptunnel_view_autostart">Auto-start</string>
<string name="copy_logs">Kopier loggførsel</string>
<string name="i2p_android_error_logs">Loggføring av feil for Android I2P</string>
<string name="i2p_android_logs">Loggfiler for Android I2P</string>
<string name="error_logs_copied_to_clipboard">Utklippstavle for feil-logg</string>
<string name="logs_copied_to_clipboard">Utklippstavle for loggføringer</string>
<string name="label_browser_configuration">Oppsett av nettleser</string>
</resources>

View File

@ -4,7 +4,7 @@
<string name="desc_i2p_logo">Emblema I2P</string>
<string name="welcome_new_install">Bine ati venit la I2P! Aceasta aplicatie este un software ALPHA și nu oferă anonimatul puternic. Vă rugăm să citiți notele de lansare și licență.</string>
<string name="welcome_new_version">Noua versiune instalată. Vă rugăm să citiți notele de lansare. versiune:</string>
<string name="label_home">Stare si Controale</string>
<string name="label_home">Controale și stare</string>
<string name="label_tunnels">Tuneluri</string>
<string name="label_status">Stare</string>
<string name="label_addressbook">Agendă</string>
@ -25,8 +25,16 @@
<string name="button_router_off">Apasari lung pentru a porni I2P</string>
<string name="button_router_on">I2P ruleaza (tineti apasat pentru a oprii)</string>
<!--Character to indicate a client tunnel. Usually first letter of the word "client".-->
<string name="char_client_tunnel">C</string>
<!--Character to indicate a server tunnel. Usually first letter of the word "server".-->
<string name="char_server_tunnel">S</string>
<string name="configure_browser_title">Configurați navigatorul web?</string>
<string name="configure_browser_for_i2p">Doriți să configurați un navigator web să vizualizați site-uri I2P? (Puteți face acest lucru mai târziu din meniul ajutor.)</string>
<string name="first_start_title">Felicitari pentru instalarea I2P!</string>
<string name="first_start_read">Cât timp așteptați, citiți notele de lansare și pagina de bun venit.</string>
<string name="first_start_faq_nonanon">Sau utilizați acest link ne-anonim dacă nu doriți să așteptați pentru tuneluri:</string>
<string name="drawer_open">Deschide nav</string>
<string name="drawer_close">Închide nav</string>
<string name="action_search">Cauta</string>
<string name="action_add">Adaugă</string>
<string name="action_edit">Editeaza</string>
@ -47,6 +55,7 @@
<string name="graphs_not_ready">Graficele nu sunt gata, sau ruterul nu rulează. Încercați mai târziu.</string>
<string name="netdb_routers_empty">Nu sunt rutere în NetDB.</string>
<string name="notification_status_bw">Lățime de bandă: %1$s KBps desc / %2$s KBps în</string>
<string name="notification_status_peers">Parteneri: %1$d activi, %2$d cunoscuți</string>
<string name="menu_settings">Configurări</string>
<string name="settings_enable">Activează</string>
<string name="settings_desc_subscriptions">URLs de abonare:</string>
@ -88,6 +97,7 @@
<string name="settings_label_expl_backupQuantity">Cantitatea de rezervă</string>
<string name="settings_summ_expl_backupQuantity">%s tuneluri</string>
<string name="settings_desc_expl_backupQuantity">Câți copii de rezervă tunel</string>
<string name="settings_router_restart_required">Reporniți I2P pentru aplicarea modificărilor</string>
<string name="menu_about">Despre</string>
<string name="about_version">Versiune:</string>
<string name="about_bugs">Defecte și suport:</string>
@ -95,16 +105,33 @@
<string name="about_volunteer">Doriți să faceți aplicația mai bună? Voluntari pe forumul Android:</string>
<string name="about_donate">Doriți să donați bani sau bitcoins pentru cumpărarea de mai multe dispozitive Android pentru dezvoltare și testare? Mergeți la:</string>
<string name="menu_help">Ajutor</string>
<string name="general">General</string>
<string name="addressbook_search_header">%s gasit</string>
<string name="addressbook_add_wizard_k_name">Nume</string>
<string name="addressbook_add_wizard_k_destination">Destinatie</string>
<string name="addressbook_add_wizard_desc_name">Numele</string>
<string name="nsu_iae_illegal_char">Numele gazdă \"%1$s\" conține caractere ilegale %2$s</string>
<string name="nsu_iae_cannot_start_with">Numele gazdă nu poate începe cu \"%s\"</string>
<string name="nsu_iae_cannot_end_with">Numele gazdă nu se poate termina cu \"%s\"</string>
<string name="nsu_iae_cannot_contain">Numele gazdă nu poate conține \"%s\"</string>
<string name="nsu_iae_requires_conversion">Numele gazdă \"%s\" necesită conversia la ASCII dar biblioteca de conversie nu este disponibilă în versiunea Android</string>
<string name="i2ptunnel_type_client">Client standard</string>
<string name="i2ptunnel_type_httpclient">Client HTTP</string>
<string name="i2ptunnel_type_ircclient">Client IRC</string>
<string name="i2ptunnel_type_server">Server standard</string>
<string name="i2ptunnel_type_httpserver">HTTP server</string>
<string name="i2ptunnel_type_sockstunnel">SOCKS 4/4a/5 proxy</string>
<string name="i2ptunnel_type_socksirctunnel">SOCKS IRC proxy</string>
<string name="i2ptunnel_type_ircserver">Server IRC</string>
<string name="i2ptunnel_new_tunnel">Tunel nou</string>
<string name="i2ptunnel_msg_config_saved">Modificările configurării s-au salvat</string>
<string name="i2ptunnel_msg_config_save_failed">A eșuat salvarea configurării</string>
<string name="i2ptunnel_msg_tunnel_starting">Se pornește tunelul</string>
<string name="i2ptunnel_msg_tunnel_stopping">Se oprește tunelul</string>
<string name="i2ptunnel_delete_confirm_message">Se șterge tunelul?</string>
<string name="i2ptunnel_delete_confirm_button">Șterge tunelul</string>
<string name="i2ptunnel_wizard_k_client_server">Client sau server</string>
<string name="i2ptunnel_wizard_k_type">Tip tunel</string>
<string name="i2ptunnel_wizard_k_name">Nume</string>
<string name="i2ptunnel_wizard_k_desc">Descriere</string>
<string name="i2ptunnel_wizard_k_dest">Destinatie</string>
@ -113,6 +140,12 @@
<string name="i2ptunnel_wizard_k_auto_start">Auto pornire</string>
<string name="next">Urmatorul</string>
<string name="prev">Anteriorul</string>
<string name="finish">Trimite</string>
<string name="enabled">Activat</string>
<string name="i2ptunnel_wizard_desc_name">Numele tunelului, pentru identificare în lista tunelurilor.</string>
<string name="i2ptunnel_wizard_desc_desc">O descriere a tunelului. Este facultativ și pur informativ.</string>
<string name="i2ptunnel_wizard_desc_reachable_on">Aceasta limitează ce computere sau smartphone-uri pot accesa acest tunel.</string>
<string name="i2ptunnel_wizard_desc_auto_start">Ar trebui ca tunelul să pornească automat când ruterul pornește?</string>
<string name="i2ptunnel_wizard_submit_confirm_message">Se creează tunelul?</string>
<string name="i2ptunnel_wizard_submit_confirm_button">Creare tunel</string>
<string name="i2ptunnel_view_type">Tip:</string>
@ -120,4 +153,10 @@
<string name="i2ptunnel_view_target">Tinta:</string>
<string name="i2ptunnel_view_access_point">Punct de acces:</string>
<string name="i2ptunnel_view_autostart">Auto pornire</string>
<string name="copy_logs">Copiază jurnale</string>
<string name="i2p_android_error_logs">Jurnale eroare I2P Android</string>
<string name="i2p_android_logs">Jurnale I2P Android</string>
<string name="error_logs_copied_to_clipboard">Jurnalele de eroare sunt copiate în memoria temporară</string>
<string name="logs_copied_to_clipboard">Jurnalele sunt copiate în memoria temporară</string>
<string name="label_browser_configuration">Configurare navigator web</string>
</resources>

View File

@ -118,6 +118,7 @@
<string name="about_volunteer">Хотите помочь улучшить приложение? Добровольцы на Android форуме:</string>
<string name="about_donate">Хотите пожертвовать деньги или bitcoins на покупку дополнительных Android устройств для разработчиков и тестировщиков? Зайдите:</string>
<string name="menu_help">Справка</string>
<string name="general">Общие</string>
<string name="addressbook_search_header">%s найдено</string>
<string name="addressbook_add_wizard_k_name">Имя</string>
<string name="addressbook_add_wizard_k_destination">Пункт назначения</string>

View File

@ -1,4 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<item name="activity_navdrawer" type="layout">@layout/activity_navdrawer_twopane</item>
<item name="activity_help" type="layout">@layout/activity_help_twopane</item>
</resources>

View File

@ -118,6 +118,7 @@
<string name="about_volunteer">想帮助让应用程序变得更好吗成为Android 论坛志愿者:</string>
<string name="about_donate">想捐钱或比特币来为开发和测试购买更多Android 设备吗?转到:</string>
<string name="menu_help">帮助</string>
<string name="general">常规</string>
<string name="addressbook_search_header">%s 找到</string>
<string name="addressbook_add_wizard_k_name">名称</string>
<string name="addressbook_add_wizard_k_destination">目的地</string>

View File

@ -51,9 +51,29 @@
<item>2</item>
</string-array>
<string-array name="help_categories">
<item>@string/app_name</item>
<item>@string/general</item>
<item>@string/label_browser_configuration</item>
<item>@string/label_addressbook</item>
<item>@string/label_i2ptunnel</item>
</string-array>
<string-array name="recommended_browsers">
<item>info.guardianproject.browser</item>
</string-array>
<string-array name="recommended_browser_labels">
<item>Orweb</item>
</string-array>
<string-array name="supported_browsers">
<item>org.mozilla.firefox</item>
</string-array>
<string-array name="supported_browser_labels">
<item>Firefox</item>
</string-array>
<string-array name="unsupported_browsers">
<item>com.android.chrome</item>
<item>com.android.browser</item>
<item>com.sec.android.app.sbrowser</item>
<item>acr.browser.lightning</item>
<item>mobi.mgeek.TunnyBrowser</item>
<item>com.lastpass.lpandroid</item>
</string-array>
</resources>

View File

@ -1,7 +1,8 @@
<resources>
<color name="primary">#673ab7</color>
<color name="primary_dark">#512da8</color>
<color name="accent">#ff6e40</color>
<color name="primary">#673ab7</color><!-- Deep Purple 500 -->
<color name="primary_dark">#512da8</color><!-- Deep Purple 700 -->
<color name="accent">#ff6e40</color><!-- Deep Orange A200 -->
<color name="accent_dark">#ff3d00</color><!-- Deep Orange A400 -->
<color name="indicator_red">#ffff0000</color>
<color name="indicator_yellow">#ffffff00</color>

View File

@ -6,6 +6,23 @@
<dimen name="nav_horizontal_margin">16dp</dimen>
<dimen name="nav_entry_height">48dp</dimen>
<dimen name="text_size_primary">16sp</dimen>
<dimen name="text_size_secondary">14sp</dimen>
<dimen name="list_vertical_padding">8dp</dimen>
<dimen name="listitem_horizontal_margin">16dp</dimen>
<dimen name="listitem_picture_size">40dp</dimen>
<dimen name="listitem_icon_size">24dp</dimen>
<dimen name="listitem_text_left_margin">72dp</dimen>
<dimen name="listitem_icon_left_margin">8dp</dimen>
<dimen name="listitem_height_one_line">48dp</dimen>
<dimen name="listitem_height_one_line_avatar">56dp</dimen>
<dimen name="listitem_height_two_lines">72dp</dimen>
<dimen name="listitem_text_top_margin_two_lines">16dp</dimen>
<dimen name="listitem_text_bottom_margin_two_lines">18dp</dimen>
<dimen name="tunnel_indicator">20dp</dimen>
<dimen name="step_pager_tab_width">32dp</dimen>

View File

@ -1,4 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<item name="activity_navdrawer" type="layout">@layout/activity_navdrawer_onepane</item>
<item name="activity_help" type="layout">@layout/activity_help_onepane</item>
</resources>

View File

@ -138,6 +138,7 @@
<string name="url_donate" translatable="false">https://geti2p.net/en/donate | http://i2p-projekt.i2p/en/donate</string>
<string name="menu_help">Help</string>
<string name="general">General</string>
<string name="addressbook_search_header">%s found</string>

View File

@ -19,6 +19,16 @@
<!-- The rest of your attributes -->
</style>
<style name="TextAppearance.AppCompat.Primary" parent="TextAppearance.AppCompat.Body1">
<item name="android:textColor">@color/primary_text_default_material_dark</item>
<item name="android:textSize">@dimen/text_size_primary</item>
</style>
<style name="TextAppearance.AppCompat.Secondary" parent="TextAppearance.AppCompat.Body1">
<item name="android:textColor">@color/secondary_text_default_material_dark</item>
<item name="android:textSize">@dimen/text_size_secondary</item>
</style>
<style name="WizardPageContainer">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">match_parent</item>

View File

@ -11,6 +11,7 @@ import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import net.i2p.android.lib.client.R;
import net.i2p.android.router.service.IRouterState;
@ -26,6 +27,10 @@ public class I2PAndroidHelper {
public static final int REQUEST_START_I2P = 9857;
private static final String ROUTER_SERVICE_CLASS = "net.i2p.android.router.service.RouterService";
private static final String LOG_TAG = "I2PClientLib";
private Context mContext;
private boolean mTriedBindState;
private IRouterState mStateService;
@ -39,17 +44,69 @@ public class I2PAndroidHelper {
* {@link android.app.Activity#onStart()}.
*/
public void bind() {
Intent i2pIntent = new Intent(IRouterState.class.getName());
try {
mTriedBindState = mContext.bindService(
i2pIntent, mStateConnection, Context.BIND_AUTO_CREATE);
} catch (SecurityException e) {
// Old version of I2P Android (pre-0.9.13), cannot use
mStateService = null;
mTriedBindState = false;
Log.i(LOG_TAG, "Binding to I2P Android");
Intent i2pIntent = getI2PAndroidIntent();
if (i2pIntent != null) {
Log.i(LOG_TAG, i2pIntent.toString());
try {
mTriedBindState = mContext.bindService(
i2pIntent, mStateConnection, Context.BIND_AUTO_CREATE);
if (!mTriedBindState)
Log.w(LOG_TAG, "Could not bind: bindService failed");
} catch (SecurityException e) {
// Old version of I2P Android (pre-0.9.13), cannot use
mStateService = null;
mTriedBindState = false;
Log.w(LOG_TAG, "Could not bind: I2P Android version is too old");
}
} else
Log.w(LOG_TAG, "Could not bind: I2P Android not installed");
}
/**
* Try to bind to I2P Android, using the provided ServiceConnection and
* flags. Call this method from
* {@link android.app.Service#onStartCommand(android.content.Intent, int, int)}.
* The ServiceConnection will be provided with an {@link android.os.IBinder}
* that can be converted to an
* {@link net.i2p.android.router.service.IRouterState} with
* <code>IRouterState.Stub.asInterface(IBinder)</code>.
*/
public boolean bind(ServiceConnection serviceConnection, int flags) {
Log.i(LOG_TAG, "Binding to I2P Android with provided ServiceConnection");
Intent i2pIntent = getI2PAndroidIntent();
if (i2pIntent != null) {
Log.i(LOG_TAG, i2pIntent.toString());
try {
boolean rv = mContext.bindService(
i2pIntent, serviceConnection, flags);
if (!rv)
Log.w(LOG_TAG, "Could not bind: bindService failed");
return rv;
} catch (SecurityException e) {
// Old version of I2P Android (pre-0.9.13), cannot use
Log.w(LOG_TAG, "Could not bind: I2P Android version is too old");
return false;
}
} else {
Log.w(LOG_TAG, "Could not bind: I2P Android not installed");
return false;
}
}
private Intent getI2PAndroidIntent() {
Intent intent = new Intent(IRouterState.class.getName());
if (isAppInstalled(URI_I2P_ANDROID))
intent.setClassName(URI_I2P_ANDROID, ROUTER_SERVICE_CLASS);
else if (isAppInstalled(URI_I2P_ANDROID_DONATE))
intent.setClassName(URI_I2P_ANDROID_DONATE, ROUTER_SERVICE_CLASS);
else if (isAppInstalled(URI_I2P_ANDROID_LEGACY))
intent.setClassName(URI_I2P_ANDROID_LEGACY, ROUTER_SERVICE_CLASS);
else
intent = null;
return intent;
}
/**
* Unbind from I2P Android. Call this method from
* {@link android.app.Activity#onStop()}.
@ -75,6 +132,7 @@ public class I2PAndroidHelper {
/**
* Check if I2P Android is installed.
*
* @return true if I2P Android is installed, false otherwise.
*/
public boolean isI2PAndroidInstalled() {
@ -97,6 +155,7 @@ public class I2PAndroidHelper {
/**
* Show dialog - install I2P Android from market or F-Droid.
*
* @param activity the Activity this method has been called from.
*/
public void promptToInstall(final Activity activity) {
@ -121,6 +180,7 @@ public class I2PAndroidHelper {
/**
* Check if I2P Android is running. If {@link net.i2p.android.ui.I2PAndroidHelper#bind()}
* has not been called previously, this will always return false.
*
* @return true if I2P Android is running, false otherwise.
*/
public boolean isI2PAndroidRunning() {
@ -137,6 +197,7 @@ public class I2PAndroidHelper {
/**
* Show dialog - request that I2P Android be started.
*
* @param activity the Activity this method has been called from.
*/
public void requestI2PAndroidStart(final Activity activity) {

View File

@ -0,0 +1,9 @@
<?xml version='1.0' encoding='UTF-8'?>
<resources>
<string name="yes"></string>
<string name="no">아니요</string>
<string name="install_i2p_android">안드로이드 I2P를 설치할까요?</string>
<string name="you_must_have_i2p_android">안드로이드 I2P가 설치되고 작동 되어야 합니다. 설치하시겠습니까?</string>
<string name="start_i2p_android">안드로이드 I2P를 시작할까요?</string>
<string name="would_you_like_to_start_i2p_android">안드로이드 I2P가 작동중이 아닌것 같습니다. 시작할까요?</string>
</resources>

View File

@ -0,0 +1,9 @@
<?xml version='1.0' encoding='UTF-8'?>
<resources>
<string name="yes">Da</string>
<string name="no">Nu</string>
<string name="install_i2p_android">Instalați I2P Android?</string>
<string name="you_must_have_i2p_android">Trebuie să aveți instalat și să ruleze I2P Android. Doriți să îl instalați?</string>
<string name="start_i2p_android">Porniți I2P Android?</string>
<string name="would_you_like_to_start_i2p_android">Apare că I2P Android nu rulează. Doriți să îl porniți?</string>
</resources>

View File

@ -1,4 +1,4 @@
VERSION_NAME=0.3
VERSION_NAME=0.4
GROUP=net.i2p.android
POM_URL=https://github.com/i2p/i2p.android.base

Binary file not shown.

View File

@ -32,11 +32,11 @@ def getSnapshotRepositoryUrl() {
}
def getRepositoryUsername() {
return hasProperty('ossrhUsername') ? ossrhUsername : ""
return hasProperty('NEXUS_USERNAME') ? NEXUS_USERNAME : ""
}
def getRepositoryPassword() {
return hasProperty('ossrhPassword') ? ossrhPassword : ""
return hasProperty('NEXUS_PASSWORD') ? NEXUS_PASSWORD : ""
}
afterEvaluate { project ->