Fixed the 'full node' switch, activated the jack tools to support some Java 8 features, and fixed some lint issues

This commit is contained in:
2016-10-16 23:16:38 +02:00
parent a5b3c33394
commit 2b1fb436a9
30 changed files with 367 additions and 436 deletions

View File

@ -23,7 +23,6 @@ import android.view.View;
import android.widget.ListView;
import ch.dissem.apps.abit.listener.ListSelectionListener;
import ch.dissem.bitmessage.entity.valueobject.Label;
/**
* @author Christian Basler
@ -38,11 +37,7 @@ public abstract class AbstractItemListFragment<T> extends ListFragment implement
* A dummy implementation of the {@link ListSelectionListener} interface that does
* nothing. Used only when this fragment is not attached to an activity.
*/
private static ListSelectionListener<Object> dummyCallbacks = new
ListSelectionListener<Object>() {
@Override
public void onItemSelected(Object plaintext) {
}
private static ListSelectionListener<Object> dummyCallbacks = plaintext -> {
};
/**
* The fragment's current callback object, which is notified of list item
@ -61,7 +56,7 @@ public abstract class AbstractItemListFragment<T> extends ListFragment implement
// Restore the previously serialized activated item position.
if (savedInstanceState != null
&& savedInstanceState.containsKey(STATE_ACTIVATED_POSITION)) {
&& savedInstanceState.containsKey(STATE_ACTIVATED_POSITION)) {
setActivatedPosition(savedInstanceState.getInt(STATE_ACTIVATED_POSITION));
}
}
@ -73,8 +68,8 @@ public abstract class AbstractItemListFragment<T> extends ListFragment implement
// When setting CHOICE_MODE_SINGLE, ListView will automatically
// give items the 'activated' state when touched.
getListView().setChoiceMode(activateOnItemClick
? ListView.CHOICE_MODE_SINGLE
: ListView.CHOICE_MODE_NONE);
? ListView.CHOICE_MODE_SINGLE
: ListView.CHOICE_MODE_NONE);
}
@Override
@ -129,8 +124,8 @@ public abstract class AbstractItemListFragment<T> extends ListFragment implement
// When setting CHOICE_MODE_SINGLE, ListView will automatically
// give items the 'activated' state when touched.
getListView().setChoiceMode(activateOnItemClick
? ListView.CHOICE_MODE_SINGLE
: ListView.CHOICE_MODE_NONE);
? ListView.CHOICE_MODE_SINGLE
: ListView.CHOICE_MODE_NONE);
}
}

View File

@ -18,7 +18,6 @@ package ch.dissem.apps.abit;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Bitmap;
import android.os.Bundle;
@ -31,7 +30,6 @@ import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CompoundButton;
import android.widget.ImageView;
import android.widget.Switch;
import android.widget.TextView;
@ -131,19 +129,15 @@ public class AddressDetailFragment extends Fragment {
warning = R.string.delete_contact_warning;
new AlertDialog.Builder(ctx)
.setMessage(warning)
.setPositiveButton(android.R.string.yes, new
DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Singleton.getAddressRepository(ctx).remove(item);
MainActivity mainActivity = MainActivity.getInstance();
if (item.getPrivateKey() != null && mainActivity != null) {
mainActivity.removeIdentityEntry(item);
}
item = null;
ctx.onBackPressed();
}
})
.setPositiveButton(android.R.string.yes, (dialog, which) -> {
Singleton.getAddressRepository(ctx).remove(item);
MainActivity mainActivity = MainActivity.getInstance();
if (item.getPrivateKey() != null && mainActivity != null) {
mainActivity.removeIdentityEntry(item);
}
item = null;
ctx.onBackPressed();
})
.setNegativeButton(android.R.string.no, null)
.show();
return true;
@ -151,22 +145,18 @@ public class AddressDetailFragment extends Fragment {
case R.id.export: {
new AlertDialog.Builder(ctx)
.setMessage(R.string.confirm_export)
.setPositiveButton(android.R.string.yes, new
DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Intent shareIntent = new Intent(Intent.ACTION_SEND);
shareIntent.setType("text/plain");
shareIntent.putExtra(Intent.EXTRA_TITLE, item +
EXPORT_POSTFIX);
WifExporter exporter = new WifExporter(Singleton
.getBitmessageContext(ctx));
exporter.addIdentity(item);
shareIntent.putExtra(Intent.EXTRA_TEXT, exporter.toString
());
startActivity(Intent.createChooser(shareIntent, null));
}
})
.setPositiveButton(android.R.string.yes, (dialog, which) -> {
Intent shareIntent = new Intent(Intent.ACTION_SEND);
shareIntent.setType("text/plain");
shareIntent.putExtra(Intent.EXTRA_TITLE, item +
EXPORT_POSTFIX);
WifExporter exporter = new WifExporter(Singleton
.getBitmessageContext(ctx));
exporter.addIdentity(item);
shareIntent.putExtra(Intent.EXTRA_TEXT, exporter.toString
());
startActivity(Intent.createChooser(shareIntent, null));
})
.setNegativeButton(android.R.string.no, null)
.show();
return true;
@ -216,12 +206,8 @@ public class AddressDetailFragment extends Fragment {
if (item.getPrivateKey() == null) {
Switch active = (Switch) rootView.findViewById(R.id.active);
active.setChecked(item.isSubscribed());
active.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
item.setSubscribed(isChecked);
}
});
active.setOnCheckedChangeListener((buttonView, isChecked) ->
item.setSubscribed(isChecked));
ImageView pubkeyAvailableImg = (ImageView) rootView.findViewById(R.id
.pubkey_available);

View File

@ -20,6 +20,7 @@ import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.MenuItem;
@ -32,7 +33,6 @@ import android.widget.TextView;
import com.google.zxing.integration.android.IntentIntegrator;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import ch.dissem.apps.abit.listener.ActionBarListener;
@ -55,59 +55,53 @@ public class AddressListFragment extends AbstractItemListFragment<BitmessageAddr
public void updateList() {
List<BitmessageAddress> addresses = Singleton.getAddressRepository(getContext())
.getContacts();
Collections.sort(addresses, new Comparator<BitmessageAddress>() {
/**
* Yields the following order:
* <ol>
* <li>Subscribed addresses come first</li>
* <li>Addresses with Aliases (alphabetically)</li>
* <li>Addresses (alphabetically)</li>
* </ol>
*/
@Override
public int compare(BitmessageAddress lhs, BitmessageAddress rhs) {
if (lhs.isSubscribed() == rhs.isSubscribed()) {
if (lhs.getAlias() != null) {
if (rhs.getAlias() != null) {
return lhs.getAlias().compareTo(rhs.getAlias());
} else {
return -1;
}
} else if (rhs.getAlias() != null) {
return 1;
.getContacts();
Collections.sort(addresses, (lhs, rhs) -> {
// Yields the following order:
// * Subscribed addresses come first
// * Addresses with Aliases (alphabetically)
// * Addresses (alphabetically)
if (lhs.isSubscribed() == rhs.isSubscribed()) {
if (lhs.getAlias() != null) {
if (rhs.getAlias() != null) {
return lhs.getAlias().compareTo(rhs.getAlias());
} else {
return lhs.getAddress().compareTo(rhs.getAddress());
return -1;
}
}
if (lhs.isSubscribed()) {
return -1;
} else {
} else if (rhs.getAlias() != null) {
return 1;
} else {
return lhs.getAddress().compareTo(rhs.getAddress());
}
}
if (lhs.isSubscribed()) {
return -1;
} else {
return 1;
}
});
setListAdapter(new ArrayAdapter<BitmessageAddress>(
getActivity(),
android.R.layout.simple_list_item_activated_1,
android.R.id.text1,
addresses) {
getActivity(),
android.R.layout.simple_list_item_activated_1,
android.R.id.text1,
addresses) {
@NonNull
@Override
public View getView(int position, View convertView, ViewGroup parent) {
public View getView(int position, View convertView, @NonNull ViewGroup parent) {
if (convertView == null) {
LayoutInflater inflater = LayoutInflater.from(getContext());
convertView = inflater.inflate(R.layout.subscription_row, null, false);
convertView = inflater.inflate(R.layout.subscription_row, parent, false);
}
BitmessageAddress item = getItem(position);
((ImageView) convertView.findViewById(R.id.avatar)).setImageDrawable(new
Identicon(item));
Identicon(item));
TextView name = (TextView) convertView.findViewById(R.id.name);
name.setText(item.toString());
TextView streamNumber = (TextView) convertView.findViewById(R.id.stream_number);
streamNumber.setText(getContext().getString(R.string.stream_number, item
.getStream()));
.getStream()));
convertView.findViewById(R.id.subscribed).setVisibility(item.isSubscribed() ?
View.VISIBLE : View.INVISIBLE);
View.VISIBLE : View.INVISIBLE);
return convertView;
}
});
@ -124,7 +118,7 @@ public class AddressListFragment extends AbstractItemListFragment<BitmessageAddr
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle
savedInstanceState) {
savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_address_list, container, false);
FabSpeedDial fabSpeedDial = (FabSpeedDial) view.findViewById(R.id.fab_add_contact);
@ -134,8 +128,8 @@ public class AddressListFragment extends AbstractItemListFragment<BitmessageAddr
switch (menuItem.getItemId()) {
case R.id.action_read_qr_code:
IntentIntegrator.forSupportFragment(AddressListFragment.this)
.setDesiredBarcodeFormats(IntentIntegrator.QR_CODE_TYPES)
.initiateScan();
.setDesiredBarcodeFormats(IntentIntegrator.QR_CODE_TYPES)
.initiateScan();
return true;
case R.id.action_create_contact:
Intent intent = new Intent(getActivity(), CreateAddressActivity.class);

View File

@ -18,7 +18,6 @@ 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;
@ -90,12 +89,9 @@ public class ComposeMessageFragment extends Fragment {
recipientInput = (AutoCompleteTextView) rootView.findViewById(R.id.recipient);
final ContactAdapter adapter = new ContactAdapter(getContext());
recipientInput.setAdapter(adapter);
recipientInput.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
recipient = adapter.getItem(position);
}
});
recipientInput.setOnItemClickListener(
(parent, view, position, id) -> recipient = adapter.getItem(position)
);
recipientInput.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {

View File

@ -42,9 +42,6 @@ import ch.dissem.bitmessage.wif.WifImporter;
public class ImportIdentitiesFragment extends Fragment {
public static final String WIF_DATA = "wif_data";
private BitmessageContext bmc;
private RecyclerView recyclerView;
private LinearLayoutManager layoutManager;
private AddressSelectorAdapter adapter;
private WifImporter importer;
@ -53,14 +50,15 @@ public class ImportIdentitiesFragment extends Fragment {
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle
savedInstanceState) {
String wifData = getArguments().getString(WIF_DATA);
bmc = Singleton.getBitmessageContext(getActivity());
BitmessageContext bmc = Singleton.getBitmessageContext(getActivity());
View view = inflater.inflate(R.layout.fragment_import_select_identities, container, false);
try {
importer = new WifImporter(bmc, wifData);
adapter = new AddressSelectorAdapter(importer.getIdentities());
layoutManager = new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL,
LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity(),
LinearLayoutManager.VERTICAL,
false);
recyclerView = (RecyclerView) view.findViewById(R.id.recycler_view);
RecyclerView recyclerView = (RecyclerView) view.findViewById(R.id.recycler_view);
recyclerView.setLayoutManager(layoutManager);
recyclerView.setAdapter(adapter);
@ -69,18 +67,15 @@ public class ImportIdentitiesFragment extends Fragment {
} catch (IOException e) {
return super.onCreateView(inflater, container, savedInstanceState);
}
view.findViewById(R.id.finish).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
importer.importAll(adapter.getSelected());
MainActivity mainActivity = MainActivity.getInstance();
if (mainActivity != null) {
for (BitmessageAddress selected : adapter.getSelected()) {
mainActivity.addIdentityEntry(selected);
}
view.findViewById(R.id.finish).setOnClickListener(v -> {
importer.importAll(adapter.getSelected());
MainActivity mainActivity = MainActivity.getInstance();
if (mainActivity != null) {
for (BitmessageAddress selected : adapter.getSelected()) {
mainActivity.addIdentityEntry(selected);
}
getActivity().finish();
}
getActivity().finish();
});
return view;
}

View File

@ -19,7 +19,6 @@ package ch.dissem.apps.abit;
import android.app.AlertDialog;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.ServiceConnection;
import android.graphics.Point;
@ -34,7 +33,6 @@ import android.widget.CompoundButton;
import android.widget.RelativeLayout;
import com.github.amlcurran.showcaseview.ShowcaseView;
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;
@ -42,7 +40,6 @@ import com.mikepenz.materialdrawer.AccountHeader;
import com.mikepenz.materialdrawer.AccountHeaderBuilder;
import com.mikepenz.materialdrawer.Drawer;
import com.mikepenz.materialdrawer.DrawerBuilder;
import com.mikepenz.materialdrawer.interfaces.OnCheckedChangeListener;
import com.mikepenz.materialdrawer.model.DividerDrawerItem;
import com.mikepenz.materialdrawer.model.PrimaryDrawerItem;
import com.mikepenz.materialdrawer.model.ProfileDrawerItem;
@ -102,7 +99,8 @@ public class MainActivity extends AppCompatActivity
private static final Logger LOG = LoggerFactory.getLogger(MainActivity.class);
private static final int ADD_IDENTITY = 1;
private static final int MANAGE_IDENTITY = 2;
private static final int ADD_CHAN = 3;
private static final long ID_NODE_SWITCH = 1;
private static WeakReference<MainActivity> instance;
@ -134,7 +132,7 @@ public class MainActivity extends AppCompatActivity
private AccountHeader accountHeader;
private Drawer drawer;
private ShowcaseView showcaseView;
private SwitchDrawerItem nodeSwitch;
@Override
protected void onCreate(Bundle savedInstanceState) {
@ -152,7 +150,9 @@ public class MainActivity extends AppCompatActivity
setSupportActionBar(toolbar);
MessageListFragment listFragment = new MessageListFragment();
getSupportFragmentManager().beginTransaction().replace(R.id.item_list, listFragment)
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.item_list, listFragment)
.commit();
if (findViewById(R.id.message_detail_container) != null) {
@ -189,27 +189,23 @@ public class MainActivity extends AppCompatActivity
int margin = ((Number) (getResources().getDisplayMetrics().density * 12)).intValue();
lps.setMargins(margin, margin, margin, margin);
showcaseView = new ShowcaseView.Builder(this)
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);
}
}
)
.setTarget(() -> {
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();
showcaseView.setButtonPosition(lps);
.build()
.setButtonPosition(lps);
}
}
@ -268,32 +264,28 @@ public class MainActivity extends AppCompatActivity
.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 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);
}
.withOnAccountHeaderListener((view, profile, currentProfile) -> {
switch ((int) profile.getIdentifier()) {
case ADD_IDENTITY:
addIdentityDialog();
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;
}
}
// false if it should close the drawer
return false;
})
.build();
if (profiles.size() > 2) { // There's always the add and manage identity items
@ -346,62 +338,55 @@ public class MainActivity extends AppCompatActivity
.withName(R.string.settings)
.withIcon(GoogleMaterial.Icon.gmd_settings));
nodeSwitch = new SwitchDrawerItem()
.withIdentifier(ID_NODE_SWITCH)
.withName(R.string.full_node)
.withIcon(CommunityMaterial.Icon.cmd_cloud_outline)
.withChecked(isRunning())
.withOnCheckedChangeListener((drawerItem, buttonView, isChecked) -> {
if (isChecked) {
checkAndStartNode(buttonView);
} else {
service.shutdownNode();
}
});
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(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;
}
}
.addStickyDrawerItems(nodeSwitch)
.withOnDrawerItemClickListener((view, position, 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;
}
}
return false;
})
.withShowDrawerOnFirstLaunch(true)
.build();
@ -415,6 +400,7 @@ public class MainActivity extends AppCompatActivity
@Override
protected void onResume() {
updateUnread();
updateNodeSwitch();
super.onResume();
}
@ -470,18 +456,14 @@ public class MainActivity extends AppCompatActivity
} 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);
}
})
.setPositiveButton(
android.R.string.yes,
(dialog, which) -> service.startupNode()
)
.setNegativeButton(
android.R.string.no,
(dialog, which) -> updateNodeSwitch()
)
.show();
}
}
@ -501,6 +483,13 @@ public class MainActivity extends AppCompatActivity
}
}
public void updateNodeSwitch() {
runOnUiThread(() -> {
nodeSwitch.withChecked(bmc.isRunning());
drawer.updateStickyFooterItem(nodeSwitch);
});
}
private void showSelectedLabel() {
if (getSupportFragmentManager().findFragmentById(R.id.item_list) instanceof
MessageListFragment) {

View File

@ -1,8 +1,6 @@
package ch.dissem.apps.abit;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
/**
* @author Christian Basler

View File

@ -20,7 +20,6 @@ import android.content.Context;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.FragmentActivity;
import android.support.v7.app.AppCompatDialogFragment;
import android.view.LayoutInflater;
import android.view.View;
@ -41,7 +40,6 @@ import ch.dissem.bitmessage.entity.payload.Pubkey;
/**
* @author Christian Basler
*/
public class DeterministicIdentityDialogFragment extends AppCompatDialogFragment {
private BitmessageContext bmc;
@ -58,76 +56,68 @@ public class DeterministicIdentityDialogFragment extends AppCompatDialogFragment
getDialog().setTitle(R.string.add_deterministic_address);
View view = inflater.inflate(R.layout.dialog_add_deterministic_identity, container, false);
view.findViewById(R.id.ok)
.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dismiss();
final Context context = getActivity().getBaseContext();
View dialogView = getView();
TextView label = (TextView) dialogView.findViewById(R.id.label);
TextView passphrase = (TextView) dialogView.findViewById(R.id.passphrase);
TextView numberOfAddresses = (TextView) dialogView.findViewById(R.id
.number_of_identities);
Switch shorter = (Switch) dialogView.findViewById(R.id.shorter);
.setOnClickListener(v -> {
dismiss();
final Context context = getActivity().getBaseContext();
View dialogView = getView();
TextView label = (TextView) dialogView.findViewById(R.id.label);
TextView passphrase = (TextView) dialogView.findViewById(R.id.passphrase);
TextView numberOfAddresses = (TextView) dialogView.findViewById(R.id
.number_of_identities);
Switch shorter = (Switch) dialogView.findViewById(R.id.shorter);
Toast.makeText(context, R.string.toast_long_running_operation,
Toast.LENGTH_SHORT).show();
new AsyncTask<Object, Void, List<BitmessageAddress>>() {
@Override
protected List<BitmessageAddress> doInBackground(Object... args) {
String label = (String) args[0];
String pass = (String) args[1];
int numberOfAddresses = (int) args[2];
boolean shorter = (boolean) args[3];
List<BitmessageAddress> identities = bmc.createDeterministicAddresses
(pass,
numberOfAddresses, Pubkey.LATEST_VERSION, 1L, shorter);
int i = 0;
for (BitmessageAddress identity : identities) {
i++;
if (identities.size() == 1) {
identity.setAlias(label);
} else {
identity.setAlias(label + " (" + i + ")");
}
bmc.addresses().save(identity);
}
return identities;
}
@Override
protected void onPostExecute(List<BitmessageAddress> identities) {
int messageRes;
Toast.makeText(context, R.string.toast_long_running_operation,
Toast.LENGTH_SHORT).show();
new AsyncTask<Object, Void, List<BitmessageAddress>>() {
@Override
protected List<BitmessageAddress> doInBackground(Object... args) {
String label = (String) args[0];
String pass = (String) args[1];
int numberOfAddresses = (int) args[2];
boolean shorter = (boolean) args[3];
List<BitmessageAddress> identities = bmc.createDeterministicAddresses
(pass,
numberOfAddresses, Pubkey.LATEST_VERSION, 1L, shorter);
int i = 0;
for (BitmessageAddress identity : identities) {
i++;
if (identities.size() == 1) {
messageRes = R.string.toast_identity_created;
identity.setAlias(label);
} else {
messageRes = R.string.toast_identities_created;
identity.setAlias(label + " (" + i + ")");
}
Toast.makeText(context,
messageRes,
Toast.LENGTH_SHORT).show();
MainActivity mainActivity = MainActivity.getInstance();
if (mainActivity != null) {
for (BitmessageAddress identity : identities) {
mainActivity.addIdentityEntry(identity);
}
bmc.addresses().save(identity);
}
return identities;
}
@Override
protected void onPostExecute(List<BitmessageAddress> identities) {
int messageRes;
if (identities.size() == 1) {
messageRes = R.string.toast_identity_created;
} else {
messageRes = R.string.toast_identities_created;
}
Toast.makeText(context,
messageRes,
Toast.LENGTH_SHORT).show();
MainActivity mainActivity = MainActivity.getInstance();
if (mainActivity != null) {
for (BitmessageAddress identity : identities) {
mainActivity.addIdentityEntry(identity);
}
}
}.execute(
label.getText().toString(),
passphrase.getText().toString(),
Integer.valueOf(numberOfAddresses.getText().toString()),
shorter.isChecked()
);
}
}
}.execute(
label.getText().toString(),
passphrase.getText().toString(),
Integer.valueOf(numberOfAddresses.getText().toString()),
shorter.isChecked()
);
});
view.findViewById(R.id.dismiss)
.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dismiss();
}
});
.setOnClickListener(v -> dismiss());
return view;
}

View File

@ -17,7 +17,6 @@
package ch.dissem.apps.abit.notification;
import android.annotation.SuppressLint;
import android.app.Notification;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
@ -28,7 +27,7 @@ import java.util.TimerTask;
import ch.dissem.apps.abit.MainActivity;
import ch.dissem.apps.abit.R;
import ch.dissem.bitmessage.BitmessageContext;
import ch.dissem.apps.abit.service.BitmessageService;
import ch.dissem.bitmessage.utils.Property;
/**
@ -37,31 +36,32 @@ import ch.dissem.bitmessage.utils.Property;
public class NetworkNotification extends AbstractNotification {
public static final int ONGOING_NOTIFICATION_ID = 2;
private final BitmessageContext bmc;
private NotificationCompat.Builder builder;
public NetworkNotification(Context ctx, BitmessageContext bmc) {
public NetworkNotification(Context ctx) {
super(ctx);
this.bmc = bmc;
Intent showMessageIntent = new Intent(ctx, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(ctx, 1, showMessageIntent, 0);
builder = new NotificationCompat.Builder(ctx);
builder.setSmallIcon(R.drawable.ic_notification_full_node)
.setContentTitle(ctx.getString(R.string.bitmessage_full_node))
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC);
}
@Override
public Notification getNotification() {
update();
return notification;
.setContentTitle(ctx.getString(R.string.bitmessage_full_node))
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
.setShowWhen(false)
.setContentIntent(pendingIntent);
}
@SuppressLint("StringFormatMatches")
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
private boolean update() {
boolean running = bmc.isRunning();
boolean running = BitmessageService.isRunning();
builder.setOngoing(running);
Property connections = bmc.status().getProperty("network").getProperty("connections");
Property connections = BitmessageService.getStatus().getProperty("network", "connections");
if (!running) {
builder.setContentText(ctx.getString(R.string.connection_info_disconnected));
MainActivity mainActivity = MainActivity.getInstance();
if (mainActivity != null) {
mainActivity.updateNodeSwitch();
}
} else if (connections.getProperties().length == 0) {
builder.setContentText(ctx.getString(R.string.connection_info_pending));
} else {
@ -71,29 +71,24 @@ public class NetworkNotification extends AbstractNotification {
Integer nodeCount = (Integer) stream.getProperty("nodes").getValue();
if (nodeCount == 1) {
info.append(ctx.getString(R.string.connection_info_1,
streamNumber));
streamNumber));
} else {
info.append(ctx.getString(R.string.connection_info_n,
streamNumber, nodeCount));
streamNumber, nodeCount));
}
info.append('\n');
}
builder.setContentText(info);
}
Intent showMessageIntent = new Intent(ctx, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(ctx, 1, showMessageIntent, 0);
builder.setContentIntent(pendingIntent);
notification = builder.build();
return running;
}
@Override
public void show() {
update();
super.show();
final Timer timer = new Timer();
timer.schedule(new TimerTask() {
new Timer().schedule(new TimerTask() {
@Override
public void run() {
if (!update()) {
@ -108,4 +103,10 @@ public class NetworkNotification extends AbstractNotification {
protected int getNotificationId() {
return ONGOING_NOTIFICATION_ID;
}
public void connecting() {
builder.setOngoing(true);
builder.setContentText(ctx.getString(R.string.connection_info_pending));
notification = builder.build();
}
}

View File

@ -36,7 +36,7 @@ import ch.dissem.bitmessage.entity.Plaintext;
import static ch.dissem.apps.abit.util.Drawables.toBitmap;
public class NewMessageNotification extends AbstractNotification {
public static final int NEW_MESSAGE_NOTIFICATION_ID = 1;
private static final int NEW_MESSAGE_NOTIFICATION_ID = 1;
private static final StyleSpan SPAN_EMPHASIS = new StyleSpan(Typeface.BOLD);
public NewMessageNotification(Context ctx) {
@ -62,6 +62,7 @@ public class NewMessageNotification extends AbstractNotification {
PendingIntent.FLAG_UPDATE_CURRENT);
builder.setContentIntent(pendingIntent);
// TODO: add proper intents to reply/delete
builder.addAction(R.drawable.ic_action_reply, ctx.getString(R.string.reply), pendingIntent);
builder.addAction(R.drawable.ic_action_delete, ctx.getString(R.string.delete),
pendingIntent);

View File

@ -196,7 +196,9 @@ public class AndroidAddressRepository implements AddressRepository {
SQLiteDatabase db = sql.getWritableDatabase();
// Create a new map of values, where column names are the keys
ContentValues values = new ContentValues();
values.put(COLUMN_ALIAS, address.getAlias());
if (address.getAlias() != null) {
values.put(COLUMN_ALIAS, address.getAlias());
}
if (address.getPubkey() != null) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
address.getPubkey().writeUnencrypted(out);
@ -207,7 +209,9 @@ public class AndroidAddressRepository implements AddressRepository {
if (address.getPrivateKey() != null) {
values.put(COLUMN_PRIVATE_KEY, Encode.bytes(address.getPrivateKey()));
}
values.put(COLUMN_CHAN, address.isChan());
if (address.isChan()) {
values.put(COLUMN_CHAN, true);
}
values.put(COLUMN_SUBSCRIBED, address.isSubscribed());
int update = db.update(TABLE_NAME, values, "address=?",

View File

@ -33,7 +33,6 @@ import ch.dissem.bitmessage.entity.ObjectMessage;
import ch.dissem.bitmessage.factory.Factory;
import ch.dissem.bitmessage.ports.ProofOfWorkRepository;
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;

View File

@ -21,11 +21,9 @@ import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ch.dissem.apps.abit.notification.NetworkNotification;
import ch.dissem.bitmessage.BitmessageContext;
import ch.dissem.bitmessage.utils.Property;
import static ch.dissem.apps.abit.notification.NetworkNotification.ONGOING_NOTIFICATION_ID;
@ -35,12 +33,7 @@ import static ch.dissem.apps.abit.notification.NetworkNotification.ONGOING_NOTIF
* onPerformSync().
*/
public class BitmessageService extends Service {
public static final Logger LOG = LoggerFactory.getLogger(BitmessageService.class);
// Object to use as a thread-safe lock
private static final Object lock = new Object();
private static NetworkNotification notification = null;
private NetworkNotification notification = null;
private static BitmessageContext bmc = null;
private static volatile boolean running = false;
@ -51,11 +44,11 @@ public class BitmessageService extends Service {
@Override
public void onCreate() {
synchronized (lock) {
synchronized (BitmessageService.class) {
if (bmc == null) {
bmc = Singleton.getBitmessageContext(this);
notification = new NetworkNotification(this, bmc);
}
notification = new NetworkNotification(this);
}
}
@ -70,7 +63,6 @@ public class BitmessageService extends Service {
running = false;
}
/**
* Return an object that allows the system to invoke
* the sync adapter.
@ -84,6 +76,7 @@ public class BitmessageService extends Service {
public void startupNode() {
startService(new Intent(BitmessageService.this, BitmessageService.class));
running = true;
notification.connecting();
startForeground(ONGOING_NOTIFICATION_ID, notification.getNotification());
if (!bmc.isRunning()) {
bmc.startup();
@ -96,8 +89,17 @@ public class BitmessageService extends Service {
bmc.shutdown();
}
running = false;
stopForeground(false);
stopForeground(true);
notification.show();
stopSelf();
}
}
}
public static Property getStatus() {
if (bmc != null) {
return bmc.status();
} else {
return new Property("bitmessage context", null);
}
}
}

View File

@ -40,7 +40,7 @@ public class ProofOfWorkService extends Service {
private static ProofOfWorkEngine engine = new MultiThreadedPOWEngine();
private static boolean calculating;
private static final Queue<PowItem> queue = new LinkedList<>();
private static ProofOfWorkNotification notification;
private ProofOfWorkNotification notification;
@Override
public void onCreate() {
@ -55,16 +55,18 @@ public class ProofOfWorkService extends Service {
public static class PowBinder extends Binder {
private final ProofOfWorkService service;
private final ProofOfWorkNotification notification;
private PowBinder(ProofOfWorkService service) {
this.service = service;
this.notification = service.notification;
}
public void process(PowItem item) {
void process(PowItem item) {
synchronized (queue) {
service.startService(new Intent(service, ProofOfWorkService.class));
service.startForeground(ONGOING_NOTIFICATION_ID,
notification.getNotification());
notification.getNotification());
if (!calculating) {
calculating = true;
service.calculateNonce(item);
@ -90,28 +92,25 @@ public class ProofOfWorkService extends Service {
}
private void calculateNonce(final PowItem item) {
engine.calculateNonce(item.initialHash, item.targetValue, new ProofOfWorkEngine.Callback() {
@Override
public void onNonceCalculated(byte[] initialHash, byte[] nonce) {
try {
item.callback.onNonceCalculated(initialHash, nonce);
} finally {
PowItem item;
synchronized (queue) {
item = queue.poll();
if (item == null) {
calculating = false;
stopForeground(true);
stopSelf();
} else {
notification.update(queue.size()).show();
}
}
if (item != null) {
calculateNonce(item);
engine.calculateNonce(item.initialHash, item.targetValue, (initialHash, nonce) -> {
try {
item.callback.onNonceCalculated(initialHash, nonce);
} finally {
PowItem next;
synchronized (queue) {
next = queue.poll();
if (next == null) {
calculating = false;
stopForeground(true);
stopSelf();
} else {
notification.update(queue.size()).show();
}
}
if (next != null) {
calculateNonce(next);
}
}
});
}
}
}

View File

@ -46,7 +46,6 @@ import static ch.dissem.bitmessage.utils.UnixTime.DAY;
* Provides singleton objects across the application.
*/
public class Singleton {
public static final Object lock = new Object();
private static BitmessageContext bitmessageContext;
private static MessageListener messageListener;
private static BitmessageAddress identity;
@ -54,28 +53,28 @@ public class Singleton {
public static BitmessageContext getBitmessageContext(Context context) {
if (bitmessageContext == null) {
synchronized (lock) {
synchronized (Singleton.class) {
if (bitmessageContext == null) {
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,
new ServerPowEngine(ctx),
new ServicePowEngine(ctx)
))
.cryptography(new AndroidCryptography())
.nodeRegistry(new AndroidNodeRegistry(sqlHelper))
.inventory(new AndroidInventory(sqlHelper))
.addressRepo(new AndroidAddressRepository(sqlHelper))
.messageRepo(new AndroidMessageRepository(sqlHelper, ctx))
.powRepo(powRepo)
.networkHandler(new NioNetworkHandler())
.listener(getMessageListener(ctx))
.doNotSendPubkeyOnIdentityCreation()
.build();
.proofOfWorkEngine(new SwitchingProofOfWorkEngine(
ctx, Constants.PREFERENCE_SERVER_POW,
new ServerPowEngine(ctx),
new ServicePowEngine(ctx)
))
.cryptography(new AndroidCryptography())
.nodeRegistry(new AndroidNodeRegistry(sqlHelper))
.inventory(new AndroidInventory(sqlHelper))
.addressRepo(new AndroidAddressRepository(sqlHelper))
.messageRepo(new AndroidMessageRepository(sqlHelper, ctx))
.powRepo(powRepo)
.networkHandler(new NioNetworkHandler())
.listener(getMessageListener(ctx))
.doNotSendPubkeyOnIdentityCreation()
.build();
}
}
}
@ -108,11 +107,12 @@ public class Singleton {
public static BitmessageAddress getIdentity(Context ctx) {
if (identity == null) {
BitmessageContext bmc = getBitmessageContext(ctx);
synchronized (Singleton.class) {
if (identity == null) {
BitmessageContext bmc = getBitmessageContext(ctx);
// FIXME: this may block the UI, there must be a better way!
List<BitmessageAddress> identities = bmc.addresses()
.getIdentities();
.getIdentities();
if (identities.size() > 0) {
identity = identities.get(0);
} else {

View File

@ -25,7 +25,6 @@ import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import ch.dissem.apps.abit.R;
import ch.dissem.apps.abit.listener.WifiReceiver;
@ -39,8 +38,6 @@ import static ch.dissem.apps.abit.util.Constants.PREFERENCE_WIFI_ONLY;
* @author Christian Basler
*/
public class Preferences {
private static Logger LOG = LoggerFactory.getLogger(Preferences.class);
public static boolean useTrustedNode(Context ctx) {
String trustedNode = getPreference(ctx, PREFERENCE_TRUSTED_NODE);
return trustedNode != null && !trustedNode.trim().isEmpty();