Merge branch 'feature/nio' into develop

This commit is contained in:
Christian Basler 2016-09-21 20:40:20 +02:00
commit d416db1307
24 changed files with 752 additions and 526 deletions

View File

@ -11,7 +11,7 @@ if (project.hasProperty("project.configs")
android { android {
compileSdkVersion 24 compileSdkVersion 24
buildToolsVersion "24.0.1" buildToolsVersion "24.0.2"
defaultConfig { defaultConfig {
applicationId "ch.dissem.apps." + appName.toLowerCase() applicationId "ch.dissem.apps." + appName.toLowerCase()
@ -29,12 +29,12 @@ android {
} }
} }
ext.jabitVersion = 'develop-SNAPSHOT' ext.jabitVersion = 'development-SNAPSHOT'
dependencies { dependencies {
compile fileTree(dir: 'libs', include: ['*.jar']) compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:24.1.1' compile 'com.android.support:appcompat-v7:24.2.0'
compile 'com.android.support:support-v4:24.1.1' compile 'com.android.support:support-v4:24.2.0'
compile 'com.android.support:design:24.1.1' compile 'com.android.support:design:24.2.0'
compile "ch.dissem.jabit:jabit-core:$jabitVersion" compile "ch.dissem.jabit:jabit-core:$jabitVersion"
compile "ch.dissem.jabit:jabit-networking:$jabitVersion" compile "ch.dissem.jabit:jabit-networking:$jabitVersion"
@ -44,20 +44,23 @@ dependencies {
compile 'org.slf4j:slf4j-android:1.7.12' compile 'org.slf4j:slf4j-android:1.7.12'
compile('com.mikepenz:materialdrawer:3.1.0@aar') { compile 'com.mikepenz:materialize:1.0.0@aar'
compile('com.mikepenz:materialdrawer:5.6.0@aar') {
transitive = true transitive = true
} }
compile('com.mikepenz:aboutlibraries:5.3.4@aar') { compile('com.mikepenz:aboutlibraries:5.8.1@aar') {
transitive = true transitive = true
} }
compile 'com.mikepenz:iconics:1.6.2@aar' compile 'com.mikepenz:iconics:1.6.2@aar'
compile 'com.mikepenz:community-material-typeface:1.1.71@aar' compile 'com.mikepenz:community-material-typeface:1.5.54.2@aar'
compile 'com.journeyapps:zxing-android-embedded:3.1.0@aar' compile 'com.journeyapps:zxing-android-embedded:3.1.0@aar'
compile 'com.google.zxing:core:3.2.0' compile 'com.google.zxing:core:3.2.0'
compile 'io.github.yavski:fab-speed-dial:1.0.2' compile 'io.github.yavski:fab-speed-dial:1.0.2'
compile 'com.github.amlcurran.showcaseview:library:5.4.3'
compile 'com.github.amlcurran.showcaseview:library:5.4.0' compile ('com.h6ah4i.android.widget.advrecyclerview:advrecyclerview:0.9.3@aar'){
transitive=true
}
testCompile 'junit:junit:4.12' testCompile 'junit:junit:4.12'
testCompile 'org.mockito:mockito-core:1.10.19' testCompile 'org.mockito:mockito-core:1.10.19'

View File

@ -0,0 +1,9 @@
CREATE TABLE Node (
stream BIGINT NOT NULL,
address BINARY(32) NOT NULL,
port INT NOT NULL,
services BIGINT NOT NULL,
time BIGINT NOT NULL,
PRIMARY KEY (stream, address, port)
);
CREATE INDEX idx_time on Node(time);

View File

@ -16,12 +16,7 @@
package ch.dissem.apps.abit; package ch.dissem.apps.abit;
import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.app.NavUtils;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.MenuItem;
/** /**
@ -33,18 +28,11 @@ import android.view.MenuItem;
* This activity is mostly just a 'shell' activity containing nothing * This activity is mostly just a 'shell' activity containing nothing
* more than a {@link AddressDetailFragment}. * more than a {@link AddressDetailFragment}.
*/ */
public class AddressDetailActivity extends AppCompatActivity { public class AddressDetailActivity extends DetailActivity {
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.scrolling_toolbar_layout);
final Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
// Show the Up button in the action bar.
//noinspection ConstantConditions
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
// savedInstanceState is non-null when there is fragment state // savedInstanceState is non-null when there is fragment state
// saved from previous configurations of this activity // saved from previous configurations of this activity
@ -68,21 +56,4 @@ public class AddressDetailActivity extends AppCompatActivity {
.commit(); .commit();
} }
} }
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == android.R.id.home) {
// This ID represents the Home or Up button. In the case of this
// activity, the Up button is shown. Use NavUtils to allow users
// to navigate up one level in the application structure. For
// more details, see the Navigation pattern on Android Design:
//
// http://developer.android.com/design/patterns/navigation.html#up-vs-back
//
NavUtils.navigateUpTo(this, new Intent(this, MainActivity.class));
return true;
}
return super.onOptionsItemSelected(item);
}
} }

View File

@ -27,6 +27,7 @@ public class ComposeMessageActivity extends AppCompatActivity {
public static final String EXTRA_IDENTITY = "ch.dissem.abit.Message.SENDER"; public static final String EXTRA_IDENTITY = "ch.dissem.abit.Message.SENDER";
public static final String EXTRA_RECIPIENT = "ch.dissem.abit.Message.RECIPIENT"; public static final String EXTRA_RECIPIENT = "ch.dissem.abit.Message.RECIPIENT";
public static final String EXTRA_SUBJECT = "ch.dissem.abit.Message.SUBJECT"; public static final String EXTRA_SUBJECT = "ch.dissem.abit.Message.SUBJECT";
public static final String EXTRA_CONTENT = "ch.dissem.abit.Message.CONTENT";
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {

View File

@ -18,6 +18,7 @@ package ch.dissem.apps.abit;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
import android.text.Selection;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.Menu; import android.view.Menu;
import android.view.MenuInflater; import android.view.MenuInflater;
@ -34,6 +35,7 @@ import ch.dissem.apps.abit.adapter.ContactAdapter;
import ch.dissem.apps.abit.service.Singleton; import ch.dissem.apps.abit.service.Singleton;
import ch.dissem.bitmessage.entity.BitmessageAddress; import ch.dissem.bitmessage.entity.BitmessageAddress;
import static ch.dissem.apps.abit.ComposeMessageActivity.EXTRA_CONTENT;
import static ch.dissem.apps.abit.ComposeMessageActivity.EXTRA_IDENTITY; import static ch.dissem.apps.abit.ComposeMessageActivity.EXTRA_IDENTITY;
import static ch.dissem.apps.abit.ComposeMessageActivity.EXTRA_RECIPIENT; import static ch.dissem.apps.abit.ComposeMessageActivity.EXTRA_RECIPIENT;
import static ch.dissem.apps.abit.ComposeMessageActivity.EXTRA_SUBJECT; import static ch.dissem.apps.abit.ComposeMessageActivity.EXTRA_SUBJECT;
@ -45,6 +47,7 @@ public class ComposeMessageFragment extends Fragment {
private BitmessageAddress identity; private BitmessageAddress identity;
private BitmessageAddress recipient; private BitmessageAddress recipient;
private String subject; private String subject;
private String content;
private AutoCompleteTextView recipientInput; private AutoCompleteTextView recipientInput;
private EditText subjectInput; private EditText subjectInput;
private EditText bodyInput; private EditText bodyInput;
@ -71,6 +74,9 @@ public class ComposeMessageFragment extends Fragment {
if (getArguments().containsKey(EXTRA_SUBJECT)) { if (getArguments().containsKey(EXTRA_SUBJECT)) {
subject = getArguments().getString(EXTRA_SUBJECT); subject = getArguments().getString(EXTRA_SUBJECT);
} }
if (getArguments().containsKey(EXTRA_CONTENT)) {
content = getArguments().getString(EXTRA_CONTENT);
}
} else { } else {
throw new RuntimeException("No identity set for ComposeMessageFragment"); throw new RuntimeException("No identity set for ComposeMessageFragment");
} }
@ -106,6 +112,16 @@ public class ComposeMessageFragment extends Fragment {
subjectInput = (EditText) rootView.findViewById(R.id.subject); subjectInput = (EditText) rootView.findViewById(R.id.subject);
subjectInput.setText(subject); subjectInput.setText(subject);
bodyInput = (EditText) rootView.findViewById(R.id.body); bodyInput = (EditText) rootView.findViewById(R.id.body);
bodyInput.setText(content);
if (recipient == null) {
recipientInput.requestFocus();
} else if (subject == null || subject.isEmpty()) {
subjectInput.requestFocus();
} else {
bodyInput.requestFocus();
bodyInput.setSelection(0);
}
return rootView; return rootView;
} }

View File

@ -0,0 +1,52 @@
package ch.dissem.apps.abit;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.NavUtils;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.MenuItem;
import com.mikepenz.materialize.MaterializeBuilder;
/**
* @author Christian Basler
*/
public class DetailActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.scrolling_toolbar_layout);
final Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
// Show the Up button in the action bar.
//noinspection ConstantConditions
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
new MaterializeBuilder()
.withActivity(this)
.withStatusBarColorRes(R.color.colorPrimaryDark)
.withTranslucentStatusBarProgrammatically(true)
.withStatusBarPadding(true)
.build();
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == android.R.id.home) {
// This ID represents the Home or Up button. In the case of this
// activity, the Up button is shown. Use NavUtils to allow users
// to navigate up one level in the application structure. For
// more details, see the Navigation pattern on Android Design:
//
// http://developer.android.com/design/patterns/navigation.html#up-vs-back
//
NavUtils.navigateUpTo(this, new Intent(this, MainActivity.class));
return true;
}
return super.onOptionsItemSelected(item);
}
}

View File

@ -32,7 +32,6 @@ import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar; import android.support.v7.widget.Toolbar;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.CompoundButton; import android.widget.CompoundButton;
import android.widget.RelativeLayout; import android.widget.RelativeLayout;
import android.widget.TextView; import android.widget.TextView;
@ -43,10 +42,11 @@ import com.github.amlcurran.showcaseview.targets.Target;
import com.mikepenz.community_material_typeface_library.CommunityMaterial; import com.mikepenz.community_material_typeface_library.CommunityMaterial;
import com.mikepenz.google_material_typeface_library.GoogleMaterial; import com.mikepenz.google_material_typeface_library.GoogleMaterial;
import com.mikepenz.iconics.IconicsDrawable; import com.mikepenz.iconics.IconicsDrawable;
import com.mikepenz.materialdrawer.AccountHeader;
import com.mikepenz.materialdrawer.AccountHeaderBuilder;
import com.mikepenz.materialdrawer.Drawer; import com.mikepenz.materialdrawer.Drawer;
import com.mikepenz.materialdrawer.DrawerBuilder; import com.mikepenz.materialdrawer.DrawerBuilder;
import com.mikepenz.materialdrawer.accountswitcher.AccountHeader; import com.mikepenz.materialdrawer.interfaces.OnCheckedChangeListener;
import com.mikepenz.materialdrawer.accountswitcher.AccountHeaderBuilder;
import com.mikepenz.materialdrawer.model.DividerDrawerItem; import com.mikepenz.materialdrawer.model.DividerDrawerItem;
import com.mikepenz.materialdrawer.model.PrimaryDrawerItem; import com.mikepenz.materialdrawer.model.PrimaryDrawerItem;
import com.mikepenz.materialdrawer.model.ProfileDrawerItem; import com.mikepenz.materialdrawer.model.ProfileDrawerItem;
@ -55,7 +55,6 @@ import com.mikepenz.materialdrawer.model.SwitchDrawerItem;
import com.mikepenz.materialdrawer.model.interfaces.IDrawerItem; import com.mikepenz.materialdrawer.model.interfaces.IDrawerItem;
import com.mikepenz.materialdrawer.model.interfaces.IProfile; import com.mikepenz.materialdrawer.model.interfaces.IProfile;
import com.mikepenz.materialdrawer.model.interfaces.Nameable; import com.mikepenz.materialdrawer.model.interfaces.Nameable;
import com.mikepenz.materialdrawer.model.interfaces.OnCheckedChangeListener;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -109,7 +108,7 @@ public class MainActivity extends AppCompatActivity
private static final int MANAGE_IDENTITY = 2; private static final int MANAGE_IDENTITY = 2;
private static final int ADD_CHAN = 3; private static final int ADD_CHAN = 3;
public static WeakReference<MainActivity> instance; private static WeakReference<MainActivity> instance;
/** /**
* Whether or not the activity is in two-pane mode, i.e. running on a tablet * Whether or not the activity is in two-pane mode, i.e. running on a tablet
@ -285,7 +284,7 @@ public class MainActivity extends AppCompatActivity
@Override @Override
public boolean onProfileChanged(View view, IProfile profile, boolean public boolean onProfileChanged(View view, IProfile profile, boolean
currentProfile) { currentProfile) {
switch (profile.getIdentifier()) { switch ((int) profile.getIdentifier()) {
case ADD_IDENTITY: case ADD_IDENTITY:
addIdentityDialog(); addIdentityDialog();
break; break;
@ -318,8 +317,9 @@ public class MainActivity extends AppCompatActivity
ArrayList<IDrawerItem> drawerItems = new ArrayList<>(); ArrayList<IDrawerItem> drawerItems = new ArrayList<>();
for (Label label : labels) { for (Label label : labels) {
PrimaryDrawerItem item = new PrimaryDrawerItem().withName(label.toString()).withTag PrimaryDrawerItem item = new PrimaryDrawerItem()
(label); .withName(label.toString())
.withTag(label);
if (label.getType() == null) { if (label.getType() == null) {
item.withIcon(CommunityMaterial.Icon.cmd_label); item.withIcon(CommunityMaterial.Icon.cmd_label);
} else { } else {
@ -386,15 +386,14 @@ public class MainActivity extends AppCompatActivity
) )
.withOnDrawerItemClickListener(new Drawer.OnDrawerItemClickListener() { .withOnDrawerItemClickListener(new Drawer.OnDrawerItemClickListener() {
@Override @Override
public boolean onItemClick(AdapterView<?> adapterView, View view, int i, long public boolean onItemClick(View view, int position, IDrawerItem item) {
l, IDrawerItem item) {
if (item.getTag() instanceof Label) { if (item.getTag() instanceof Label) {
selectedLabel = (Label) item.getTag(); selectedLabel = (Label) item.getTag();
showSelectedLabel(); showSelectedLabel();
return false; return false;
} else if (item instanceof Nameable<?>) { } else if (item instanceof Nameable<?>) {
Nameable<?> ni = (Nameable<?>) item; Nameable<?> ni = (Nameable<?>) item;
switch (ni.getNameRes()) { switch (ni.getName().getTextRes()) {
case R.string.contacts_and_subscriptions: case R.string.contacts_and_subscriptions:
if (!(getSupportFragmentManager().findFragmentById(R.id if (!(getSupportFragmentManager().findFragmentById(R.id
.item_list) instanceof AddressListFragment)) { .item_list) instanceof AddressListFragment)) {
@ -403,7 +402,6 @@ public class MainActivity extends AppCompatActivity
((AddressListFragment) getSupportFragmentManager() ((AddressListFragment) getSupportFragmentManager()
.findFragmentById(R.id.item_list)).updateList(); .findFragmentById(R.id.item_list)).updateList();
} }
break; break;
case R.string.settings: case R.string.settings:
startActivity(new Intent(MainActivity.this, SettingsActivity startActivity(new Intent(MainActivity.this, SettingsActivity
@ -556,7 +554,7 @@ public class MainActivity extends AppCompatActivity
if (unread > 0) { if (unread > 0) {
((PrimaryDrawerItem) item).withBadge(String.valueOf(unread)); ((PrimaryDrawerItem) item).withBadge(String.valueOf(unread));
} else { } else {
((PrimaryDrawerItem) item).withBadge(null); ((PrimaryDrawerItem) item).withBadge((String) null);
} }
} }
} }

View File

@ -1,11 +1,6 @@
package ch.dissem.apps.abit; package ch.dissem.apps.abit;
import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.app.NavUtils;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.MenuItem;
/** /**
@ -17,18 +12,11 @@ import android.view.MenuItem;
* This activity is mostly just a 'shell' activity containing nothing * This activity is mostly just a 'shell' activity containing nothing
* more than a {@link MessageDetailFragment}. * more than a {@link MessageDetailFragment}.
*/ */
public class MessageDetailActivity extends AppCompatActivity { public class MessageDetailActivity extends DetailActivity {
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.scrolling_toolbar_layout);
final Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
// Show the Up button in the action bar.
//noinspection ConstantConditions
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
// savedInstanceState is non-null when there is fragment state // savedInstanceState is non-null when there is fragment state
// saved from previous configurations of this activity // saved from previous configurations of this activity
@ -52,21 +40,4 @@ public class MessageDetailActivity extends AppCompatActivity {
.commit(); .commit();
} }
} }
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == android.R.id.home) {
// This ID represents the Home or Up button. In the case of this
// activity, the Up button is shown. Use NavUtils to allow users
// to navigate up one level in the application structure. For
// more details, see the Navigation pattern on Android Design:
//
// http://developer.android.com/design/patterns/navigation.html#up-vs-back
//
NavUtils.navigateUpTo(this, new Intent(this, MainActivity.class));
return true;
}
return super.onOptionsItemSelected(item);
}
} }

View File

@ -44,6 +44,7 @@ import ch.dissem.bitmessage.entity.valueobject.Label;
import ch.dissem.bitmessage.ports.MessageRepository; import ch.dissem.bitmessage.ports.MessageRepository;
import static android.text.util.Linkify.WEB_URLS; import static android.text.util.Linkify.WEB_URLS;
import static ch.dissem.apps.abit.ComposeMessageActivity.EXTRA_CONTENT;
import static ch.dissem.apps.abit.ComposeMessageActivity.EXTRA_IDENTITY; import static ch.dissem.apps.abit.ComposeMessageActivity.EXTRA_IDENTITY;
import static ch.dissem.apps.abit.ComposeMessageActivity.EXTRA_RECIPIENT; import static ch.dissem.apps.abit.ComposeMessageActivity.EXTRA_RECIPIENT;
import static ch.dissem.apps.abit.ComposeMessageActivity.EXTRA_SUBJECT; import static ch.dissem.apps.abit.ComposeMessageActivity.EXTRA_SUBJECT;
@ -169,6 +170,9 @@ public class MessageDetailFragment extends Fragment {
prefix = "RE: "; prefix = "RE: ";
} }
replyIntent.putExtra(EXTRA_SUBJECT, prefix + item.getSubject()); replyIntent.putExtra(EXTRA_SUBJECT, prefix + item.getSubject());
replyIntent.putExtra(EXTRA_CONTENT,
"\n\n------------------------------------------------------\n"
+ item.getText());
startActivity(replyIntent); startActivity(replyIntent);
return true; return true;
case R.id.delete: case R.id.delete:

View File

@ -7,18 +7,10 @@ import android.support.v7.widget.Toolbar;
/** /**
* @author Christian Basler * @author Christian Basler
*/ */
public class SettingsActivity extends AppCompatActivity { public class SettingsActivity extends DetailActivity {
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.scrolling_toolbar_layout);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
//noinspection ConstantConditions
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setHomeButtonEnabled(false);
// Display the fragment as the main content. // Display the fragment as the main content.
getFragmentManager().beginTransaction() getFragmentManager().beginTransaction()

View File

@ -21,6 +21,8 @@ import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar; import android.support.v7.widget.Toolbar;
import android.widget.TextView; import android.widget.TextView;
import com.mikepenz.materialize.MaterializeBuilder;
import ch.dissem.apps.abit.service.Singleton; import ch.dissem.apps.abit.service.Singleton;
import ch.dissem.bitmessage.BitmessageContext; import ch.dissem.bitmessage.BitmessageContext;
import ch.dissem.bitmessage.entity.BitmessageAddress; import ch.dissem.bitmessage.entity.BitmessageAddress;
@ -39,6 +41,13 @@ public class StatusActivity extends AppCompatActivity {
getSupportActionBar().setDisplayHomeAsUpEnabled(true); getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setHomeButtonEnabled(false); getSupportActionBar().setHomeButtonEnabled(false);
new MaterializeBuilder()
.withActivity(this)
.withStatusBarColorRes(R.color.colorPrimaryDark)
.withTranslucentStatusBarProgrammatically(true)
.withStatusBarPadding(true)
.build();
BitmessageContext bmc = Singleton.getBitmessageContext(this); BitmessageContext bmc = Singleton.getBitmessageContext(this);
StringBuilder status = new StringBuilder(); StringBuilder status = new StringBuilder();
for (BitmessageAddress address : bmc.addresses().getIdentities()) { for (BitmessageAddress address : bmc.addresses().getIdentities()) {

View File

@ -32,15 +32,24 @@ public class WifiReceiver extends BroadcastReceiver {
if (Preferences.isWifiOnly(ctx)) { if (Preferences.isWifiOnly(ctx)) {
BitmessageContext bmc = Singleton.getBitmessageContext(ctx); BitmessageContext bmc = Singleton.getBitmessageContext(ctx);
if (!isConnectedToWifi(ctx) && bmc.isRunning()) { if (isConnectedToMeteredNetwork(ctx) && bmc.isRunning()) {
bmc.shutdown(); bmc.shutdown();
} }
} }
} }
public static boolean isConnectedToWifi(Context ctx) { public static boolean isConnectedToMeteredNetwork(Context ctx) {
NetworkInfo netInfo = getNetworkInfo(ctx); NetworkInfo netInfo = getNetworkInfo(ctx);
return netInfo != null && netInfo.getType() == ConnectivityManager.TYPE_WIFI; if (netInfo == null || !netInfo.isConnectedOrConnecting()) {
return false;
}
switch (netInfo.getType()){
case ConnectivityManager.TYPE_ETHERNET:
case ConnectivityManager.TYPE_WIFI:
return false;
default:
return true;
}
} }
private static NetworkInfo getNetworkInfo(Context ctx) { private static NetworkInfo getNetworkInfo(Context ctx) {

View File

@ -133,8 +133,7 @@ public class AndroidAddressRepository implements AddressRepository {
where, where,
null, null, null, null null, null, null, null
)) { )) {
c.moveToFirst(); while (c.moveToNext()) {
while (!c.isAfterLast()) {
BitmessageAddress address; BitmessageAddress address;
byte[] privateKeyBytes = c.getBlob(c.getColumnIndex(COLUMN_PRIVATE_KEY)); byte[] privateKeyBytes = c.getBlob(c.getColumnIndex(COLUMN_PRIVATE_KEY));
@ -161,7 +160,6 @@ public class AndroidAddressRepository implements AddressRepository {
address.setSubscribed(c.getInt(c.getColumnIndex(COLUMN_SUBSCRIBED)) == 1); address.setSubscribed(c.getInt(c.getColumnIndex(COLUMN_SUBSCRIBED)) == 1);
result.add(address); result.add(address);
c.moveToNext();
} }
} catch (IOException e) { } catch (IOException e) {
LOG.error(e.getMessage(), e); LOG.error(e.getMessage(), e);
@ -184,8 +182,10 @@ public class AndroidAddressRepository implements AddressRepository {
private boolean exists(BitmessageAddress address) { private boolean exists(BitmessageAddress address) {
SQLiteDatabase db = sql.getReadableDatabase(); SQLiteDatabase db = sql.getReadableDatabase();
try (Cursor cursor = db.rawQuery("SELECT COUNT(*) FROM Address WHERE address='" + address try (Cursor cursor = db.rawQuery(
.getAddress() + "'", null)) { "SELECT COUNT(*) FROM Address WHERE address=?",
new String[]{address.getAddress()}
)) {
cursor.moveToFirst(); cursor.moveToFirst();
return cursor.getInt(0) > 0; return cursor.getInt(0) > 0;
} }
@ -210,8 +210,8 @@ public class AndroidAddressRepository implements AddressRepository {
values.put(COLUMN_CHAN, address.isChan()); values.put(COLUMN_CHAN, address.isChan());
values.put(COLUMN_SUBSCRIBED, address.isSubscribed()); values.put(COLUMN_SUBSCRIBED, address.isSubscribed());
int update = db.update(TABLE_NAME, values, "address = '" + address.getAddress() + int update = db.update(TABLE_NAME, values, "address=?",
"'", null); new String[]{address.getAddress()});
if (update < 0) { if (update < 0) {
LOG.error("Could not update address " + address); LOG.error("Could not update address " + address);
} }

View File

@ -25,7 +25,6 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
@ -42,6 +41,7 @@ import ch.dissem.bitmessage.utils.Encode;
import static ch.dissem.apps.abit.repository.SqlHelper.join; import static ch.dissem.apps.abit.repository.SqlHelper.join;
import static ch.dissem.bitmessage.utils.UnixTime.MINUTE; import static ch.dissem.bitmessage.utils.UnixTime.MINUTE;
import static ch.dissem.bitmessage.utils.UnixTime.now; import static ch.dissem.bitmessage.utils.UnixTime.now;
import static java.lang.String.valueOf;
/** /**
* {@link Inventory} implementation using the Android SQL API. * {@link Inventory} implementation using the Android SQL API.
@ -97,12 +97,10 @@ public class AndroidInventory implements Inventory {
"stream = " + stream, "stream = " + stream,
null, null, null, null null, null, null, null
)) { )) {
c.moveToFirst(); while (c.moveToNext()) {
while (!c.isAfterLast()) {
byte[] blob = c.getBlob(c.getColumnIndex(COLUMN_HASH)); byte[] blob = c.getBlob(c.getColumnIndex(COLUMN_HASH));
long expires = c.getLong(c.getColumnIndex(COLUMN_EXPIRES)); long expires = c.getLong(c.getColumnIndex(COLUMN_EXPIRES));
result.put(new InventoryVector(blob), expires); result.put(new InventoryVector(blob), expires);
c.moveToNext();
} }
} }
LOG.info("Stream #" + stream + " inventory size: " + result.size()); LOG.info("Stream #" + stream + " inventory size: " + result.size());
@ -136,8 +134,7 @@ public class AndroidInventory implements Inventory {
"hash = X'" + vector + "'", "hash = X'" + vector + "'",
null, null, null, null null, null, null, null
)) { )) {
c.moveToFirst(); if (!c.moveToFirst()) {
if (c.isAfterLast()) {
LOG.info("Object requested that we don't have. IV: " + vector); LOG.info("Object requested that we don't have. IV: " + vector);
return null; return null;
} }
@ -174,13 +171,11 @@ public class AndroidInventory implements Inventory {
where.toString(), where.toString(),
null, null, null, null null, null, null, null
)) { )) {
c.moveToFirst(); while (c.moveToNext()) {
while (!c.isAfterLast()) {
int objectVersion = c.getInt(c.getColumnIndex(COLUMN_VERSION)); int objectVersion = c.getInt(c.getColumnIndex(COLUMN_VERSION));
byte[] blob = c.getBlob(c.getColumnIndex(COLUMN_DATA)); byte[] blob = c.getBlob(c.getColumnIndex(COLUMN_DATA));
result.add(Factory.getObjectMessage(objectVersion, new ByteArrayInputStream(blob), result.add(Factory.getObjectMessage(objectVersion, new ByteArrayInputStream(blob),
blob.length)); blob.length));
c.moveToNext();
} }
} }
return result; return result;
@ -211,8 +206,6 @@ public class AndroidInventory implements Inventory {
getCache(object.getStream()).put(iv, object.getExpiresTime()); getCache(object.getStream()).put(iv, object.getExpiresTime());
} catch (SQLiteConstraintException e) { } catch (SQLiteConstraintException e) {
LOG.trace(e.getMessage(), e); LOG.trace(e.getMessage(), e);
} catch (IOException e) {
LOG.error(e.getMessage(), e);
} }
} }
@ -225,7 +218,7 @@ public class AndroidInventory implements Inventory {
public void cleanup() { public void cleanup() {
long fiveMinutesAgo = now() - 5 * MINUTE; long fiveMinutesAgo = now() - 5 * MINUTE;
SQLiteDatabase db = sql.getWritableDatabase(); SQLiteDatabase db = sql.getWritableDatabase();
db.delete(TABLE_NAME, "expires < " + fiveMinutesAgo, null); db.delete(TABLE_NAME, "expires < ?", new String[]{valueOf(fiveMinutesAgo)});
for (Map<InventoryVector, Long> c : cache.values()) { for (Map<InventoryVector, Long> c : cache.values()) {
Iterator<Map.Entry<InventoryVector, Long>> iterator = c.entrySet().iterator(); Iterator<Map.Entry<InventoryVector, Long>> iterator = c.entrySet().iterator();

View File

@ -41,6 +41,8 @@ import ch.dissem.bitmessage.ports.AbstractMessageRepository;
import ch.dissem.bitmessage.ports.MessageRepository; import ch.dissem.bitmessage.ports.MessageRepository;
import ch.dissem.bitmessage.utils.Encode; import ch.dissem.bitmessage.utils.Encode;
import static java.lang.String.valueOf;
/** /**
* {@link MessageRepository} implementation using the Android SQL API. * {@link MessageRepository} implementation using the Android SQL API.
*/ */
@ -100,10 +102,8 @@ public class AndroidMessageRepository extends AbstractMessageRepository {
null, null, null, null, null, null,
LBL_COLUMN_ORDER LBL_COLUMN_ORDER
)) { )) {
c.moveToFirst(); while (c.moveToNext()) {
while (!c.isAfterLast()) {
result.add(getLabel(c)); result.add(getLabel(c));
c.moveToNext();
} }
} }
return result; return result;
@ -149,17 +149,25 @@ public class AndroidMessageRepository extends AbstractMessageRepository {
@Override @Override
public int countUnread(Label label) { public int countUnread(Label label) {
String[] args;
String where; String where;
if (label != null) { if (label != null) {
where = "id IN (SELECT message_id FROM Message_Label WHERE label_id=" + label.getId() where = "id IN (SELECT message_id FROM Message_Label WHERE label_id=?) AND ";
+ ") AND "; args = new String[]{
label.getId().toString(),
Label.Type.UNREAD.name()
};
} else { } else {
where = ""; where = "";
args = new String[]{
Label.Type.UNREAD.name()
};
} }
SQLiteDatabase db = sql.getReadableDatabase(); SQLiteDatabase db = sql.getReadableDatabase();
return (int) DatabaseUtils.queryNumEntries(db, TABLE_NAME, return (int) DatabaseUtils.queryNumEntries(db, TABLE_NAME,
where + "id IN (SELECT message_id FROM Message_Label WHERE label_id IN (" + where + "id IN (SELECT message_id FROM Message_Label WHERE label_id IN (" +
"SELECT id FROM Label WHERE type = '" + Label.Type.UNREAD.name() + "'))" "SELECT id FROM Label WHERE type=?))",
args
); );
} }
@ -191,8 +199,7 @@ public class AndroidMessageRepository extends AbstractMessageRepository {
null, null, null, null, null, null,
COLUMN_RECEIVED + " DESC" COLUMN_RECEIVED + " DESC"
)) { )) {
c.moveToFirst(); while (c.moveToNext()) {
while (!c.isAfterLast()) {
byte[] iv = c.getBlob(c.getColumnIndex(COLUMN_IV)); byte[] iv = c.getBlob(c.getColumnIndex(COLUMN_IV));
byte[] data = c.getBlob(c.getColumnIndex(COLUMN_DATA)); byte[] data = c.getBlob(c.getColumnIndex(COLUMN_DATA));
Plaintext.Type type = Plaintext.Type.valueOf(c.getString(c.getColumnIndex Plaintext.Type type = Plaintext.Type.valueOf(c.getString(c.getColumnIndex
@ -219,7 +226,6 @@ public class AndroidMessageRepository extends AbstractMessageRepository {
} }
builder.labels(findLabels(id)); builder.labels(findLabels(id));
result.add(builder.build()); result.add(builder.build());
c.moveToNext();
} }
} catch (IOException e) { } catch (IOException e) {
LOG.error(e.getMessage(), e); LOG.error(e.getMessage(), e);
@ -257,7 +263,7 @@ public class AndroidMessageRepository extends AbstractMessageRepository {
} }
// remove existing labels // remove existing labels
db.delete(JOIN_TABLE_NAME, "message_id=" + message.getId(), null); db.delete(JOIN_TABLE_NAME, "message_id=?", new String[]{valueOf(message.getId())});
// save labels // save labels
ContentValues values = new ContentValues(); ContentValues values = new ContentValues();
@ -284,10 +290,14 @@ public class AndroidMessageRepository extends AbstractMessageRepository {
values.put(COLUMN_SENDER, message.getFrom().getAddress()); values.put(COLUMN_SENDER, message.getFrom().getAddress());
values.put(COLUMN_RECIPIENT, message.getTo() == null ? null : message.getTo().getAddress()); values.put(COLUMN_RECIPIENT, message.getTo() == null ? null : message.getTo().getAddress());
values.put(COLUMN_DATA, Encode.bytes(message)); values.put(COLUMN_DATA, Encode.bytes(message));
values.put(COLUMN_ACK_DATA, message.getAckData());
values.put(COLUMN_SENT, message.getSent()); values.put(COLUMN_SENT, message.getSent());
values.put(COLUMN_RECEIVED, message.getReceived()); values.put(COLUMN_RECEIVED, message.getReceived());
values.put(COLUMN_STATUS, message.getStatus() == null ? null : message.getStatus().name()); values.put(COLUMN_STATUS, message.getStatus() == null ? null : message.getStatus().name());
values.put(COLUMN_INITIAL_HASH, message.getInitialHash()); values.put(COLUMN_INITIAL_HASH, message.getInitialHash());
values.put(COLUMN_TTL, message.getTTL());
values.put(COLUMN_RETRIES, message.getRetries());
values.put(COLUMN_NEXT_TRY, message.getNextTry());
long id = db.insertOrThrow(TABLE_NAME, null, values); long id = db.insertOrThrow(TABLE_NAME, null, values);
message.setId(id); message.setId(id);
} }
@ -300,10 +310,14 @@ public class AndroidMessageRepository extends AbstractMessageRepository {
values.put(COLUMN_SENDER, message.getFrom().getAddress()); values.put(COLUMN_SENDER, message.getFrom().getAddress());
values.put(COLUMN_RECIPIENT, message.getTo() == null ? null : message.getTo().getAddress()); values.put(COLUMN_RECIPIENT, message.getTo() == null ? null : message.getTo().getAddress());
values.put(COLUMN_DATA, Encode.bytes(message)); values.put(COLUMN_DATA, Encode.bytes(message));
values.put(COLUMN_ACK_DATA, message.getAckData());
values.put(COLUMN_SENT, message.getSent()); values.put(COLUMN_SENT, message.getSent());
values.put(COLUMN_RECEIVED, message.getReceived()); values.put(COLUMN_RECEIVED, message.getReceived());
values.put(COLUMN_STATUS, message.getStatus() == null ? null : message.getStatus().name()); values.put(COLUMN_STATUS, message.getStatus() == null ? null : message.getStatus().name());
values.put(COLUMN_INITIAL_HASH, message.getInitialHash()); values.put(COLUMN_INITIAL_HASH, message.getInitialHash());
values.put(COLUMN_TTL, message.getTTL());
values.put(COLUMN_RETRIES, message.getRetries());
values.put(COLUMN_NEXT_TRY, message.getNextTry());
db.update(TABLE_NAME, values, "id = " + message.getId(), null); db.update(TABLE_NAME, values, "id = " + message.getId(), null);
} }

View File

@ -0,0 +1,187 @@
package ch.dissem.apps.abit.repository;
import android.content.ContentValues;
import android.database.Cursor;
import android.database.sqlite.SQLiteConstraintException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDoneException;
import android.database.sqlite.SQLiteStatement;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import ch.dissem.bitmessage.entity.valueobject.NetworkAddress;
import ch.dissem.bitmessage.exception.ApplicationException;
import ch.dissem.bitmessage.ports.NodeRegistry;
import ch.dissem.bitmessage.utils.Collections;
import ch.dissem.bitmessage.utils.SqlStrings;
import static ch.dissem.bitmessage.ports.NodeRegistryHelper.loadStableNodes;
import static ch.dissem.bitmessage.utils.Strings.hex;
import static ch.dissem.bitmessage.utils.UnixTime.DAY;
import static ch.dissem.bitmessage.utils.UnixTime.MINUTE;
import static ch.dissem.bitmessage.utils.UnixTime.now;
import static java.lang.String.valueOf;
/**
* @author Christian Basler
*/
public class AndroidNodeRegistry implements NodeRegistry {
private static final Logger LOG = LoggerFactory.getLogger(AndroidInventory.class);
private static final String TABLE_NAME = "Node";
private static final String COLUMN_STREAM = "stream";
private static final String COLUMN_ADDRESS = "address";
private static final String COLUMN_PORT = "port";
private static final String COLUMN_SERVICES = "services";
private static final String COLUMN_TIME = "time";
private final ThreadLocal<SQLiteStatement> loadExistingStatement = new ThreadLocal<>();
private final SqlHelper sql;
private Map<Long, Set<NetworkAddress>> stableNodes;
public AndroidNodeRegistry(SqlHelper sql) {
this.sql = sql;
cleanUp();
}
private void cleanUp() {
SQLiteDatabase db = sql.getWritableDatabase();
db.delete(TABLE_NAME, "time < ?", new String[]{valueOf(now(-28 * DAY))});
}
private Long loadExistingTime(NetworkAddress node) {
SQLiteStatement statement = loadExistingStatement.get();
if (statement == null) {
statement = sql.getWritableDatabase().compileStatement(
"SELECT " + COLUMN_TIME +
" FROM " + TABLE_NAME +
" WHERE stream=? AND address=? AND port=?"
);
loadExistingStatement.set(statement);
}
statement.bindLong(1, node.getStream());
statement.bindBlob(2, node.getIPv6());
statement.bindLong(3, node.getPort());
try {
return statement.simpleQueryForLong();
} catch (SQLiteDoneException e) {
return null;
}
}
@Override
public List<NetworkAddress> getKnownAddresses(int limit, long... streams) {
String[] projection = {
COLUMN_STREAM,
COLUMN_ADDRESS,
COLUMN_PORT,
COLUMN_SERVICES,
COLUMN_TIME
};
List<NetworkAddress> result = new LinkedList<>();
SQLiteDatabase db = sql.getReadableDatabase();
try (Cursor c = db.query(
TABLE_NAME, projection,
"stream IN (?)",
new String[]{SqlStrings.join(streams).toString()},
null, null,
"time DESC",
valueOf(limit)
)) {
while (c.moveToNext()) {
result.add(
new NetworkAddress.Builder()
.stream(c.getLong(c.getColumnIndex(COLUMN_STREAM)))
.ipv6(c.getBlob(c.getColumnIndex(COLUMN_ADDRESS)))
.port(c.getInt(c.getColumnIndex(COLUMN_PORT)))
.services(c.getLong(c.getColumnIndex(COLUMN_SERVICES)))
.time(c.getLong(c.getColumnIndex(COLUMN_TIME)))
.build()
);
}
} catch (Exception e) {
LOG.error(e.getMessage(), e);
throw new ApplicationException(e);
}
if (result.isEmpty()) {
synchronized (this) {
if (stableNodes == null) {
stableNodes = loadStableNodes();
}
}
for (long stream : streams) {
Set<NetworkAddress> nodes = stableNodes.get(stream);
if (nodes != null && !nodes.isEmpty()) {
result.add(Collections.selectRandom(nodes));
}
}
}
return result;
}
@Override
public void offerAddresses(List<NetworkAddress> nodes) {
SQLiteDatabase db = sql.getWritableDatabase();
db.beginTransaction();
try {
cleanUp();
for (NetworkAddress node : nodes) {
if (node.getTime() < now(+5 * MINUTE) && node.getTime() > now(-28 * DAY)) {
synchronized (this) {
Long existing = loadExistingTime(node);
if (existing == null) {
insert(node);
} else if (node.getTime() > existing) {
update(node);
}
}
}
}
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
}
private void insert(NetworkAddress node) {
try {
SQLiteDatabase db = sql.getWritableDatabase();
// Create a new map of values, where column names are the keys
ContentValues values = new ContentValues();
values.put(COLUMN_STREAM, node.getStream());
values.put(COLUMN_ADDRESS, node.getIPv6());
values.put(COLUMN_PORT, node.getPort());
values.put(COLUMN_SERVICES, node.getServices());
values.put(COLUMN_TIME, node.getTime());
db.insertOrThrow(TABLE_NAME, null, values);
} catch (SQLiteConstraintException e) {
LOG.trace(e.getMessage(), e);
}
}
private void update(NetworkAddress node) {
try {
SQLiteDatabase db = sql.getWritableDatabase();
// Create a new map of values, where column names are the keys
ContentValues values = new ContentValues();
values.put(COLUMN_SERVICES, node.getServices());
values.put(COLUMN_TIME, node.getTime());
db.update(TABLE_NAME, values,
"stream=" + node.getStream() + " AND address=X'" + hex(node.getIPv6()) + "' AND " +
"port=" + node.getPort(),
null);
} catch (SQLiteConstraintException e) {
LOG.trace(e.getMessage(), e);
}
}
}

View File

@ -25,7 +25,6 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
@ -37,6 +36,7 @@ import ch.dissem.bitmessage.utils.Encode;
import ch.dissem.bitmessage.utils.Strings; import ch.dissem.bitmessage.utils.Strings;
import static ch.dissem.bitmessage.utils.Singleton.cryptography; import static ch.dissem.bitmessage.utils.Singleton.cryptography;
import static ch.dissem.bitmessage.utils.Strings.hex;
/** /**
* @author Christian Basler * @author Christian Basler
@ -82,11 +82,10 @@ public class AndroidProofOfWorkRepository implements ProofOfWorkRepository, Inte
SQLiteDatabase db = sql.getReadableDatabase(); SQLiteDatabase db = sql.getReadableDatabase();
try (Cursor c = db.query( try (Cursor c = db.query(
TABLE_NAME, projection, TABLE_NAME, projection,
"initial_hash = X'" + Strings.hex(initialHash) + "'", "initial_hash=X'" + hex(initialHash) + "'",
null, null, null, null null, null, null, null
)) { )) {
c.moveToFirst(); if (c.moveToFirst()) {
if (!c.isAfterLast()) {
int version = c.getInt(c.getColumnIndex(COLUMN_VERSION)); int version = c.getInt(c.getColumnIndex(COLUMN_VERSION));
byte[] blob = c.getBlob(c.getColumnIndex(COLUMN_DATA)); byte[] blob = c.getBlob(c.getColumnIndex(COLUMN_DATA));
if (c.isNull(c.getColumnIndex(COLUMN_MESSAGE_ID))) { if (c.isNull(c.getColumnIndex(COLUMN_MESSAGE_ID))) {
@ -110,7 +109,7 @@ public class AndroidProofOfWorkRepository implements ProofOfWorkRepository, Inte
} }
} }
throw new RuntimeException("Object requested that we don't have. Initial hash: " + throw new RuntimeException("Object requested that we don't have. Initial hash: " +
Strings.hex(initialHash)); hex(initialHash));
} }
@Override @Override
@ -127,11 +126,9 @@ public class AndroidProofOfWorkRepository implements ProofOfWorkRepository, Inte
TABLE_NAME, projection, TABLE_NAME, projection,
null, null, null, null, null null, null, null, null, null
)) { )) {
c.moveToFirst(); while (c.moveToNext()) {
while (!c.isAfterLast()) {
byte[] initialHash = c.getBlob(c.getColumnIndex(COLUMN_INITIAL_HASH)); byte[] initialHash = c.getBlob(c.getColumnIndex(COLUMN_INITIAL_HASH));
result.add(initialHash); result.add(initialHash);
c.moveToNext();
} }
} }
return result; return result;
@ -156,8 +153,6 @@ public class AndroidProofOfWorkRepository implements ProofOfWorkRepository, Inte
db.insertOrThrow(TABLE_NAME, null, values); db.insertOrThrow(TABLE_NAME, null, values);
} catch (SQLiteConstraintException e) { } catch (SQLiteConstraintException e) {
LOG.trace(e.getMessage(), e); LOG.trace(e.getMessage(), e);
} catch (IOException e) {
LOG.error(e.getMessage(), e);
} }
} }
@ -169,8 +164,10 @@ public class AndroidProofOfWorkRepository implements ProofOfWorkRepository, Inte
@Override @Override
public void removeObject(byte[] initialHash) { public void removeObject(byte[] initialHash) {
SQLiteDatabase db = sql.getWritableDatabase(); SQLiteDatabase db = sql.getWritableDatabase();
db.delete(TABLE_NAME, db.delete(
"initial_hash = X'" + Strings.hex(initialHash) + "'", TABLE_NAME,
null); "initial_hash=X'" + hex(initialHash) + "'",
null
);
} }
} }

View File

@ -19,6 +19,7 @@ package ch.dissem.apps.abit.repository;
import android.content.Context; import android.content.Context;
import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper; import android.database.sqlite.SQLiteOpenHelper;
import ch.dissem.apps.abit.util.Assets; import ch.dissem.apps.abit.util.Assets;
/** /**
@ -26,7 +27,7 @@ import ch.dissem.apps.abit.util.Assets;
*/ */
public class SqlHelper extends SQLiteOpenHelper { public class SqlHelper extends SQLiteOpenHelper {
// If you change the database schema, you must increment the database version. // If you change the database schema, you must increment the database version.
public static final int DATABASE_VERSION = 4; public static final int DATABASE_VERSION = 5;
public static final String DATABASE_NAME = "jabit.db"; public static final String DATABASE_NAME = "jabit.db";
protected final Context ctx; protected final Context ctx;
@ -38,7 +39,7 @@ public class SqlHelper extends SQLiteOpenHelper {
@Override @Override
public void onCreate(SQLiteDatabase db) { public void onCreate(SQLiteDatabase db) {
onUpgrade(db, 0, 2); onUpgrade(db, 0, DATABASE_VERSION);
} }
@Override @Override
@ -56,8 +57,11 @@ public class SqlHelper extends SQLiteOpenHelper {
case 3: case 3:
executeMigration(db, "V3.1__Update_table_POW"); executeMigration(db, "V3.1__Update_table_POW");
executeMigration(db, "V3.2__Update_table_message"); executeMigration(db, "V3.2__Update_table_message");
case 4:
executeMigration(db, "V3.3__Create_table_node");
default: default:
// Nothing to do. Let's assume we won't upgrade from a version that's newer than DATABASE_VERSION. // Nothing to do. Let's assume we won't upgrade from a version that's newer than
// DATABASE_VERSION.
} }
} }

View File

@ -28,16 +28,17 @@ import ch.dissem.apps.abit.pow.ServerPowEngine;
import ch.dissem.apps.abit.repository.AndroidAddressRepository; import ch.dissem.apps.abit.repository.AndroidAddressRepository;
import ch.dissem.apps.abit.repository.AndroidInventory; import ch.dissem.apps.abit.repository.AndroidInventory;
import ch.dissem.apps.abit.repository.AndroidMessageRepository; import ch.dissem.apps.abit.repository.AndroidMessageRepository;
import ch.dissem.apps.abit.repository.AndroidNodeRegistry;
import ch.dissem.apps.abit.repository.AndroidProofOfWorkRepository; import ch.dissem.apps.abit.repository.AndroidProofOfWorkRepository;
import ch.dissem.apps.abit.repository.SqlHelper; import ch.dissem.apps.abit.repository.SqlHelper;
import ch.dissem.apps.abit.util.Constants; import ch.dissem.apps.abit.util.Constants;
import ch.dissem.bitmessage.BitmessageContext; import ch.dissem.bitmessage.BitmessageContext;
import ch.dissem.bitmessage.entity.BitmessageAddress; import ch.dissem.bitmessage.entity.BitmessageAddress;
import ch.dissem.bitmessage.networking.DefaultNetworkHandler; import ch.dissem.bitmessage.networking.nio.NioNetworkHandler;
import ch.dissem.bitmessage.ports.AddressRepository; import ch.dissem.bitmessage.ports.AddressRepository;
import ch.dissem.bitmessage.ports.MemoryNodeRegistry;
import ch.dissem.bitmessage.ports.MessageRepository; import ch.dissem.bitmessage.ports.MessageRepository;
import ch.dissem.bitmessage.ports.ProofOfWorkRepository; import ch.dissem.bitmessage.ports.ProofOfWorkRepository;
import ch.dissem.bitmessage.utils.TTL;
import static ch.dissem.bitmessage.utils.UnixTime.DAY; import static ch.dissem.bitmessage.utils.UnixTime.DAY;
@ -58,6 +59,7 @@ public class Singleton {
final Context ctx = context.getApplicationContext(); final Context ctx = context.getApplicationContext();
SqlHelper sqlHelper = new SqlHelper(ctx); SqlHelper sqlHelper = new SqlHelper(ctx);
powRepo = new AndroidProofOfWorkRepository(sqlHelper); powRepo = new AndroidProofOfWorkRepository(sqlHelper);
TTL.pubkey(2 * DAY);
bitmessageContext = new BitmessageContext.Builder() bitmessageContext = new BitmessageContext.Builder()
.proofOfWorkEngine(new SwitchingProofOfWorkEngine( .proofOfWorkEngine(new SwitchingProofOfWorkEngine(
ctx, Constants.PREFERENCE_SERVER_POW, ctx, Constants.PREFERENCE_SERVER_POW,
@ -65,15 +67,14 @@ public class Singleton {
new ServicePowEngine(ctx) new ServicePowEngine(ctx)
)) ))
.cryptography(new AndroidCryptography()) .cryptography(new AndroidCryptography())
.nodeRegistry(new MemoryNodeRegistry()) .nodeRegistry(new AndroidNodeRegistry(sqlHelper))
.inventory(new AndroidInventory(sqlHelper)) .inventory(new AndroidInventory(sqlHelper))
.addressRepo(new AndroidAddressRepository(sqlHelper)) .addressRepo(new AndroidAddressRepository(sqlHelper))
.messageRepo(new AndroidMessageRepository(sqlHelper, ctx)) .messageRepo(new AndroidMessageRepository(sqlHelper, ctx))
.powRepo(powRepo) .powRepo(powRepo)
.networkHandler(new DefaultNetworkHandler()) .networkHandler(new NioNetworkHandler())
.listener(getMessageListener(ctx)) .listener(getMessageListener(ctx))
.doNotSendPubkeyOnIdentityCreation() .doNotSendPubkeyOnIdentityCreation()
.pubkeyTTL(2 * DAY)
.build(); .build();
} }
} }

View File

@ -101,7 +101,7 @@ public class Preferences {
} }
public static boolean isConnectionAllowed(Context ctx) { public static boolean isConnectionAllowed(Context ctx) {
return !isWifiOnly(ctx) || WifiReceiver.isConnectedToWifi(ctx); return !isWifiOnly(ctx) || !WifiReceiver.isConnectedToMeteredNetwork(ctx);
} }
public static boolean isWifiOnly(Context ctx) { public static boolean isWifiOnly(Context ctx) {

View File

@ -1,24 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="AppTheme" parent="AppTheme.Base">
<!-- Main theme colors -->
<!-- your app branding color for the app bar -->
<item name="android:colorPrimary">@color/colorPrimary</item>
<!-- darker variant for the status bar and contextual app bars -->
<item name="android:colorPrimaryDark">@color/colorPrimaryDark</item>
<!-- theme UI controls like checkboxes and text fields -->
<item name="android:colorAccent">@color/colorAccent</item>
<item name="android:windowContentTransitions">true</item>
<item name="android:windowAllowEnterTransitionOverlap">true</item>
<item name="android:windowAllowReturnTransitionOverlap">true</item>
<item name="android:windowSharedElementEnterTransition">@android:transition/move</item>
<item name="android:windowSharedElementExitTransition">@android:transition/move</item>
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
<!--<item name="android:statusBarColor">@android:color/transparent</item>-->
</style>
</resources>

View File

@ -10,4 +10,39 @@
<color name="colorSecondaryText">#727272</color> <color name="colorSecondaryText">#727272</color>
<color name="icons">#212121</color> <color name="icons">#212121</color>
<color name="divider">#B6B6B6</color> <color name="divider">#B6B6B6</color>
<!-- Material DEFAULT colors -->
<color name="material_drawer_primary">@color/colorPrimary</color>
<color name="material_drawer_primary_dark">@color/colorPrimaryDark</color>
<color name="material_drawer_primary_light">@color/colorPrimaryLight</color>
<color name="material_drawer_accent">@color/colorAccent</color>
<!-- OVERWRITE THESE COLORS FOR A LIGHT THEME -->
<!-- MaterialDrawer DEFAULT colors -->
<color name="material_drawer_background">@color/colorPrimaryDark</color>
<!-- Material DEFAULT text / items colors -->
<color name="material_drawer_primary_text">@color/colorPrimaryText</color>
<color name="material_drawer_primary_icon">@color/icons</color>
<color name="material_drawer_secondary_text">@color/colorSecondaryText</color>
<color name="material_drawer_hint_text">@color/colorSecondaryText</color>
<color name="material_drawer_divider">@color/divider</color>
<!-- Material DEFAULT drawer colors -->
<color name="material_drawer_selected">@color/primary</color>
<color name="material_drawer_selected_text">@color/colorPrimaryText</color>
<color name="material_drawer_header_selection_text">@color/colorPrimaryText</color>
<!-- OVERWRITE THESE COLORS FOR A DARK THEME -->
<!-- MaterialDrawer DEFAULT DARK colors -->
<color name="material_drawer_dark_background">#303030</color>
<!-- MaterialDrawer DEFAULT DARK text / items colors -->
<color name="material_drawer_dark_primary_text">#DEFFFFFF</color>
<color name="material_drawer_dark_primary_icon">#8AFFFFFF</color>
<color name="material_drawer_dark_secondary_text">#8AFFFFFF</color>
<color name="material_drawer_dark_hint_text">#42FFFFFF</color>
<color name="material_drawer_dark_divider">#1FFFFFFF</color>
<!-- MaterialDrawer DEFAULT DARK drawer colors -->
<color name="material_drawer_dark_selected">#202020</color>
<color name="material_drawer_dark_selected_text">@color/material_drawer_primary</color>
<color name="material_drawer_dark_header_selection_text">#FFF</color>
</resources> </resources>

View File

@ -1,28 +1,12 @@
<resources> <resources>
<!-- Base application theme. --> <!-- Base application theme. -->
<style name="AppTheme.Base" parent="MaterialDrawerTheme.Light.DarkToolbar.TranslucentStatus"> <style name="AppTheme" parent="MaterialDrawerTheme.Light.DarkToolbar.TranslucentStatus">
<item name="android:activatedBackgroundIndicator">@color/colorPrimaryLight</item> <item name="android:activatedBackgroundIndicator">@color/colorPrimaryLight</item>
<item name="android:textColor">@color/colorPrimaryText</item> <item name="android:textColor">@color/colorPrimaryText</item>
<item name="android:textColorSecondary">@color/colorSecondaryText</item> <item name="android:textColorSecondary">@color/colorSecondaryText</item>
<!-- MaterialDrawer specific values -->
<item name="material_drawer_background">@color/colorPrimaryDark</item>
<item name="material_drawer_icons">@color/colorPrimaryText</item>
<item name="material_drawer_primary_icon">@color/icons</item>
<item name="material_drawer_primary_text">@color/colorPrimaryText</item>
<item name="material_drawer_secondary_text">@color/colorSecondaryText</item>
<item name="material_drawer_hint_text">@color/colorSecondaryText</item>
<item name="material_drawer_divider">@color/divider</item>
<item name="material_drawer_selected">@color/primary</item>
<item name="material_drawer_selected_text">@color/colorPrimaryText</item>
<item name="material_drawer_header_selection_text">@color/colorPrimaryText</item>
</style> </style>
<style name="AppTheme" parent="AppTheme.Base"/>
<style name="CustomShowcaseTheme" parent="ShowcaseView"> <style name="CustomShowcaseTheme" parent="ShowcaseView">
<item name="sv_backgroundColor">#eeffc107</item> <item name="sv_backgroundColor">#eeffc107</item>
<item name="sv_showcaseColor">#ffc107</item> <item name="sv_showcaseColor">#ffc107</item>

View File

@ -9,7 +9,7 @@ buildscript {
jcenter() jcenter()
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:2.1.2' classpath 'com.android.tools.build:gradle:2.1.3'
// NOTE: Do not place your application dependencies here; they belong // NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files // in the individual module build.gradle files