diff --git a/app/build.gradle b/app/build.gradle
index e600ee0..364f4d3 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -11,7 +11,7 @@ if (project.hasProperty("project.configs")
android {
compileSdkVersion 24
- buildToolsVersion "24.0.1"
+ buildToolsVersion "24.0.2"
defaultConfig {
applicationId "ch.dissem.apps." + appName.toLowerCase()
@@ -29,12 +29,12 @@ android {
}
}
-ext.jabitVersion = 'develop-SNAPSHOT'
+ext.jabitVersion = 'development-SNAPSHOT'
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
- compile 'com.android.support:appcompat-v7:24.1.1'
- compile 'com.android.support:support-v4:24.1.1'
- compile 'com.android.support:design:24.1.1'
+ compile 'com.android.support:appcompat-v7:24.2.0'
+ compile 'com.android.support:support-v4:24.2.0'
+ compile 'com.android.support:design:24.2.0'
compile "ch.dissem.jabit:jabit-core:$jabitVersion"
compile "ch.dissem.jabit:jabit-networking:$jabitVersion"
@@ -44,20 +44,23 @@ dependencies {
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
}
- compile('com.mikepenz:aboutlibraries:5.3.4@aar') {
+ compile('com.mikepenz:aboutlibraries:5.8.1@aar') {
transitive = true
}
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.google.zxing:core:3.2.0'
compile 'io.github.yavski:fab-speed-dial:1.0.2'
-
- compile 'com.github.amlcurran.showcaseview:library:5.4.0'
+ compile 'com.github.amlcurran.showcaseview:library:5.4.3'
+ compile ('com.h6ah4i.android.widget.advrecyclerview:advrecyclerview:0.9.3@aar'){
+ transitive=true
+ }
testCompile 'junit:junit:4.12'
testCompile 'org.mockito:mockito-core:1.10.19'
@@ -72,4 +75,4 @@ android {
lintOptions {
abortOnError false
}
-}
\ No newline at end of file
+}
diff --git a/app/src/main/assets/db/migration/V3.3__Create_table_node.sql b/app/src/main/assets/db/migration/V3.3__Create_table_node.sql
new file mode 100644
index 0000000..5d03bb5
--- /dev/null
+++ b/app/src/main/assets/db/migration/V3.3__Create_table_node.sql
@@ -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);
diff --git a/app/src/main/java/ch/dissem/apps/abit/AddressDetailActivity.java b/app/src/main/java/ch/dissem/apps/abit/AddressDetailActivity.java
index 077a5d4..a00e613 100644
--- a/app/src/main/java/ch/dissem/apps/abit/AddressDetailActivity.java
+++ b/app/src/main/java/ch/dissem/apps/abit/AddressDetailActivity.java
@@ -16,12 +16,7 @@
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;
/**
@@ -33,18 +28,11 @@ import android.view.MenuItem;
* This activity is mostly just a 'shell' activity containing nothing
* more than a {@link AddressDetailFragment}.
*/
-public class AddressDetailActivity extends AppCompatActivity {
+public class AddressDetailActivity extends DetailActivity {
@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);
// savedInstanceState is non-null when there is fragment state
// saved from previous configurations of this activity
@@ -68,21 +56,4 @@ public class AddressDetailActivity extends AppCompatActivity {
.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);
- }
}
diff --git a/app/src/main/java/ch/dissem/apps/abit/ComposeMessageActivity.java b/app/src/main/java/ch/dissem/apps/abit/ComposeMessageActivity.java
index 5fa12a4..c5f2032 100644
--- a/app/src/main/java/ch/dissem/apps/abit/ComposeMessageActivity.java
+++ b/app/src/main/java/ch/dissem/apps/abit/ComposeMessageActivity.java
@@ -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_RECIPIENT = "ch.dissem.abit.Message.RECIPIENT";
public static final String EXTRA_SUBJECT = "ch.dissem.abit.Message.SUBJECT";
+ public static final String EXTRA_CONTENT = "ch.dissem.abit.Message.CONTENT";
@Override
protected void onCreate(Bundle savedInstanceState) {
diff --git a/app/src/main/java/ch/dissem/apps/abit/ComposeMessageFragment.java b/app/src/main/java/ch/dissem/apps/abit/ComposeMessageFragment.java
index b19ef4d..5d80e31 100644
--- a/app/src/main/java/ch/dissem/apps/abit/ComposeMessageFragment.java
+++ b/app/src/main/java/ch/dissem/apps/abit/ComposeMessageFragment.java
@@ -18,6 +18,7 @@ package ch.dissem.apps.abit;
import android.os.Bundle;
import android.support.v4.app.Fragment;
+import android.text.Selection;
import android.view.LayoutInflater;
import android.view.Menu;
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.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_RECIPIENT;
import static ch.dissem.apps.abit.ComposeMessageActivity.EXTRA_SUBJECT;
@@ -45,6 +47,7 @@ public class ComposeMessageFragment extends Fragment {
private BitmessageAddress identity;
private BitmessageAddress recipient;
private String subject;
+ private String content;
private AutoCompleteTextView recipientInput;
private EditText subjectInput;
private EditText bodyInput;
@@ -71,6 +74,9 @@ public class ComposeMessageFragment extends Fragment {
if (getArguments().containsKey(EXTRA_SUBJECT)) {
subject = getArguments().getString(EXTRA_SUBJECT);
}
+ if (getArguments().containsKey(EXTRA_CONTENT)) {
+ content = getArguments().getString(EXTRA_CONTENT);
+ }
} else {
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.setText(subject);
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;
}
@@ -126,7 +142,7 @@ public class ComposeMessageFragment extends Fragment {
recipient = new BitmessageAddress(inputString);
} catch (Exception e) {
List contacts = Singleton.getAddressRepository
- (getContext()).getContacts();
+ (getContext()).getContacts();
for (BitmessageAddress contact : contacts) {
if (inputString.equalsIgnoreCase(contact.getAlias())) {
recipient = contact;
@@ -137,8 +153,8 @@ public class ComposeMessageFragment extends Fragment {
}
}
Singleton.getBitmessageContext(getContext()).send(identity, recipient,
- subjectInput.getText().toString(),
- bodyInput.getText().toString());
+ subjectInput.getText().toString(),
+ bodyInput.getText().toString());
getActivity().finish();
return true;
default:
diff --git a/app/src/main/java/ch/dissem/apps/abit/DetailActivity.java b/app/src/main/java/ch/dissem/apps/abit/DetailActivity.java
new file mode 100644
index 0000000..fb94ef2
--- /dev/null
+++ b/app/src/main/java/ch/dissem/apps/abit/DetailActivity.java
@@ -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);
+ }
+}
diff --git a/app/src/main/java/ch/dissem/apps/abit/MainActivity.java b/app/src/main/java/ch/dissem/apps/abit/MainActivity.java
index b1e9ded..b8825c8 100644
--- a/app/src/main/java/ch/dissem/apps/abit/MainActivity.java
+++ b/app/src/main/java/ch/dissem/apps/abit/MainActivity.java
@@ -32,7 +32,6 @@ import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.view.ViewGroup;
-import android.widget.AdapterView;
import android.widget.CompoundButton;
import android.widget.RelativeLayout;
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.google_material_typeface_library.GoogleMaterial;
import com.mikepenz.iconics.IconicsDrawable;
+import com.mikepenz.materialdrawer.AccountHeader;
+import com.mikepenz.materialdrawer.AccountHeaderBuilder;
import com.mikepenz.materialdrawer.Drawer;
import com.mikepenz.materialdrawer.DrawerBuilder;
-import com.mikepenz.materialdrawer.accountswitcher.AccountHeader;
-import com.mikepenz.materialdrawer.accountswitcher.AccountHeaderBuilder;
+import com.mikepenz.materialdrawer.interfaces.OnCheckedChangeListener;
import com.mikepenz.materialdrawer.model.DividerDrawerItem;
import com.mikepenz.materialdrawer.model.PrimaryDrawerItem;
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.IProfile;
import com.mikepenz.materialdrawer.model.interfaces.Nameable;
-import com.mikepenz.materialdrawer.model.interfaces.OnCheckedChangeListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -100,7 +99,7 @@ import static ch.dissem.apps.abit.service.BitmessageService.isRunning;
*
*/
public class MainActivity extends AppCompatActivity
- implements ListSelectionListener, ActionBarListener {
+ implements ListSelectionListener, ActionBarListener {
public static final String EXTRA_SHOW_MESSAGE = "ch.dissem.abit.ShowMessage";
public static final String ACTION_SHOW_INBOX = "ch.dissem.abit.ShowInbox";
@@ -109,7 +108,7 @@ public class MainActivity extends AppCompatActivity
private static final int MANAGE_IDENTITY = 2;
private static final int ADD_CHAN = 3;
- public static WeakReference instance;
+ private static WeakReference instance;
/**
* Whether or not the activity is in two-pane mode, i.e. running on a tablet
@@ -157,7 +156,7 @@ public class MainActivity extends AppCompatActivity
MessageListFragment listFragment = new MessageListFragment();
getSupportFragmentManager().beginTransaction().replace(R.id.item_list, listFragment)
- .commit();
+ .commit();
if (findViewById(R.id.message_detail_container) != null) {
// The detail container view will be present only in the
@@ -187,42 +186,42 @@ public class MainActivity extends AppCompatActivity
}
if (drawer.isDrawerOpen()) {
RelativeLayout.LayoutParams lps = new RelativeLayout.LayoutParams(ViewGroup
- .LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
+ .LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
lps.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
lps.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
int margin = ((Number) (getResources().getDisplayMetrics().density * 12)).intValue();
lps.setMargins(margin, margin, margin, margin);
showcaseView = new ShowcaseView.Builder(this)
- .withMaterialShowcase()
- .setStyle(R.style.CustomShowcaseTheme)
- .setContentTitle(R.string.full_node)
- .setContentText(R.string.full_node_description)
- .setTarget(new Target() {
- @Override
- public Point getPoint() {
- View view = drawer.getStickyFooter();
- int[] location = new int[2];
- view.getLocationInWindow(location);
- int x = location[0] + 7 * view.getWidth() / 8;
- int y = location[1] + view.getHeight() / 2;
- return new Point(x, y);
- }
+ .withMaterialShowcase()
+ .setStyle(R.style.CustomShowcaseTheme)
+ .setContentTitle(R.string.full_node)
+ .setContentText(R.string.full_node_description)
+ .setTarget(new Target() {
+ @Override
+ public Point getPoint() {
+ View view = drawer.getStickyFooter();
+ int[] location = new int[2];
+ view.getLocationInWindow(location);
+ int x = location[0] + 7 * view.getWidth() / 8;
+ int y = location[1] + view.getHeight() / 2;
+ return new Point(x, y);
}
- )
- .replaceEndButton(R.layout.showcase_button)
- .hideOnTouchOutside()
- .build();
+ }
+ )
+ .replaceEndButton(R.layout.showcase_button)
+ .hideOnTouchOutside()
+ .build();
showcaseView.setButtonPosition(lps);
}
}
private void changeList(AbstractItemListFragment> listFragment) {
getSupportFragmentManager()
- .beginTransaction()
- .replace(R.id.item_list, listFragment)
- .addToBackStack(null)
- .commit();
+ .beginTransaction()
+ .replace(R.id.item_list, listFragment)
+ .addToBackStack(null)
+ .commit();
if (twoPane) {
// In two-pane mode, list items should be given the
@@ -236,90 +235,91 @@ public class MainActivity extends AppCompatActivity
for (BitmessageAddress identity : bmc.addresses().getIdentities()) {
LOG.info("Adding identity " + identity.getAddress());
profiles.add(new ProfileDrawerItem()
- .withIcon(new Identicon(identity))
- .withName(identity.toString())
- .withNameShown(true)
- .withEmail(identity.getAddress())
- .withTag(identity)
+ .withIcon(new Identicon(identity))
+ .withName(identity.toString())
+ .withNameShown(true)
+ .withEmail(identity.getAddress())
+ .withTag(identity)
);
}
if (profiles.isEmpty()) {
// Create an initial identity
BitmessageAddress identity = Singleton.getIdentity(this);
profiles.add(new ProfileDrawerItem()
- .withIcon(new Identicon(identity))
- .withName(identity.toString())
- .withEmail(identity.getAddress())
- .withTag(identity)
+ .withIcon(new Identicon(identity))
+ .withName(identity.toString())
+ .withEmail(identity.getAddress())
+ .withTag(identity)
);
}
profiles.add(new ProfileSettingDrawerItem()
- .withName(getString(R.string.add_identity))
- .withDescription(getString(R.string.add_identity_summary))
- .withIcon(new IconicsDrawable(this, GoogleMaterial.Icon.gmd_add)
- .actionBar()
- .paddingDp(5)
- .colorRes(R.color.icons))
- .withIdentifier(ADD_IDENTITY)
+ .withName(getString(R.string.add_identity))
+ .withDescription(getString(R.string.add_identity_summary))
+ .withIcon(new IconicsDrawable(this, GoogleMaterial.Icon.gmd_add)
+ .actionBar()
+ .paddingDp(5)
+ .colorRes(R.color.icons))
+ .withIdentifier(ADD_IDENTITY)
);
profiles.add(new ProfileSettingDrawerItem()
- .withName(getString(R.string.add_chan))
- .withDescription(getString(R.string.add_chan_summary))
- .withIcon(new IconicsDrawable(this, GoogleMaterial.Icon.gmd_add)
- .actionBar()
- .paddingDp(5)
- .colorRes(R.color.icons))
- .withIdentifier(ADD_CHAN)
+ .withName(getString(R.string.add_chan))
+ .withDescription(getString(R.string.add_chan_summary))
+ .withIcon(new IconicsDrawable(this, GoogleMaterial.Icon.gmd_add)
+ .actionBar()
+ .paddingDp(5)
+ .colorRes(R.color.icons))
+ .withIdentifier(ADD_CHAN)
);
profiles.add(new ProfileSettingDrawerItem()
- .withName(getString(R.string.manage_identity))
- .withIcon(GoogleMaterial.Icon.gmd_settings)
- .withIdentifier(MANAGE_IDENTITY)
+ .withName(getString(R.string.manage_identity))
+ .withIcon(GoogleMaterial.Icon.gmd_settings)
+ .withIdentifier(MANAGE_IDENTITY)
);
// Create the AccountHeader
accountHeader = new AccountHeaderBuilder()
- .withActivity(this)
- .withHeaderBackground(R.drawable.header)
- .withProfiles(profiles)
- .withOnAccountHeaderListener(new AccountHeader.OnAccountHeaderListener() {
- @Override
- public boolean onProfileChanged(View view, IProfile profile, boolean
- currentProfile) {
- switch (profile.getIdentifier()) {
- case ADD_IDENTITY:
- addIdentityDialog();
- break;
- case ADD_CHAN:
- addChanDialog();
- break;
- case MANAGE_IDENTITY:
- Intent show = new Intent(MainActivity.this,
- AddressDetailActivity.class);
- show.putExtra(AddressDetailFragment.ARG_ITEM,
- Singleton.getIdentity(getApplicationContext()));
- startActivity(show);
- break;
- default:
- if (profile instanceof ProfileDrawerItem) {
- Object tag = ((ProfileDrawerItem) profile).getTag();
- if (tag instanceof BitmessageAddress) {
- Singleton.setIdentity((BitmessageAddress) tag);
- }
+ .withActivity(this)
+ .withHeaderBackground(R.drawable.header)
+ .withProfiles(profiles)
+ .withOnAccountHeaderListener(new AccountHeader.OnAccountHeaderListener() {
+ @Override
+ public boolean onProfileChanged(View view, IProfile profile, boolean
+ currentProfile) {
+ switch ((int) profile.getIdentifier()) {
+ case ADD_IDENTITY:
+ addIdentityDialog();
+ break;
+ case ADD_CHAN:
+ addChanDialog();
+ break;
+ case MANAGE_IDENTITY:
+ Intent show = new Intent(MainActivity.this,
+ AddressDetailActivity.class);
+ show.putExtra(AddressDetailFragment.ARG_ITEM,
+ Singleton.getIdentity(getApplicationContext()));
+ startActivity(show);
+ break;
+ default:
+ if (profile instanceof ProfileDrawerItem) {
+ Object tag = ((ProfileDrawerItem) profile).getTag();
+ if (tag instanceof BitmessageAddress) {
+ Singleton.setIdentity((BitmessageAddress) tag);
}
- }
- // false if it should close the drawer
- return false;
+ }
}
- })
- .build();
+ // false if it should close the drawer
+ return false;
+ }
+ })
+ .build();
if (profiles.size() > 2) { // There's always the add and manage identity items
accountHeader.setActiveProfile(profiles.get(0), true);
}
ArrayList drawerItems = new ArrayList<>();
for (Label label : labels) {
- PrimaryDrawerItem item = new PrimaryDrawerItem().withName(label.toString()).withTag
- (label);
+ PrimaryDrawerItem item = new PrimaryDrawerItem()
+ .withName(label.toString())
+ .withTag(label);
if (label.getType() == null) {
item.withIcon(CommunityMaterial.Icon.cmd_label);
} else {
@@ -349,146 +349,144 @@ public class MainActivity extends AppCompatActivity
drawerItems.add(item);
}
drawerItems.add(new PrimaryDrawerItem()
- .withName(R.string.archive)
- .withTag(null)
- .withIcon(CommunityMaterial.Icon.cmd_archive)
+ .withName(R.string.archive)
+ .withTag(null)
+ .withIcon(CommunityMaterial.Icon.cmd_archive)
);
drawerItems.add(new DividerDrawerItem());
drawerItems.add(new PrimaryDrawerItem()
- .withName(R.string.contacts_and_subscriptions)
- .withIcon(GoogleMaterial.Icon.gmd_contacts));
+ .withName(R.string.contacts_and_subscriptions)
+ .withIcon(GoogleMaterial.Icon.gmd_contacts));
drawerItems.add(new PrimaryDrawerItem()
- .withName(R.string.settings)
- .withIcon(GoogleMaterial.Icon.gmd_settings));
+ .withName(R.string.settings)
+ .withIcon(GoogleMaterial.Icon.gmd_settings));
drawer = new DrawerBuilder()
- .withActivity(this)
- .withToolbar(toolbar)
- .withAccountHeader(accountHeader)
- .withDrawerItems(drawerItems)
- .addStickyDrawerItems(
- new SwitchDrawerItem()
- .withName(R.string.full_node)
- .withIcon(CommunityMaterial.Icon.cmd_cloud_outline)
- .withChecked(isRunning())
- .withOnCheckedChangeListener(new OnCheckedChangeListener() {
- @Override
- public void onCheckedChanged(IDrawerItem drawerItem,
- CompoundButton buttonView,
- boolean isChecked) {
- if (isChecked) {
- checkAndStartNode(buttonView);
- } else {
- service.shutdownNode();
- }
- }
- })
- )
- .withOnDrawerItemClickListener(new Drawer.OnDrawerItemClickListener() {
- @Override
- public boolean onItemClick(AdapterView> adapterView, View view, int i, long
- l, IDrawerItem item) {
- if (item.getTag() instanceof Label) {
- selectedLabel = (Label) item.getTag();
- showSelectedLabel();
- return false;
- } else if (item instanceof Nameable>) {
- Nameable> ni = (Nameable>) item;
- switch (ni.getNameRes()) {
- case R.string.contacts_and_subscriptions:
- if (!(getSupportFragmentManager().findFragmentById(R.id
- .item_list) instanceof AddressListFragment)) {
- changeList(new AddressListFragment());
- } else {
- ((AddressListFragment) getSupportFragmentManager()
- .findFragmentById(R.id.item_list)).updateList();
- }
-
- break;
- case R.string.settings:
- startActivity(new Intent(MainActivity.this, SettingsActivity
- .class));
- break;
- case R.string.archive:
- selectedLabel = null;
- showSelectedLabel();
- break;
- case R.string.full_node:
- return true;
+ .withActivity(this)
+ .withToolbar(toolbar)
+ .withAccountHeader(accountHeader)
+ .withDrawerItems(drawerItems)
+ .addStickyDrawerItems(
+ new SwitchDrawerItem()
+ .withName(R.string.full_node)
+ .withIcon(CommunityMaterial.Icon.cmd_cloud_outline)
+ .withChecked(isRunning())
+ .withOnCheckedChangeListener(new OnCheckedChangeListener() {
+ @Override
+ public void onCheckedChanged(IDrawerItem drawerItem,
+ CompoundButton buttonView,
+ boolean isChecked) {
+ if (isChecked) {
+ checkAndStartNode(buttonView);
+ } else {
+ service.shutdownNode();
}
}
+ })
+ )
+ .withOnDrawerItemClickListener(new Drawer.OnDrawerItemClickListener() {
+ @Override
+ public boolean onItemClick(View view, int position, IDrawerItem item) {
+ if (item.getTag() instanceof Label) {
+ selectedLabel = (Label) item.getTag();
+ showSelectedLabel();
return false;
+ } else if (item instanceof Nameable>) {
+ Nameable> ni = (Nameable>) item;
+ switch (ni.getName().getTextRes()) {
+ case R.string.contacts_and_subscriptions:
+ if (!(getSupportFragmentManager().findFragmentById(R.id
+ .item_list) instanceof AddressListFragment)) {
+ changeList(new AddressListFragment());
+ } else {
+ ((AddressListFragment) getSupportFragmentManager()
+ .findFragmentById(R.id.item_list)).updateList();
+ }
+ break;
+ case R.string.settings:
+ startActivity(new Intent(MainActivity.this, SettingsActivity
+ .class));
+ break;
+ case R.string.archive:
+ selectedLabel = null;
+ showSelectedLabel();
+ break;
+ case R.string.full_node:
+ return true;
+ }
}
- })
- .withShowDrawerOnFirstLaunch(true)
- .build();
+ return false;
+ }
+ })
+ .withShowDrawerOnFirstLaunch(true)
+ .build();
}
private void addIdentityDialog() {
new AlertDialog.Builder(MainActivity.this)
- .setMessage(R.string.add_identity_warning)
- .setPositiveButton(android.R.string.yes, new
- DialogInterface.OnClickListener() {
+ .setMessage(R.string.add_identity_warning)
+ .setPositiveButton(android.R.string.yes, new
+ DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog,
+ int which) {
+ Toast.makeText(MainActivity.this,
+ R.string.toast_long_running_operation,
+ Toast.LENGTH_SHORT).show();
+ new AsyncTask() {
@Override
- public void onClick(DialogInterface dialog,
- int which) {
- Toast.makeText(MainActivity.this,
- R.string.toast_long_running_operation,
- Toast.LENGTH_SHORT).show();
- new AsyncTask() {
- @Override
- protected BitmessageAddress doInBackground(Void... args) {
- return bmc.createIdentity(false, Pubkey.Feature.DOES_ACK);
- }
-
- @Override
- protected void onPostExecute(BitmessageAddress chan) {
- Toast.makeText(MainActivity.this,
- R.string.toast_identity_created,
- Toast.LENGTH_SHORT).show();
- addIdentityEntry(chan);
- }
- }.execute();
+ protected BitmessageAddress doInBackground(Void... args) {
+ return bmc.createIdentity(false, Pubkey.Feature.DOES_ACK);
}
- })
- .setNegativeButton(android.R.string.no, null)
- .show();
+
+ @Override
+ protected void onPostExecute(BitmessageAddress chan) {
+ Toast.makeText(MainActivity.this,
+ R.string.toast_identity_created,
+ Toast.LENGTH_SHORT).show();
+ addIdentityEntry(chan);
+ }
+ }.execute();
+ }
+ })
+ .setNegativeButton(android.R.string.no, null)
+ .show();
}
private void addChanDialog() {
@SuppressLint("InflateParams")
final View dialogView = getLayoutInflater().inflate(R.layout.dialog_input_passphrase, null);
new AlertDialog.Builder(MainActivity.this)
- .setMessage(R.string.add_chan)
- .setView(dialogView)
- .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialogInterface, int i) {
- TextView passphrase = (TextView) dialogView.findViewById(R.id.passphrase);
- Toast.makeText(MainActivity.this, R.string.toast_long_running_operation,
- Toast.LENGTH_SHORT).show();
- new AsyncTask() {
- @Override
- protected BitmessageAddress doInBackground(String... args) {
- String pass = args[0];
- BitmessageAddress chan = bmc.createChan(pass);
- chan.setAlias(pass);
- bmc.addresses().save(chan);
- return chan;
- }
+ .setMessage(R.string.add_chan)
+ .setView(dialogView)
+ .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialogInterface, int i) {
+ TextView passphrase = (TextView) dialogView.findViewById(R.id.passphrase);
+ Toast.makeText(MainActivity.this, R.string.toast_long_running_operation,
+ Toast.LENGTH_SHORT).show();
+ new AsyncTask() {
+ @Override
+ protected BitmessageAddress doInBackground(String... args) {
+ String pass = args[0];
+ BitmessageAddress chan = bmc.createChan(pass);
+ chan.setAlias(pass);
+ bmc.addresses().save(chan);
+ return chan;
+ }
- @Override
- protected void onPostExecute(BitmessageAddress chan) {
- Toast.makeText(MainActivity.this,
- R.string.toast_chan_created,
- Toast.LENGTH_SHORT).show();
- addIdentityEntry(chan);
- }
- }.execute(passphrase.getText().toString());
- }
- })
- .setNegativeButton(R.string.cancel, null)
- .show();
+ @Override
+ protected void onPostExecute(BitmessageAddress chan) {
+ Toast.makeText(MainActivity.this,
+ R.string.toast_chan_created,
+ Toast.LENGTH_SHORT).show();
+ addIdentityEntry(chan);
+ }
+ }.execute(passphrase.getText().toString());
+ }
+ })
+ .setNegativeButton(R.string.cancel, null)
+ .show();
}
@Override
@@ -500,18 +498,18 @@ public class MainActivity extends AppCompatActivity
private void addIdentityEntry(BitmessageAddress identity) {
IProfile newProfile = new
- ProfileDrawerItem()
- .withName(identity.toString())
- .withEmail(identity.getAddress())
- .withTag(identity);
+ ProfileDrawerItem()
+ .withName(identity.toString())
+ .withEmail(identity.getAddress())
+ .withTag(identity);
if (accountHeader.getProfiles() != null) {
// we know that there are 3 setting
// elements.
// Set the new profile above them ;)
accountHeader.addProfile(
- newProfile, accountHeader
- .getProfiles().size()
- - 3);
+ newProfile, accountHeader
+ .getProfiles().size()
+ - 3);
} else {
accountHeader.addProfiles(newProfile);
}
@@ -530,20 +528,20 @@ public class MainActivity extends AppCompatActivity
service.startupNode();
} else {
new AlertDialog.Builder(MainActivity.this)
- .setMessage(R.string.full_node_warning)
- .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- service.startupNode();
- }
- })
- .setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- buttonView.setChecked(false);
- }
- })
- .show();
+ .setMessage(R.string.full_node_warning)
+ .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ service.startupNode();
+ }
+ })
+ .setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ buttonView.setChecked(false);
+ }
+ })
+ .show();
}
}
@@ -556,7 +554,7 @@ public class MainActivity extends AppCompatActivity
if (unread > 0) {
((PrimaryDrawerItem) item).withBadge(String.valueOf(unread));
} else {
- ((PrimaryDrawerItem) item).withBadge(null);
+ ((PrimaryDrawerItem) item).withBadge((String) null);
}
}
}
@@ -564,9 +562,9 @@ public class MainActivity extends AppCompatActivity
private void showSelectedLabel() {
if (getSupportFragmentManager().findFragmentById(R.id.item_list) instanceof
- MessageListFragment) {
+ MessageListFragment) {
((MessageListFragment) getSupportFragmentManager()
- .findFragmentById(R.id.item_list)).updateList(selectedLabel);
+ .findFragmentById(R.id.item_list)).updateList(selectedLabel);
} else {
MessageListFragment listFragment = new MessageListFragment();
changeList(listFragment);
@@ -593,12 +591,12 @@ public class MainActivity extends AppCompatActivity
fragment = new AddressDetailFragment();
else
throw new IllegalArgumentException("Plaintext or BitmessageAddress expected, but " +
- "was "
- + item.getClass().getSimpleName());
+ "was "
+ + item.getClass().getSimpleName());
fragment.setArguments(arguments);
getSupportFragmentManager().beginTransaction()
- .replace(R.id.message_detail_container, fragment)
- .commit();
+ .replace(R.id.message_detail_container, fragment)
+ .commit();
} else {
// In single-pane mode, simply start the detail activity
// for the selected item ID.
@@ -609,8 +607,8 @@ public class MainActivity extends AppCompatActivity
detailIntent = new Intent(this, AddressDetailActivity.class);
else
throw new IllegalArgumentException("Plaintext or BitmessageAddress expected, but " +
- "was "
- + item.getClass().getSimpleName());
+ "was "
+ + item.getClass().getSimpleName());
detailIntent.putExtra(MessageDetailFragment.ARG_ITEM, item);
startActivity(detailIntent);
@@ -632,7 +630,7 @@ public class MainActivity extends AppCompatActivity
protected void onStart() {
super.onStart();
bindService(new Intent(this, BitmessageService.class), connection, Context
- .BIND_AUTO_CREATE);
+ .BIND_AUTO_CREATE);
}
@Override
diff --git a/app/src/main/java/ch/dissem/apps/abit/MessageDetailActivity.java b/app/src/main/java/ch/dissem/apps/abit/MessageDetailActivity.java
index 7957185..dbad234 100644
--- a/app/src/main/java/ch/dissem/apps/abit/MessageDetailActivity.java
+++ b/app/src/main/java/ch/dissem/apps/abit/MessageDetailActivity.java
@@ -1,11 +1,6 @@
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;
/**
@@ -17,18 +12,11 @@ import android.view.MenuItem;
* This activity is mostly just a 'shell' activity containing nothing
* more than a {@link MessageDetailFragment}.
*/
-public class MessageDetailActivity extends AppCompatActivity {
+public class MessageDetailActivity extends DetailActivity {
@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);
// savedInstanceState is non-null when there is fragment state
// saved from previous configurations of this activity
@@ -52,21 +40,4 @@ public class MessageDetailActivity extends AppCompatActivity {
.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);
- }
}
diff --git a/app/src/main/java/ch/dissem/apps/abit/MessageDetailFragment.java b/app/src/main/java/ch/dissem/apps/abit/MessageDetailFragment.java
index b67cee5..6afb2d0 100644
--- a/app/src/main/java/ch/dissem/apps/abit/MessageDetailFragment.java
+++ b/app/src/main/java/ch/dissem/apps/abit/MessageDetailFragment.java
@@ -44,6 +44,7 @@ import ch.dissem.bitmessage.entity.valueobject.Label;
import ch.dissem.bitmessage.ports.MessageRepository;
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_RECIPIENT;
import static ch.dissem.apps.abit.ComposeMessageActivity.EXTRA_SUBJECT;
@@ -100,7 +101,7 @@ public class MessageDetailFragment extends Fragment {
((TextView) rootView.findViewById(R.id.subject)).setText(item.getSubject());
BitmessageAddress sender = item.getFrom();
((ImageView) rootView.findViewById(R.id.avatar)).setImageDrawable(new Identicon
- (sender));
+ (sender));
((TextView) rootView.findViewById(R.id.sender)).setText(sender.toString());
if (item.getTo() != null) {
((TextView) rootView.findViewById(R.id.recipient)).setText(item.getTo().toString());
@@ -112,11 +113,11 @@ public class MessageDetailFragment extends Fragment {
Linkify.addLinks(messageBody, WEB_URLS);
Linkify.addLinks(messageBody, BITMESSAGE_ADDRESS_PATTERN, BITMESSAGE_URL_SCHEMA, null,
- new TransformFilter() {
- public final String transformUrl(final Matcher match, String url) {
- return match.group();
- }
- });
+ new TransformFilter() {
+ public final String transformUrl(final Matcher match, String url) {
+ return match.group();
+ }
+ });
messageBody.setLinksClickable(true);
messageBody.setTextIsSelectable(true);
@@ -146,7 +147,7 @@ public class MessageDetailFragment extends Fragment {
Drawables.addIcon(getActivity(), menu, R.id.reply, GoogleMaterial.Icon.gmd_reply);
Drawables.addIcon(getActivity(), menu, R.id.delete, GoogleMaterial.Icon.gmd_delete);
Drawables.addIcon(getActivity(), menu, R.id.mark_unread, GoogleMaterial.Icon
- .gmd_markunread);
+ .gmd_markunread);
Drawables.addIcon(getActivity(), menu, R.id.archive, GoogleMaterial.Icon.gmd_archive);
super.onCreateOptionsMenu(menu, inflater);
@@ -158,17 +159,20 @@ public class MessageDetailFragment extends Fragment {
switch (menuItem.getItemId()) {
case R.id.reply:
Intent replyIntent = new Intent(getActivity().getApplicationContext(),
- ComposeMessageActivity.class);
+ ComposeMessageActivity.class);
replyIntent.putExtra(EXTRA_RECIPIENT, item.getFrom());
replyIntent.putExtra(EXTRA_IDENTITY, item.getTo());
String prefix;
if (item.getSubject().length() >= 3 && item.getSubject().substring(0, 3)
- .equalsIgnoreCase("RE:")) {
+ .equalsIgnoreCase("RE:")) {
prefix = "";
} else {
prefix = "RE: ";
}
replyIntent.putExtra(EXTRA_SUBJECT, prefix + item.getSubject());
+ replyIntent.putExtra(EXTRA_CONTENT,
+ "\n\n------------------------------------------------------\n"
+ + item.getText());
startActivity(replyIntent);
return true;
case R.id.delete:
diff --git a/app/src/main/java/ch/dissem/apps/abit/SettingsActivity.java b/app/src/main/java/ch/dissem/apps/abit/SettingsActivity.java
index 6a86ef2..07f4cc7 100644
--- a/app/src/main/java/ch/dissem/apps/abit/SettingsActivity.java
+++ b/app/src/main/java/ch/dissem/apps/abit/SettingsActivity.java
@@ -7,22 +7,14 @@ import android.support.v7.widget.Toolbar;
/**
* @author Christian Basler
*/
-public class SettingsActivity extends AppCompatActivity {
+public class SettingsActivity extends DetailActivity {
@Override
protected void onCreate(Bundle 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.
getFragmentManager().beginTransaction()
.replace(R.id.content, new SettingsFragment())
.commit();
}
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/ch/dissem/apps/abit/StatusActivity.java b/app/src/main/java/ch/dissem/apps/abit/StatusActivity.java
index 1babcf6..cefd609 100644
--- a/app/src/main/java/ch/dissem/apps/abit/StatusActivity.java
+++ b/app/src/main/java/ch/dissem/apps/abit/StatusActivity.java
@@ -21,6 +21,8 @@ import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.widget.TextView;
+import com.mikepenz.materialize.MaterializeBuilder;
+
import ch.dissem.apps.abit.service.Singleton;
import ch.dissem.bitmessage.BitmessageContext;
import ch.dissem.bitmessage.entity.BitmessageAddress;
@@ -39,6 +41,13 @@ public class StatusActivity extends AppCompatActivity {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setHomeButtonEnabled(false);
+ new MaterializeBuilder()
+ .withActivity(this)
+ .withStatusBarColorRes(R.color.colorPrimaryDark)
+ .withTranslucentStatusBarProgrammatically(true)
+ .withStatusBarPadding(true)
+ .build();
+
BitmessageContext bmc = Singleton.getBitmessageContext(this);
StringBuilder status = new StringBuilder();
for (BitmessageAddress address : bmc.addresses().getIdentities()) {
diff --git a/app/src/main/java/ch/dissem/apps/abit/listener/WifiReceiver.java b/app/src/main/java/ch/dissem/apps/abit/listener/WifiReceiver.java
index e4ea8e0..ccd81ac 100644
--- a/app/src/main/java/ch/dissem/apps/abit/listener/WifiReceiver.java
+++ b/app/src/main/java/ch/dissem/apps/abit/listener/WifiReceiver.java
@@ -32,20 +32,29 @@ public class WifiReceiver extends BroadcastReceiver {
if (Preferences.isWifiOnly(ctx)) {
BitmessageContext bmc = Singleton.getBitmessageContext(ctx);
- if (!isConnectedToWifi(ctx) && bmc.isRunning()) {
+ if (isConnectedToMeteredNetwork(ctx) && bmc.isRunning()) {
bmc.shutdown();
}
}
}
- public static boolean isConnectedToWifi(Context ctx) {
+ public static boolean isConnectedToMeteredNetwork(Context 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) {
ConnectivityManager conMan = (ConnectivityManager) ctx.getSystemService(Context
- .CONNECTIVITY_SERVICE);
+ .CONNECTIVITY_SERVICE);
return conMan.getActiveNetworkInfo();
}
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/ch/dissem/apps/abit/repository/AndroidAddressRepository.java b/app/src/main/java/ch/dissem/apps/abit/repository/AndroidAddressRepository.java
index 25c9b2a..4eb3374 100644
--- a/app/src/main/java/ch/dissem/apps/abit/repository/AndroidAddressRepository.java
+++ b/app/src/main/java/ch/dissem/apps/abit/repository/AndroidAddressRepository.java
@@ -119,37 +119,36 @@ public class AndroidAddressRepository implements AddressRepository {
// Define a projection that specifies which columns from the database
// you will actually use after this query.
String[] projection = {
- COLUMN_ADDRESS,
- COLUMN_ALIAS,
- COLUMN_PUBLIC_KEY,
- COLUMN_PRIVATE_KEY,
- COLUMN_SUBSCRIBED,
- COLUMN_CHAN
+ COLUMN_ADDRESS,
+ COLUMN_ALIAS,
+ COLUMN_PUBLIC_KEY,
+ COLUMN_PRIVATE_KEY,
+ COLUMN_SUBSCRIBED,
+ COLUMN_CHAN
};
SQLiteDatabase db = sql.getReadableDatabase();
try (Cursor c = db.query(
- TABLE_NAME, projection,
- where,
- null, null, null, null
+ TABLE_NAME, projection,
+ where,
+ null, null, null, null
)) {
- c.moveToFirst();
- while (!c.isAfterLast()) {
+ while (c.moveToNext()) {
BitmessageAddress address;
byte[] privateKeyBytes = c.getBlob(c.getColumnIndex(COLUMN_PRIVATE_KEY));
if (privateKeyBytes != null) {
PrivateKey privateKey = PrivateKey.read(new ByteArrayInputStream
- (privateKeyBytes));
+ (privateKeyBytes));
address = new BitmessageAddress(privateKey);
} else {
address = new BitmessageAddress(c.getString(c.getColumnIndex(COLUMN_ADDRESS)));
byte[] publicKeyBytes = c.getBlob(c.getColumnIndex(COLUMN_PUBLIC_KEY));
if (publicKeyBytes != null) {
Pubkey pubkey = Factory.readPubkey(address.getVersion(), address
- .getStream(),
- new ByteArrayInputStream(publicKeyBytes), publicKeyBytes.length,
- false);
+ .getStream(),
+ new ByteArrayInputStream(publicKeyBytes), publicKeyBytes.length,
+ false);
if (address.getVersion() == 4 && pubkey instanceof V3Pubkey) {
pubkey = new V4Pubkey((V3Pubkey) pubkey);
}
@@ -161,7 +160,6 @@ public class AndroidAddressRepository implements AddressRepository {
address.setSubscribed(c.getInt(c.getColumnIndex(COLUMN_SUBSCRIBED)) == 1);
result.add(address);
- c.moveToNext();
}
} catch (IOException e) {
LOG.error(e.getMessage(), e);
@@ -184,8 +182,10 @@ public class AndroidAddressRepository implements AddressRepository {
private boolean exists(BitmessageAddress address) {
SQLiteDatabase db = sql.getReadableDatabase();
- try (Cursor cursor = db.rawQuery("SELECT COUNT(*) FROM Address WHERE address='" + address
- .getAddress() + "'", null)) {
+ try (Cursor cursor = db.rawQuery(
+ "SELECT COUNT(*) FROM Address WHERE address=?",
+ new String[]{address.getAddress()}
+ )) {
cursor.moveToFirst();
return cursor.getInt(0) > 0;
}
@@ -210,8 +210,8 @@ public class AndroidAddressRepository implements AddressRepository {
values.put(COLUMN_CHAN, address.isChan());
values.put(COLUMN_SUBSCRIBED, address.isSubscribed());
- int update = db.update(TABLE_NAME, values, "address = '" + address.getAddress() +
- "'", null);
+ int update = db.update(TABLE_NAME, values, "address=?",
+ new String[]{address.getAddress()});
if (update < 0) {
LOG.error("Could not update address " + address);
}
diff --git a/app/src/main/java/ch/dissem/apps/abit/repository/AndroidInventory.java b/app/src/main/java/ch/dissem/apps/abit/repository/AndroidInventory.java
index c88ca2a..8632679 100644
--- a/app/src/main/java/ch/dissem/apps/abit/repository/AndroidInventory.java
+++ b/app/src/main/java/ch/dissem/apps/abit/repository/AndroidInventory.java
@@ -25,7 +25,6 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.ByteArrayInputStream;
-import java.io.IOException;
import java.util.Iterator;
import java.util.LinkedList;
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.bitmessage.utils.UnixTime.MINUTE;
import static ch.dissem.bitmessage.utils.UnixTime.now;
+import static java.lang.String.valueOf;
/**
* {@link Inventory} implementation using the Android SQL API.
@@ -88,21 +88,19 @@ public class AndroidInventory implements Inventory {
cache.put(stream, result);
String[] projection = {
- COLUMN_HASH, COLUMN_EXPIRES
+ COLUMN_HASH, COLUMN_EXPIRES
};
SQLiteDatabase db = sql.getReadableDatabase();
try (Cursor c = db.query(
- TABLE_NAME, projection,
- "stream = " + stream,
- null, null, null, null
+ TABLE_NAME, projection,
+ "stream = " + stream,
+ null, null, null, null
)) {
- c.moveToFirst();
- while (!c.isAfterLast()) {
+ while (c.moveToNext()) {
byte[] blob = c.getBlob(c.getColumnIndex(COLUMN_HASH));
long expires = c.getLong(c.getColumnIndex(COLUMN_EXPIRES));
result.put(new InventoryVector(blob), expires);
- c.moveToNext();
}
}
LOG.info("Stream #" + stream + " inventory size: " + result.size());
@@ -126,18 +124,17 @@ public class AndroidInventory implements Inventory {
// Define a projection that specifies which columns from the database
// you will actually use after this query.
String[] projection = {
- COLUMN_VERSION,
- COLUMN_DATA
+ COLUMN_VERSION,
+ COLUMN_DATA
};
SQLiteDatabase db = sql.getReadableDatabase();
try (Cursor c = db.query(
- TABLE_NAME, projection,
- "hash = X'" + vector + "'",
- null, null, null, null
+ TABLE_NAME, projection,
+ "hash = X'" + vector + "'",
+ null, null, null, null
)) {
- c.moveToFirst();
- if (c.isAfterLast()) {
+ if (!c.moveToFirst()) {
LOG.info("Object requested that we don't have. IV: " + vector);
return null;
}
@@ -153,8 +150,8 @@ public class AndroidInventory implements Inventory {
// Define a projection that specifies which columns from the database
// you will actually use after this query.
String[] projection = {
- COLUMN_VERSION,
- COLUMN_DATA
+ COLUMN_VERSION,
+ COLUMN_DATA
};
StringBuilder where = new StringBuilder("1=1");
if (stream > 0) {
@@ -170,17 +167,15 @@ public class AndroidInventory implements Inventory {
SQLiteDatabase db = sql.getReadableDatabase();
List result = new LinkedList<>();
try (Cursor c = db.query(
- TABLE_NAME, projection,
- where.toString(),
- null, null, null, null
+ TABLE_NAME, projection,
+ where.toString(),
+ null, null, null, null
)) {
- c.moveToFirst();
- while (!c.isAfterLast()) {
+ while (c.moveToNext()) {
int objectVersion = c.getInt(c.getColumnIndex(COLUMN_VERSION));
byte[] blob = c.getBlob(c.getColumnIndex(COLUMN_DATA));
result.add(Factory.getObjectMessage(objectVersion, new ByteArrayInputStream(blob),
- blob.length));
- c.moveToNext();
+ blob.length));
}
}
return result;
@@ -211,8 +206,6 @@ public class AndroidInventory implements Inventory {
getCache(object.getStream()).put(iv, object.getExpiresTime());
} catch (SQLiteConstraintException 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() {
long fiveMinutesAgo = now() - 5 * MINUTE;
SQLiteDatabase db = sql.getWritableDatabase();
- db.delete(TABLE_NAME, "expires < " + fiveMinutesAgo, null);
+ db.delete(TABLE_NAME, "expires < ?", new String[]{valueOf(fiveMinutesAgo)});
for (Map c : cache.values()) {
Iterator> iterator = c.entrySet().iterator();
diff --git a/app/src/main/java/ch/dissem/apps/abit/repository/AndroidMessageRepository.java b/app/src/main/java/ch/dissem/apps/abit/repository/AndroidMessageRepository.java
index 5a1765e..f430f66 100644
--- a/app/src/main/java/ch/dissem/apps/abit/repository/AndroidMessageRepository.java
+++ b/app/src/main/java/ch/dissem/apps/abit/repository/AndroidMessageRepository.java
@@ -41,6 +41,8 @@ import ch.dissem.bitmessage.ports.AbstractMessageRepository;
import ch.dissem.bitmessage.ports.MessageRepository;
import ch.dissem.bitmessage.utils.Encode;
+import static java.lang.String.valueOf;
+
/**
* {@link MessageRepository} implementation using the Android SQL API.
*/
@@ -87,23 +89,21 @@ public class AndroidMessageRepository extends AbstractMessageRepository {
// Define a projection that specifies which columns from the database
// you will actually use after this query.
String[] projection = {
- LBL_COLUMN_ID,
- LBL_COLUMN_LABEL,
- LBL_COLUMN_TYPE,
- LBL_COLUMN_COLOR
+ LBL_COLUMN_ID,
+ LBL_COLUMN_LABEL,
+ LBL_COLUMN_TYPE,
+ LBL_COLUMN_COLOR
};
SQLiteDatabase db = sql.getReadableDatabase();
try (Cursor c = db.query(
- LBL_TABLE_NAME, projection,
- where,
- null, null, null,
- LBL_COLUMN_ORDER
+ LBL_TABLE_NAME, projection,
+ where,
+ null, null, null,
+ LBL_COLUMN_ORDER
)) {
- c.moveToFirst();
- while (!c.isAfterLast()) {
+ while (c.moveToNext()) {
result.add(getLabel(c));
- c.moveToNext();
}
}
return result;
@@ -140,26 +140,34 @@ public class AndroidMessageRepository extends AbstractMessageRepository {
}
}
Label label = new Label(
- text,
- type,
- c.getInt(c.getColumnIndex(LBL_COLUMN_COLOR)));
+ text,
+ type,
+ c.getInt(c.getColumnIndex(LBL_COLUMN_COLOR)));
label.setId(c.getLong(c.getColumnIndex(LBL_COLUMN_ID)));
return label;
}
@Override
public int countUnread(Label label) {
+ String[] args;
String where;
if (label != null) {
- where = "id IN (SELECT message_id FROM Message_Label WHERE label_id=" + label.getId()
- + ") AND ";
+ where = "id IN (SELECT message_id FROM Message_Label WHERE label_id=?) AND ";
+ args = new String[]{
+ label.getId().toString(),
+ Label.Type.UNREAD.name()
+ };
} else {
where = "";
+ args = new String[]{
+ Label.Type.UNREAD.name()
+ };
}
SQLiteDatabase db = sql.getReadableDatabase();
return (int) DatabaseUtils.queryNumEntries(db, TABLE_NAME,
- where + "id IN (SELECT message_id FROM Message_Label WHERE label_id IN (" +
- "SELECT id FROM Label WHERE type = '" + Label.Type.UNREAD.name() + "'))"
+ where + "id IN (SELECT message_id FROM Message_Label WHERE label_id IN (" +
+ "SELECT id FROM Label WHERE type=?))",
+ args
);
}
@@ -169,48 +177,47 @@ public class AndroidMessageRepository extends AbstractMessageRepository {
// Define a projection that specifies which columns from the database
// you will actually use after this query.
String[] projection = {
- COLUMN_ID,
- COLUMN_IV,
- COLUMN_TYPE,
- COLUMN_SENDER,
- COLUMN_RECIPIENT,
- COLUMN_DATA,
- COLUMN_ACK_DATA,
- COLUMN_SENT,
- COLUMN_RECEIVED,
- COLUMN_STATUS,
- COLUMN_TTL,
- COLUMN_RETRIES,
- COLUMN_NEXT_TRY
+ COLUMN_ID,
+ COLUMN_IV,
+ COLUMN_TYPE,
+ COLUMN_SENDER,
+ COLUMN_RECIPIENT,
+ COLUMN_DATA,
+ COLUMN_ACK_DATA,
+ COLUMN_SENT,
+ COLUMN_RECEIVED,
+ COLUMN_STATUS,
+ COLUMN_TTL,
+ COLUMN_RETRIES,
+ COLUMN_NEXT_TRY
};
SQLiteDatabase db = sql.getReadableDatabase();
try (Cursor c = db.query(
- TABLE_NAME, projection,
- where,
- null, null, null,
- COLUMN_RECEIVED + " DESC"
+ TABLE_NAME, projection,
+ where,
+ null, null, null,
+ COLUMN_RECEIVED + " DESC"
)) {
- c.moveToFirst();
- while (!c.isAfterLast()) {
+ while (c.moveToNext()) {
byte[] iv = c.getBlob(c.getColumnIndex(COLUMN_IV));
byte[] data = c.getBlob(c.getColumnIndex(COLUMN_DATA));
Plaintext.Type type = Plaintext.Type.valueOf(c.getString(c.getColumnIndex
- (COLUMN_TYPE)));
+ (COLUMN_TYPE)));
Plaintext.Builder builder = Plaintext.readWithoutSignature(type, new
- ByteArrayInputStream(data));
+ ByteArrayInputStream(data));
long id = c.getLong(c.getColumnIndex(COLUMN_ID));
builder.id(id);
builder.IV(new InventoryVector(iv));
builder.from(ctx.getAddressRepository().getAddress(c.getString(c.getColumnIndex
- (COLUMN_SENDER))));
+ (COLUMN_SENDER))));
builder.to(ctx.getAddressRepository().getAddress(c.getString(c.getColumnIndex
- (COLUMN_RECIPIENT))));
+ (COLUMN_RECIPIENT))));
builder.ackData(c.getBlob(c.getColumnIndex(COLUMN_ACK_DATA)));
builder.sent(c.getLong(c.getColumnIndex(COLUMN_SENT)));
builder.received(c.getLong(c.getColumnIndex(COLUMN_RECEIVED)));
builder.status(Plaintext.Status.valueOf(c.getString(c.getColumnIndex
- (COLUMN_STATUS))));
+ (COLUMN_STATUS))));
builder.ttl(c.getLong(c.getColumnIndex(COLUMN_TTL)));
builder.retries(c.getInt(c.getColumnIndex(COLUMN_RETRIES)));
int nextTryColumn = c.getColumnIndex(COLUMN_NEXT_TRY);
@@ -219,7 +226,6 @@ public class AndroidMessageRepository extends AbstractMessageRepository {
}
builder.labels(findLabels(id));
result.add(builder.build());
- c.moveToNext();
}
} catch (IOException e) {
LOG.error(e.getMessage(), e);
@@ -240,7 +246,7 @@ public class AndroidMessageRepository extends AbstractMessageRepository {
// save from address if necessary
if (message.getId() == null) {
BitmessageAddress savedAddress = ctx.getAddressRepository().getAddress(message
- .getFrom().getAddress());
+ .getFrom().getAddress());
if (savedAddress == null || savedAddress.getPrivateKey() == null) {
if (savedAddress != null && savedAddress.getAlias() != null) {
message.getFrom().setAlias(savedAddress.getAlias());
@@ -257,7 +263,7 @@ public class AndroidMessageRepository extends AbstractMessageRepository {
}
// 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
ContentValues values = new ContentValues();
@@ -279,15 +285,19 @@ public class AndroidMessageRepository extends AbstractMessageRepository {
private void insert(SQLiteDatabase db, Plaintext message) throws IOException {
ContentValues values = new ContentValues();
values.put(COLUMN_IV, message.getInventoryVector() == null ? null : message
- .getInventoryVector().getHash());
+ .getInventoryVector().getHash());
values.put(COLUMN_TYPE, message.getType().name());
values.put(COLUMN_SENDER, message.getFrom().getAddress());
values.put(COLUMN_RECIPIENT, message.getTo() == null ? null : message.getTo().getAddress());
values.put(COLUMN_DATA, Encode.bytes(message));
+ values.put(COLUMN_ACK_DATA, message.getAckData());
values.put(COLUMN_SENT, message.getSent());
values.put(COLUMN_RECEIVED, message.getReceived());
values.put(COLUMN_STATUS, message.getStatus() == null ? null : message.getStatus().name());
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);
message.setId(id);
}
@@ -295,15 +305,19 @@ public class AndroidMessageRepository extends AbstractMessageRepository {
private void update(SQLiteDatabase db, Plaintext message) throws IOException {
ContentValues values = new ContentValues();
values.put(COLUMN_IV, message.getInventoryVector() == null ? null : message
- .getInventoryVector().getHash());
+ .getInventoryVector().getHash());
values.put(COLUMN_TYPE, message.getType().name());
values.put(COLUMN_SENDER, message.getFrom().getAddress());
values.put(COLUMN_RECIPIENT, message.getTo() == null ? null : message.getTo().getAddress());
values.put(COLUMN_DATA, Encode.bytes(message));
+ values.put(COLUMN_ACK_DATA, message.getAckData());
values.put(COLUMN_SENT, message.getSent());
values.put(COLUMN_RECEIVED, message.getReceived());
values.put(COLUMN_STATUS, message.getStatus() == null ? null : message.getStatus().name());
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);
}
diff --git a/app/src/main/java/ch/dissem/apps/abit/repository/AndroidNodeRegistry.java b/app/src/main/java/ch/dissem/apps/abit/repository/AndroidNodeRegistry.java
new file mode 100644
index 0000000..b20c173
--- /dev/null
+++ b/app/src/main/java/ch/dissem/apps/abit/repository/AndroidNodeRegistry.java
@@ -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 loadExistingStatement = new ThreadLocal<>();
+
+ private final SqlHelper sql;
+ private Map> 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 getKnownAddresses(int limit, long... streams) {
+ String[] projection = {
+ COLUMN_STREAM,
+ COLUMN_ADDRESS,
+ COLUMN_PORT,
+ COLUMN_SERVICES,
+ COLUMN_TIME
+ };
+
+ List 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 nodes = stableNodes.get(stream);
+ if (nodes != null && !nodes.isEmpty()) {
+ result.add(Collections.selectRandom(nodes));
+ }
+ }
+ }
+ return result;
+ }
+
+ @Override
+ public void offerAddresses(List 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);
+ }
+ }
+}
diff --git a/app/src/main/java/ch/dissem/apps/abit/repository/AndroidProofOfWorkRepository.java b/app/src/main/java/ch/dissem/apps/abit/repository/AndroidProofOfWorkRepository.java
index 5fccc5d..d27a821 100644
--- a/app/src/main/java/ch/dissem/apps/abit/repository/AndroidProofOfWorkRepository.java
+++ b/app/src/main/java/ch/dissem/apps/abit/repository/AndroidProofOfWorkRepository.java
@@ -25,7 +25,6 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.ByteArrayInputStream;
-import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
@@ -37,12 +36,13 @@ import ch.dissem.bitmessage.utils.Encode;
import ch.dissem.bitmessage.utils.Strings;
import static ch.dissem.bitmessage.utils.Singleton.cryptography;
+import static ch.dissem.bitmessage.utils.Strings.hex;
/**
* @author Christian Basler
*/
public class AndroidProofOfWorkRepository implements ProofOfWorkRepository, InternalContext
- .ContextHolder {
+ .ContextHolder {
private static final Logger LOG = LoggerFactory.getLogger(AndroidProofOfWorkRepository.class);
private static final String TABLE_NAME = "POW";
@@ -71,46 +71,45 @@ public class AndroidProofOfWorkRepository implements ProofOfWorkRepository, Inte
// Define a projection that specifies which columns from the database
// you will actually use after this query.
String[] projection = {
- COLUMN_DATA,
- COLUMN_VERSION,
- COLUMN_NONCE_TRIALS_PER_BYTE,
- COLUMN_EXTRA_BYTES,
- COLUMN_EXPIRATION_TIME,
- COLUMN_MESSAGE_ID
+ COLUMN_DATA,
+ COLUMN_VERSION,
+ COLUMN_NONCE_TRIALS_PER_BYTE,
+ COLUMN_EXTRA_BYTES,
+ COLUMN_EXPIRATION_TIME,
+ COLUMN_MESSAGE_ID
};
SQLiteDatabase db = sql.getReadableDatabase();
try (Cursor c = db.query(
- TABLE_NAME, projection,
- "initial_hash = X'" + Strings.hex(initialHash) + "'",
- null, null, null, null
+ TABLE_NAME, projection,
+ "initial_hash=X'" + hex(initialHash) + "'",
+ null, null, null, null
)) {
- c.moveToFirst();
- if (!c.isAfterLast()) {
+ if (c.moveToFirst()) {
int version = c.getInt(c.getColumnIndex(COLUMN_VERSION));
byte[] blob = c.getBlob(c.getColumnIndex(COLUMN_DATA));
if (c.isNull(c.getColumnIndex(COLUMN_MESSAGE_ID))) {
return new Item(
- Factory.getObjectMessage(version, new ByteArrayInputStream(blob), blob
- .length),
- c.getLong(c.getColumnIndex(COLUMN_NONCE_TRIALS_PER_BYTE)),
- c.getLong(c.getColumnIndex(COLUMN_EXTRA_BYTES))
+ Factory.getObjectMessage(version, new ByteArrayInputStream(blob), blob
+ .length),
+ c.getLong(c.getColumnIndex(COLUMN_NONCE_TRIALS_PER_BYTE)),
+ c.getLong(c.getColumnIndex(COLUMN_EXTRA_BYTES))
);
} else {
return new Item(
- Factory.getObjectMessage(version, new ByteArrayInputStream(blob), blob
- .length),
- c.getLong(c.getColumnIndex(COLUMN_NONCE_TRIALS_PER_BYTE)),
- c.getLong(c.getColumnIndex(COLUMN_EXTRA_BYTES)),
- c.getLong(c.getColumnIndex(COLUMN_EXPIRATION_TIME)),
- bmc.getMessageRepository().getMessage(
- c.getLong(c.getColumnIndex(COLUMN_MESSAGE_ID)))
+ Factory.getObjectMessage(version, new ByteArrayInputStream(blob), blob
+ .length),
+ c.getLong(c.getColumnIndex(COLUMN_NONCE_TRIALS_PER_BYTE)),
+ c.getLong(c.getColumnIndex(COLUMN_EXTRA_BYTES)),
+ c.getLong(c.getColumnIndex(COLUMN_EXPIRATION_TIME)),
+ bmc.getMessageRepository().getMessage(
+ c.getLong(c.getColumnIndex(COLUMN_MESSAGE_ID)))
);
}
}
}
throw new RuntimeException("Object requested that we don't have. Initial hash: " +
- Strings.hex(initialHash));
+ hex(initialHash));
}
@Override
@@ -118,20 +117,18 @@ public class AndroidProofOfWorkRepository implements ProofOfWorkRepository, Inte
// Define a projection that specifies which columns from the database
// you will actually use after this query.
String[] projection = {
- COLUMN_INITIAL_HASH
+ COLUMN_INITIAL_HASH
};
SQLiteDatabase db = sql.getReadableDatabase();
List result = new LinkedList<>();
try (Cursor c = db.query(
- TABLE_NAME, projection,
- null, null, null, null, null
+ TABLE_NAME, projection,
+ null, null, null, null, null
)) {
- c.moveToFirst();
- while (!c.isAfterLast()) {
+ while (c.moveToNext()) {
byte[] initialHash = c.getBlob(c.getColumnIndex(COLUMN_INITIAL_HASH));
result.add(initialHash);
- c.moveToNext();
}
}
return result;
@@ -156,8 +153,6 @@ public class AndroidProofOfWorkRepository implements ProofOfWorkRepository, Inte
db.insertOrThrow(TABLE_NAME, null, values);
} catch (SQLiteConstraintException 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
public void removeObject(byte[] initialHash) {
SQLiteDatabase db = sql.getWritableDatabase();
- db.delete(TABLE_NAME,
- "initial_hash = X'" + Strings.hex(initialHash) + "'",
- null);
+ db.delete(
+ TABLE_NAME,
+ "initial_hash=X'" + hex(initialHash) + "'",
+ null
+ );
}
}
diff --git a/app/src/main/java/ch/dissem/apps/abit/repository/SqlHelper.java b/app/src/main/java/ch/dissem/apps/abit/repository/SqlHelper.java
index 9a0f7ec..87a2bc2 100644
--- a/app/src/main/java/ch/dissem/apps/abit/repository/SqlHelper.java
+++ b/app/src/main/java/ch/dissem/apps/abit/repository/SqlHelper.java
@@ -19,6 +19,7 @@ package ch.dissem.apps.abit.repository;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
+
import ch.dissem.apps.abit.util.Assets;
/**
@@ -26,7 +27,7 @@ import ch.dissem.apps.abit.util.Assets;
*/
public class SqlHelper extends SQLiteOpenHelper {
// 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";
protected final Context ctx;
@@ -38,7 +39,7 @@ public class SqlHelper extends SQLiteOpenHelper {
@Override
public void onCreate(SQLiteDatabase db) {
- onUpgrade(db, 0, 2);
+ onUpgrade(db, 0, DATABASE_VERSION);
}
@Override
@@ -56,8 +57,11 @@ public class SqlHelper extends SQLiteOpenHelper {
case 3:
executeMigration(db, "V3.1__Update_table_POW");
executeMigration(db, "V3.2__Update_table_message");
+ case 4:
+ executeMigration(db, "V3.3__Create_table_node");
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.
}
}
diff --git a/app/src/main/java/ch/dissem/apps/abit/service/Singleton.java b/app/src/main/java/ch/dissem/apps/abit/service/Singleton.java
index 178c8bb..1bc0f77 100644
--- a/app/src/main/java/ch/dissem/apps/abit/service/Singleton.java
+++ b/app/src/main/java/ch/dissem/apps/abit/service/Singleton.java
@@ -28,16 +28,17 @@ import ch.dissem.apps.abit.pow.ServerPowEngine;
import ch.dissem.apps.abit.repository.AndroidAddressRepository;
import ch.dissem.apps.abit.repository.AndroidInventory;
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.SqlHelper;
import ch.dissem.apps.abit.util.Constants;
import ch.dissem.bitmessage.BitmessageContext;
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.MemoryNodeRegistry;
import ch.dissem.bitmessage.ports.MessageRepository;
import ch.dissem.bitmessage.ports.ProofOfWorkRepository;
+import ch.dissem.bitmessage.utils.TTL;
import static ch.dissem.bitmessage.utils.UnixTime.DAY;
@@ -58,6 +59,7 @@ public class Singleton {
final Context ctx = context.getApplicationContext();
SqlHelper sqlHelper = new SqlHelper(ctx);
powRepo = new AndroidProofOfWorkRepository(sqlHelper);
+ TTL.pubkey(2 * DAY);
bitmessageContext = new BitmessageContext.Builder()
.proofOfWorkEngine(new SwitchingProofOfWorkEngine(
ctx, Constants.PREFERENCE_SERVER_POW,
@@ -65,15 +67,14 @@ public class Singleton {
new ServicePowEngine(ctx)
))
.cryptography(new AndroidCryptography())
- .nodeRegistry(new MemoryNodeRegistry())
+ .nodeRegistry(new AndroidNodeRegistry(sqlHelper))
.inventory(new AndroidInventory(sqlHelper))
.addressRepo(new AndroidAddressRepository(sqlHelper))
.messageRepo(new AndroidMessageRepository(sqlHelper, ctx))
.powRepo(powRepo)
- .networkHandler(new DefaultNetworkHandler())
+ .networkHandler(new NioNetworkHandler())
.listener(getMessageListener(ctx))
.doNotSendPubkeyOnIdentityCreation()
- .pubkeyTTL(2 * DAY)
.build();
}
}
diff --git a/app/src/main/java/ch/dissem/apps/abit/util/Preferences.java b/app/src/main/java/ch/dissem/apps/abit/util/Preferences.java
index a0cee3f..b7f3d97 100644
--- a/app/src/main/java/ch/dissem/apps/abit/util/Preferences.java
+++ b/app/src/main/java/ch/dissem/apps/abit/util/Preferences.java
@@ -101,7 +101,7 @@ public class Preferences {
}
public static boolean isConnectionAllowed(Context ctx) {
- return !isWifiOnly(ctx) || WifiReceiver.isConnectedToWifi(ctx);
+ return !isWifiOnly(ctx) || !WifiReceiver.isConnectedToMeteredNetwork(ctx);
}
public static boolean isWifiOnly(Context ctx) {
diff --git a/app/src/main/res/values-v21/styles.xml b/app/src/main/res/values-v21/styles.xml
deleted file mode 100644
index 72150b4..0000000
--- a/app/src/main/res/values-v21/styles.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index 8958204..6e7e100 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -1,13 +1,48 @@
- #FFC107
- #FFA000
- #DEFFFFFF
- #FFECB3
- #607D8B
- #212121
- #727272
- #212121
- #B6B6B6
+ #FFC107
+ #FFA000
+ #DEFFFFFF
+ #FFECB3
+ #607D8B
+ #212121
+ #727272
+ #212121
+ #B6B6B6
+
+
+ @color/colorPrimary
+ @color/colorPrimaryDark
+ @color/colorPrimaryLight
+ @color/colorAccent
+
+
+
+ @color/colorPrimaryDark
+
+ @color/colorPrimaryText
+ @color/icons
+ @color/colorSecondaryText
+ @color/colorSecondaryText
+ @color/divider
+
+ @color/primary
+ @color/colorPrimaryText
+ @color/colorPrimaryText
+
+
+
+ #303030
+
+ #DEFFFFFF
+ #8AFFFFFF
+ #8AFFFFFF
+ #42FFFFFF
+ #1FFFFFFF
+
+ #202020
+ @color/material_drawer_primary
+ #FFF
+
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index 58f503e..a299e46 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -1,28 +1,12 @@
-
-
-