Asynchronously load contacts to improve responsiveness
This commit is contained in:
parent
a67560c28b
commit
bf52d2f3de
@ -70,9 +70,6 @@ public class AddressDetailFragment extends Fragment {
|
|||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
if (getArguments().containsKey(ARG_ITEM)) {
|
if (getArguments().containsKey(ARG_ITEM)) {
|
||||||
// Load the dummy content specified by the fragment
|
|
||||||
// arguments. In a real-world scenario, use a Loader
|
|
||||||
// to load content from a content provider.
|
|
||||||
item = (BitmessageAddress) getArguments().getSerializable(ARG_ITEM);
|
item = (BitmessageAddress) getArguments().getSerializable(ARG_ITEM);
|
||||||
}
|
}
|
||||||
setHasOptionsMenu(true);
|
setHasOptionsMenu(true);
|
||||||
|
@ -19,6 +19,7 @@ package ch.dissem.apps.abit;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import android.os.AsyncTask;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
@ -32,11 +33,11 @@ import android.widget.TextView;
|
|||||||
|
|
||||||
import com.google.zxing.integration.android.IntentIntegrator;
|
import com.google.zxing.integration.android.IntentIntegrator;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.LinkedList;
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import ch.dissem.apps.abit.listener.ActionBarListener;
|
import ch.dissem.apps.abit.listener.ActionBarListener;
|
||||||
|
import ch.dissem.apps.abit.repository.AndroidAddressRepository;
|
||||||
import ch.dissem.apps.abit.service.Singleton;
|
import ch.dissem.apps.abit.service.Singleton;
|
||||||
import ch.dissem.bitmessage.entity.BitmessageAddress;
|
import ch.dissem.bitmessage.entity.BitmessageAddress;
|
||||||
import ch.dissem.bitmessage.entity.valueobject.Label;
|
import ch.dissem.bitmessage.entity.valueobject.Label;
|
||||||
@ -47,6 +48,46 @@ import io.github.yavski.fabspeeddial.SimpleMenuListenerAdapter;
|
|||||||
* Fragment that shows a list of all contacts, the ones we subscribed to first.
|
* Fragment that shows a list of all contacts, the ones we subscribed to first.
|
||||||
*/
|
*/
|
||||||
public class AddressListFragment extends AbstractItemListFragment<BitmessageAddress> {
|
public class AddressListFragment extends AbstractItemListFragment<BitmessageAddress> {
|
||||||
|
private ArrayAdapter<BitmessageAddress> adapter;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
|
adapter = new ArrayAdapter<BitmessageAddress>(
|
||||||
|
getActivity(),
|
||||||
|
R.layout.subscription_row,
|
||||||
|
R.id.name,
|
||||||
|
new LinkedList<BitmessageAddress>()) {
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public View getView(int position, View convertView, @NonNull ViewGroup parent) {
|
||||||
|
ViewHolder v;
|
||||||
|
if (convertView == null) {
|
||||||
|
LayoutInflater inflater = LayoutInflater.from(getContext());
|
||||||
|
convertView = inflater.inflate(R.layout.subscription_row, parent, false);
|
||||||
|
v = new ViewHolder();
|
||||||
|
v.ctx = getContext();
|
||||||
|
v.avatar = (ImageView) convertView.findViewById(R.id.avatar);
|
||||||
|
v.name = (TextView) convertView.findViewById(R.id.name);
|
||||||
|
v.streamNumber = (TextView) convertView.findViewById(R.id.stream_number);
|
||||||
|
v.subscribed = convertView.findViewById(R.id.subscribed);
|
||||||
|
convertView.setTag(v);
|
||||||
|
} else {
|
||||||
|
v = (ViewHolder) convertView.getTag();
|
||||||
|
}
|
||||||
|
BitmessageAddress item = getItem(position);
|
||||||
|
assert item != null;
|
||||||
|
v.avatar.setImageDrawable(new Identicon(item));
|
||||||
|
v.name.setText(item.toString());
|
||||||
|
v.streamNumber.setText(v.ctx.getString(R.string.stream_number, item.getStream()));
|
||||||
|
v.subscribed.setVisibility(item.isSubscribed() ? View.VISIBLE : View.INVISIBLE);
|
||||||
|
return convertView;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
setListAdapter(adapter);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onResume() {
|
public void onResume() {
|
||||||
super.onResume();
|
super.onResume();
|
||||||
@ -55,61 +96,26 @@ public class AddressListFragment extends AbstractItemListFragment<BitmessageAddr
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void updateList() {
|
public void updateList() {
|
||||||
List<BitmessageAddress> addresses = Singleton.getAddressRepository(getContext())
|
adapter.clear();
|
||||||
.getContacts();
|
final AndroidAddressRepository addressRepo = Singleton.getAddressRepository(getContext());
|
||||||
Collections.sort(addresses, new Comparator<BitmessageAddress>() {
|
new AsyncTask<Void, BitmessageAddress, Void>() {
|
||||||
@Override
|
@Override
|
||||||
public int compare(BitmessageAddress lhs, BitmessageAddress rhs) {
|
protected Void doInBackground(Void... params) {
|
||||||
// Yields the following order:
|
List<String> ids = addressRepo.getContactIds();
|
||||||
// * Subscribed addresses come first
|
for (String id : ids) {
|
||||||
// * Addresses with Aliases (alphabetically)
|
BitmessageAddress address = addressRepo.getById(id);
|
||||||
// * Addresses (alphabetically)
|
publishProgress(address);
|
||||||
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;
|
|
||||||
} else {
|
|
||||||
return lhs.getAddress().compareTo(rhs.getAddress());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (lhs.isSubscribed()) {
|
return null;
|
||||||
return -1;
|
}
|
||||||
} else {
|
|
||||||
return 1;
|
@Override
|
||||||
|
protected void onProgressUpdate(BitmessageAddress... values) {
|
||||||
|
for (BitmessageAddress address : values) {
|
||||||
|
adapter.add(address);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
}.execute();
|
||||||
setListAdapter(new ArrayAdapter<BitmessageAddress>(
|
|
||||||
getActivity(),
|
|
||||||
android.R.layout.simple_list_item_activated_1,
|
|
||||||
android.R.id.text1,
|
|
||||||
addresses) {
|
|
||||||
@NonNull
|
|
||||||
@Override
|
|
||||||
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, parent, false);
|
|
||||||
}
|
|
||||||
BitmessageAddress item = getItem(position);
|
|
||||||
assert item != null;
|
|
||||||
((ImageView) convertView.findViewById(R.id.avatar)).setImageDrawable(new
|
|
||||||
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()));
|
|
||||||
convertView.findViewById(R.id.subscribed).setVisibility(item.isSubscribed() ?
|
|
||||||
View.VISIBLE : View.INVISIBLE);
|
|
||||||
return convertView;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -163,4 +169,12 @@ public class AddressListFragment extends AbstractItemListFragment<BitmessageAddr
|
|||||||
public void updateList(Label label) {
|
public void updateList(Label label) {
|
||||||
updateList();
|
updateList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class ViewHolder {
|
||||||
|
private Context ctx;
|
||||||
|
private ImageView avatar;
|
||||||
|
private TextView name;
|
||||||
|
private TextView streamNumber;
|
||||||
|
private View subscribed;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -52,21 +52,19 @@ public class ImportIdentitiesFragment extends Fragment {
|
|||||||
String wifData = getArguments().getString(WIF_DATA);
|
String wifData = getArguments().getString(WIF_DATA);
|
||||||
BitmessageContext bmc = Singleton.getBitmessageContext(getActivity());
|
BitmessageContext bmc = Singleton.getBitmessageContext(getActivity());
|
||||||
View view = inflater.inflate(R.layout.fragment_import_select_identities, container, false);
|
View view = inflater.inflate(R.layout.fragment_import_select_identities, container, false);
|
||||||
try {
|
|
||||||
importer = new WifImporter(bmc, wifData);
|
|
||||||
adapter = new AddressSelectorAdapter(importer.getIdentities());
|
|
||||||
LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity(),
|
|
||||||
LinearLayoutManager.VERTICAL,
|
|
||||||
false);
|
|
||||||
RecyclerView recyclerView = (RecyclerView) view.findViewById(R.id.recycler_view);
|
|
||||||
recyclerView.setLayoutManager(layoutManager);
|
|
||||||
recyclerView.setAdapter(adapter);
|
|
||||||
|
|
||||||
recyclerView.addItemDecoration(new SimpleListDividerDecorator(
|
importer = new WifImporter(bmc, wifData);
|
||||||
ContextCompat.getDrawable(getActivity(), R.drawable.list_divider_h), true));
|
adapter = new AddressSelectorAdapter(importer.getIdentities());
|
||||||
} catch (IOException e) {
|
LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity(),
|
||||||
return super.onCreateView(inflater, container, savedInstanceState);
|
LinearLayoutManager.VERTICAL,
|
||||||
}
|
false);
|
||||||
|
RecyclerView recyclerView = (RecyclerView) view.findViewById(R.id.recycler_view);
|
||||||
|
recyclerView.setLayoutManager(layoutManager);
|
||||||
|
recyclerView.setAdapter(adapter);
|
||||||
|
|
||||||
|
recyclerView.addItemDecoration(new SimpleListDividerDecorator(
|
||||||
|
ContextCompat.getDrawable(getActivity(), R.drawable.list_divider_h), true));
|
||||||
|
|
||||||
view.findViewById(R.id.finish).setOnClickListener(new View.OnClickListener() {
|
view.findViewById(R.id.finish).setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View view) {
|
public void onClick(View view) {
|
||||||
|
@ -499,14 +499,13 @@ public class MainActivity extends AppCompatActivity
|
|||||||
Bundle arguments = new Bundle();
|
Bundle arguments = new Bundle();
|
||||||
arguments.putSerializable(MessageDetailFragment.ARG_ITEM, item);
|
arguments.putSerializable(MessageDetailFragment.ARG_ITEM, item);
|
||||||
Fragment fragment;
|
Fragment fragment;
|
||||||
if (item instanceof Plaintext)
|
if (item instanceof Plaintext) {
|
||||||
fragment = new MessageDetailFragment();
|
fragment = new MessageDetailFragment();
|
||||||
else if (item instanceof BitmessageAddress)
|
} else if (item instanceof String) {
|
||||||
fragment = new AddressDetailFragment();
|
fragment = new AddressDetailFragment();
|
||||||
else
|
} else {
|
||||||
throw new IllegalArgumentException("Plaintext or BitmessageAddress expected, but " +
|
throw new IllegalArgumentException("Plaintext or BitmessageAddress expected, but was " + item.getClass().getSimpleName());
|
||||||
"was "
|
}
|
||||||
+ item.getClass().getSimpleName());
|
|
||||||
fragment.setArguments(arguments);
|
fragment.setArguments(arguments);
|
||||||
getSupportFragmentManager().beginTransaction()
|
getSupportFragmentManager().beginTransaction()
|
||||||
.replace(R.id.message_detail_container, fragment)
|
.replace(R.id.message_detail_container, fragment)
|
||||||
@ -518,7 +517,7 @@ public class MainActivity extends AppCompatActivity
|
|||||||
if (item instanceof Plaintext) {
|
if (item instanceof Plaintext) {
|
||||||
detailIntent = new Intent(this, MessageDetailActivity.class);
|
detailIntent = new Intent(this, MessageDetailActivity.class);
|
||||||
detailIntent.putExtra(EXTRA_SHOW_LABEL, selectedLabel);
|
detailIntent.putExtra(EXTRA_SHOW_LABEL, selectedLabel);
|
||||||
} else if (item instanceof BitmessageAddress) {
|
} else if (item instanceof String) {
|
||||||
detailIntent = new Intent(this, AddressDetailActivity.class);
|
detailIntent = new Intent(this, AddressDetailActivity.class);
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalArgumentException("Plaintext or BitmessageAddress expected, but " +
|
throw new IllegalArgumentException("Plaintext or BitmessageAddress expected, but " +
|
||||||
|
@ -19,26 +19,27 @@ package ch.dissem.apps.abit.repository;
|
|||||||
import android.content.ContentValues;
|
import android.content.ContentValues;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.database.sqlite.SQLiteDatabase;
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
import ch.dissem.bitmessage.entity.BitmessageAddress;
|
|
||||||
import ch.dissem.bitmessage.entity.payload.Pubkey;
|
|
||||||
import ch.dissem.bitmessage.entity.payload.V3Pubkey;
|
|
||||||
import ch.dissem.bitmessage.entity.payload.V4Pubkey;
|
|
||||||
import ch.dissem.bitmessage.entity.valueobject.PrivateKey;
|
|
||||||
import ch.dissem.bitmessage.factory.Factory;
|
|
||||||
import ch.dissem.bitmessage.ports.AddressRepository;
|
|
||||||
import ch.dissem.bitmessage.utils.Encode;
|
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import ch.dissem.bitmessage.entity.BitmessageAddress;
|
||||||
|
import ch.dissem.bitmessage.entity.payload.Pubkey;
|
||||||
|
import ch.dissem.bitmessage.entity.payload.V3Pubkey;
|
||||||
|
import ch.dissem.bitmessage.entity.payload.V4Pubkey;
|
||||||
|
import ch.dissem.bitmessage.entity.valueobject.PrivateKey;
|
||||||
|
import ch.dissem.bitmessage.exception.ApplicationException;
|
||||||
|
import ch.dissem.bitmessage.factory.Factory;
|
||||||
|
import ch.dissem.bitmessage.ports.AddressRepository;
|
||||||
|
import ch.dissem.bitmessage.utils.Encode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link AddressRepository} implementation using the Android SQL API.
|
* {@link AddressRepository} implementation using the Android SQL API.
|
||||||
*/
|
*/
|
||||||
@ -84,21 +85,25 @@ public class AndroidAddressRepository implements AddressRepository {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public List<BitmessageAddress> getIdentities() {
|
public List<BitmessageAddress> getIdentities() {
|
||||||
return find("private_key IS NOT NULL");
|
return find("private_key IS NOT NULL");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public List<BitmessageAddress> getChans() {
|
public List<BitmessageAddress> getChans() {
|
||||||
return find("chan = '1'");
|
return find("chan = '1'");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public List<BitmessageAddress> getSubscriptions() {
|
public List<BitmessageAddress> getSubscriptions() {
|
||||||
return find("subscribed = '1'");
|
return find("subscribed = '1'");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public List<BitmessageAddress> getSubscriptions(long broadcastVersion) {
|
public List<BitmessageAddress> getSubscriptions(long broadcastVersion) {
|
||||||
if (broadcastVersion > 4) {
|
if (broadcastVersion > 4) {
|
||||||
@ -108,11 +113,55 @@ public class AndroidAddressRepository implements AddressRepository {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public List<BitmessageAddress> getContacts() {
|
public List<BitmessageAddress> getContacts() {
|
||||||
return find("private_key IS NULL OR chan = '1'");
|
return find("private_key IS NULL OR chan = '1'");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the contacts in the following order:
|
||||||
|
* <ul>
|
||||||
|
* <li>Subscribed addresses come first
|
||||||
|
* <li>Addresses with Aliases (alphabetically)
|
||||||
|
* <li>Addresses (alphabetically)
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* @return the ordered list of ids (address strings)
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
public List<String> getContactIds() {
|
||||||
|
return findIds(
|
||||||
|
"private_key IS NULL OR chan = '1'",
|
||||||
|
COLUMN_SUBSCRIBED + " DESC, " + COLUMN_ALIAS + " IS NULL, " + COLUMN_ALIAS + ", " + COLUMN_ADDRESS
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private List<String> findIds(String where, String orderBy) {
|
||||||
|
List<String> result = new LinkedList<>();
|
||||||
|
|
||||||
|
// Define a projection that specifies which columns from the database
|
||||||
|
// you will actually use after this query.
|
||||||
|
String[] projection = {
|
||||||
|
COLUMN_ADDRESS
|
||||||
|
};
|
||||||
|
|
||||||
|
SQLiteDatabase db = sql.getReadableDatabase();
|
||||||
|
try (Cursor c = db.query(
|
||||||
|
TABLE_NAME, projection,
|
||||||
|
where,
|
||||||
|
null, null, null,
|
||||||
|
orderBy
|
||||||
|
)) {
|
||||||
|
while (c.moveToNext()) {
|
||||||
|
result.add(c.getString(c.getColumnIndex(COLUMN_ADDRESS)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
private List<BitmessageAddress> find(String where) {
|
private List<BitmessageAddress> find(String where) {
|
||||||
List<BitmessageAddress> result = new LinkedList<>();
|
List<BitmessageAddress> result = new LinkedList<>();
|
||||||
|
|
||||||
@ -161,8 +210,6 @@ public class AndroidAddressRepository implements AddressRepository {
|
|||||||
|
|
||||||
result.add(address);
|
result.add(address);
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
|
||||||
LOG.error(e.getMessage(), e);
|
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -188,61 +235,55 @@ public class AndroidAddressRepository implements AddressRepository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void update(BitmessageAddress address) {
|
private void update(BitmessageAddress address) {
|
||||||
try {
|
SQLiteDatabase db = sql.getWritableDatabase();
|
||||||
SQLiteDatabase db = sql.getWritableDatabase();
|
// Create a new map of values, where column names are the keys
|
||||||
// Create a new map of values, where column names are the keys
|
ContentValues values = new ContentValues();
|
||||||
ContentValues values = new ContentValues();
|
if (address.getAlias() != null) {
|
||||||
if (address.getAlias() != null) {
|
values.put(COLUMN_ALIAS, address.getAlias());
|
||||||
values.put(COLUMN_ALIAS, address.getAlias());
|
}
|
||||||
}
|
if (address.getPubkey() != null) {
|
||||||
if (address.getPubkey() != null) {
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
address.getPubkey().writeUnencrypted(out);
|
||||||
address.getPubkey().writeUnencrypted(out);
|
values.put(COLUMN_PUBLIC_KEY, out.toByteArray());
|
||||||
values.put(COLUMN_PUBLIC_KEY, out.toByteArray());
|
}
|
||||||
}
|
if (address.getPrivateKey() != null) {
|
||||||
if (address.getPrivateKey() != null) {
|
values.put(COLUMN_PRIVATE_KEY, Encode.bytes(address.getPrivateKey()));
|
||||||
values.put(COLUMN_PRIVATE_KEY, Encode.bytes(address.getPrivateKey()));
|
}
|
||||||
}
|
if (address.isChan()) {
|
||||||
if (address.isChan()) {
|
values.put(COLUMN_CHAN, true);
|
||||||
values.put(COLUMN_CHAN, true);
|
}
|
||||||
}
|
values.put(COLUMN_SUBSCRIBED, address.isSubscribed());
|
||||||
values.put(COLUMN_SUBSCRIBED, address.isSubscribed());
|
|
||||||
|
|
||||||
int update = db.update(TABLE_NAME, values, "address=?",
|
int update = db.update(TABLE_NAME, values, "address=?",
|
||||||
new String[]{address.getAddress()});
|
new String[]{address.getAddress()});
|
||||||
if (update < 0) {
|
if (update < 0) {
|
||||||
LOG.error("Could not update address " + address);
|
LOG.error("Could not update address " + address);
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
LOG.error(e.getMessage(), e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void insert(BitmessageAddress address) {
|
private void insert(BitmessageAddress address) {
|
||||||
try {
|
SQLiteDatabase db = sql.getWritableDatabase();
|
||||||
SQLiteDatabase db = sql.getWritableDatabase();
|
// Create a new map of values, where column names are the keys
|
||||||
// Create a new map of values, where column names are the keys
|
ContentValues values = new ContentValues();
|
||||||
ContentValues values = new ContentValues();
|
values.put(COLUMN_ADDRESS, address.getAddress());
|
||||||
values.put(COLUMN_ADDRESS, address.getAddress());
|
values.put(COLUMN_VERSION, address.getVersion());
|
||||||
values.put(COLUMN_VERSION, address.getVersion());
|
values.put(COLUMN_ALIAS, address.getAlias());
|
||||||
values.put(COLUMN_ALIAS, address.getAlias());
|
if (address.getPubkey() != null) {
|
||||||
if (address.getPubkey() != null) {
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
address.getPubkey().writeUnencrypted(out);
|
||||||
address.getPubkey().writeUnencrypted(out);
|
values.put(COLUMN_PUBLIC_KEY, out.toByteArray());
|
||||||
values.put(COLUMN_PUBLIC_KEY, out.toByteArray());
|
} else {
|
||||||
} else {
|
values.put(COLUMN_PUBLIC_KEY, (byte[]) null);
|
||||||
values.put(COLUMN_PUBLIC_KEY, (byte[]) null);
|
}
|
||||||
}
|
if (address.getPrivateKey() != null) {
|
||||||
values.put(COLUMN_PRIVATE_KEY, Encode.bytes(address.getPrivateKey()));
|
values.put(COLUMN_PRIVATE_KEY, Encode.bytes(address.getPrivateKey()));
|
||||||
values.put(COLUMN_CHAN, address.isChan());
|
}
|
||||||
values.put(COLUMN_SUBSCRIBED, address.isSubscribed());
|
values.put(COLUMN_CHAN, address.isChan());
|
||||||
|
values.put(COLUMN_SUBSCRIBED, address.isSubscribed());
|
||||||
|
|
||||||
long insert = db.insert(TABLE_NAME, null, values);
|
long insert = db.insert(TABLE_NAME, null, values);
|
||||||
if (insert < 0) {
|
if (insert < 0) {
|
||||||
LOG.error("Could not insert address " + address);
|
LOG.error("Could not insert address " + address);
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
LOG.error(e.getMessage(), e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -252,10 +293,21 @@ public class AndroidAddressRepository implements AddressRepository {
|
|||||||
db.delete(TABLE_NAME, "address = ?", new String[]{address.getAddress()});
|
db.delete(TABLE_NAME, "address = ?", new String[]{address.getAddress()});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public BitmessageAddress getById(String id) {
|
||||||
|
List<BitmessageAddress> result = find("address = '" + id + "'");
|
||||||
|
if (result.size() > 0) {
|
||||||
|
return result.get(0);
|
||||||
|
} else {
|
||||||
|
throw new ApplicationException("Address with id " + id + " not found.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public BitmessageAddress getAddress(String address) {
|
public BitmessageAddress getAddress(String address) {
|
||||||
List<BitmessageAddress> result = find("address = '" + address + "'");
|
List<BitmessageAddress> result = find("address = '" + address + "'");
|
||||||
if (result.size() > 0) return result.get(0);
|
if (result.size() > 0) return result.get(0);
|
||||||
return null;
|
return new BitmessageAddress(address);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,12 +22,12 @@ import android.database.Cursor;
|
|||||||
import android.database.DatabaseUtils;
|
import android.database.DatabaseUtils;
|
||||||
import android.database.sqlite.SQLiteConstraintException;
|
import android.database.sqlite.SQLiteConstraintException;
|
||||||
import android.database.sqlite.SQLiteDatabase;
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -91,6 +91,7 @@ public class AndroidMessageRepository extends AbstractMessageRepository {
|
|||||||
this.context = ctx;
|
this.context = ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public List<Plaintext> findMessages(Label label) {
|
public List<Plaintext> findMessages(Label label) {
|
||||||
if (label == LABEL_ARCHIVE) {
|
if (label == LABEL_ARCHIVE) {
|
||||||
@ -100,6 +101,7 @@ public class AndroidMessageRepository extends AbstractMessageRepository {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
public List<Label> findLabels(String where) {
|
public List<Label> findLabels(String where) {
|
||||||
List<Label> result = new LinkedList<>();
|
List<Label> result = new LinkedList<>();
|
||||||
|
|
||||||
@ -156,7 +158,7 @@ public class AndroidMessageRepository extends AbstractMessageRepository {
|
|||||||
} else {
|
} else {
|
||||||
where = "id IN (SELECT message_id FROM Message_Label WHERE label_id=?) AND ";
|
where = "id IN (SELECT message_id FROM Message_Label WHERE label_id=?) AND ";
|
||||||
args = new String[]{
|
args = new String[]{
|
||||||
label.getId().toString(),
|
String.valueOf(label.getId()),
|
||||||
Label.Type.UNREAD.name()
|
Label.Type.UNREAD.name()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -168,6 +170,7 @@ public class AndroidMessageRepository extends AbstractMessageRepository {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public List<UUID> findConversations(Label label) {
|
public List<UUID> findConversations(Label label) {
|
||||||
String[] projection = {
|
String[] projection = {
|
||||||
@ -202,20 +205,22 @@ public class AndroidMessageRepository extends AbstractMessageRepository {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
byte[] childIV = message.getInventoryVector().getHash();
|
byte[] childIV = message.getInventoryVector().getHash();
|
||||||
db.delete(PARENTS_TABLE_NAME, "child=?", new String[]{hex(childIV).toString()});
|
db.delete(PARENTS_TABLE_NAME, "child=?", new String[]{hex(childIV)});
|
||||||
|
|
||||||
// save new parents
|
// save new parents
|
||||||
int order = 0;
|
int order = 0;
|
||||||
for (InventoryVector parentIV : message.getParents()) {
|
for (InventoryVector parentIV : message.getParents()) {
|
||||||
Plaintext parent = getMessage(parentIV);
|
Plaintext parent = getMessage(parentIV);
|
||||||
mergeConversations(db, parent.getConversationId(), message.getConversationId());
|
if (parent != null) {
|
||||||
order++;
|
mergeConversations(db, parent.getConversationId(), message.getConversationId());
|
||||||
ContentValues values = new ContentValues();
|
order++;
|
||||||
values.put("parent", parentIV.getHash());
|
ContentValues values = new ContentValues();
|
||||||
values.put("child", childIV);
|
values.put("parent", parentIV.getHash());
|
||||||
values.put("pos", order);
|
values.put("child", childIV);
|
||||||
values.put("conversation", UuidUtils.asBytes(message.getConversationId()));
|
values.put("pos", order);
|
||||||
db.insertOrThrow(PARENTS_TABLE_NAME, null, values);
|
values.put("conversation", UuidUtils.asBytes(message.getConversationId()));
|
||||||
|
db.insertOrThrow(PARENTS_TABLE_NAME, null, values);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -229,11 +234,12 @@ public class AndroidMessageRepository extends AbstractMessageRepository {
|
|||||||
private void mergeConversations(SQLiteDatabase db, UUID source, UUID target) {
|
private void mergeConversations(SQLiteDatabase db, UUID source, UUID target) {
|
||||||
ContentValues values = new ContentValues();
|
ContentValues values = new ContentValues();
|
||||||
values.put("conversation", UuidUtils.asBytes(target));
|
values.put("conversation", UuidUtils.asBytes(target));
|
||||||
String[] whereArgs = {hex(UuidUtils.asBytes(source)).toString()};
|
String[] whereArgs = {hex(UuidUtils.asBytes(source))};
|
||||||
db.update(TABLE_NAME, values, "conversation=?", whereArgs);
|
db.update(TABLE_NAME, values, "conversation=?", whereArgs);
|
||||||
db.update(PARENTS_TABLE_NAME, values, "conversation=?", whereArgs);
|
db.update(PARENTS_TABLE_NAME, values, "conversation=?", whereArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
protected List<Plaintext> find(String where) {
|
protected List<Plaintext> find(String where) {
|
||||||
List<Plaintext> result = new LinkedList<>();
|
List<Plaintext> result = new LinkedList<>();
|
||||||
|
|
||||||
@ -292,8 +298,6 @@ public class AndroidMessageRepository extends AbstractMessageRepository {
|
|||||||
builder.labels(findLabels(id));
|
builder.labels(findLabels(id));
|
||||||
result.add(builder.build());
|
result.add(builder.build());
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
|
||||||
LOG.error(e.getMessage(), e);
|
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -348,7 +352,7 @@ public class AndroidMessageRepository extends AbstractMessageRepository {
|
|||||||
values.put(COLUMN_ACK_DATA, message.getAckData());
|
values.put(COLUMN_ACK_DATA, message.getAckData());
|
||||||
values.put(COLUMN_SENT, message.getSent());
|
values.put(COLUMN_SENT, message.getSent());
|
||||||
values.put(COLUMN_RECEIVED, message.getReceived());
|
values.put(COLUMN_RECEIVED, message.getReceived());
|
||||||
values.put(COLUMN_STATUS, message.getStatus() == null ? null : message.getStatus().name());
|
values.put(COLUMN_STATUS, message.getStatus().name());
|
||||||
values.put(COLUMN_INITIAL_HASH, message.getInitialHash());
|
values.put(COLUMN_INITIAL_HASH, message.getInitialHash());
|
||||||
values.put(COLUMN_TTL, message.getTTL());
|
values.put(COLUMN_TTL, message.getTTL());
|
||||||
values.put(COLUMN_RETRIES, message.getRetries());
|
values.put(COLUMN_RETRIES, message.getRetries());
|
||||||
|
@ -6,6 +6,7 @@ import android.database.sqlite.SQLiteConstraintException;
|
|||||||
import android.database.sqlite.SQLiteDatabase;
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
import android.database.sqlite.SQLiteDoneException;
|
import android.database.sqlite.SQLiteDoneException;
|
||||||
import android.database.sqlite.SQLiteStatement;
|
import android.database.sqlite.SQLiteStatement;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
@ -53,7 +54,7 @@ public class AndroidNodeRegistry implements NodeRegistry {
|
|||||||
|
|
||||||
private void cleanUp() {
|
private void cleanUp() {
|
||||||
SQLiteDatabase db = sql.getWritableDatabase();
|
SQLiteDatabase db = sql.getWritableDatabase();
|
||||||
db.delete(TABLE_NAME, "time < ?", new String[]{valueOf(now(-28 * DAY))});
|
db.delete(TABLE_NAME, "time < ?", new String[]{valueOf(now() - 28 * DAY)});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -82,6 +83,7 @@ public class AndroidNodeRegistry implements NodeRegistry {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public List<NetworkAddress> getKnownAddresses(int limit, long... streams) {
|
public List<NetworkAddress> getKnownAddresses(int limit, long... streams) {
|
||||||
String[] projection = {
|
String[] projection = {
|
||||||
@ -97,7 +99,7 @@ public class AndroidNodeRegistry implements NodeRegistry {
|
|||||||
try (Cursor c = db.query(
|
try (Cursor c = db.query(
|
||||||
TABLE_NAME, projection,
|
TABLE_NAME, projection,
|
||||||
"stream IN (?)",
|
"stream IN (?)",
|
||||||
new String[]{SqlStrings.join(streams).toString()},
|
new String[]{SqlStrings.join(streams)},
|
||||||
null, null,
|
null, null,
|
||||||
"time DESC",
|
"time DESC",
|
||||||
valueOf(limit)
|
valueOf(limit)
|
||||||
@ -140,7 +142,7 @@ public class AndroidNodeRegistry implements NodeRegistry {
|
|||||||
try {
|
try {
|
||||||
cleanUp();
|
cleanUp();
|
||||||
for (NetworkAddress node : nodes) {
|
for (NetworkAddress node : nodes) {
|
||||||
if (node.getTime() < now(+5 * MINUTE) && node.getTime() > now(-28 * DAY)) {
|
if (node.getTime() < now() + 5 * MINUTE && node.getTime() > now() - 28 * DAY) {
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
Long existing = loadExistingTime(node);
|
Long existing = loadExistingTime(node);
|
||||||
if (existing == null) {
|
if (existing == null) {
|
||||||
|
@ -20,6 +20,7 @@ import android.content.ContentValues;
|
|||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.database.sqlite.SQLiteConstraintException;
|
import android.database.sqlite.SQLiteConstraintException;
|
||||||
import android.database.sqlite.SQLiteDatabase;
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
@ -65,6 +66,7 @@ public class AndroidProofOfWorkRepository implements ProofOfWorkRepository, Inte
|
|||||||
this.bmc = internalContext;
|
this.bmc = internalContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public Item getItem(byte[] initialHash) {
|
public Item getItem(byte[] initialHash) {
|
||||||
// Define a projection that specifies which columns from the database
|
// Define a projection that specifies which columns from the database
|
||||||
@ -111,6 +113,7 @@ public class AndroidProofOfWorkRepository implements ProofOfWorkRepository, Inte
|
|||||||
hex(initialHash));
|
hex(initialHash));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public List<byte[]> getItems() {
|
public List<byte[]> getItems() {
|
||||||
// Define a projection that specifies which columns from the database
|
// Define a projection that specifies which columns from the database
|
||||||
@ -139,14 +142,14 @@ public class AndroidProofOfWorkRepository implements ProofOfWorkRepository, Inte
|
|||||||
SQLiteDatabase db = sql.getWritableDatabase();
|
SQLiteDatabase db = sql.getWritableDatabase();
|
||||||
// Create a new map of values, where column names are the keys
|
// Create a new map of values, where column names are the keys
|
||||||
ContentValues values = new ContentValues();
|
ContentValues values = new ContentValues();
|
||||||
values.put(COLUMN_INITIAL_HASH, cryptography().getInitialHash(item.object));
|
values.put(COLUMN_INITIAL_HASH, cryptography().getInitialHash(item.getObjectMessage()));
|
||||||
values.put(COLUMN_DATA, Encode.bytes(item.object));
|
values.put(COLUMN_DATA, Encode.bytes(item.getObjectMessage()));
|
||||||
values.put(COLUMN_VERSION, item.object.getVersion());
|
values.put(COLUMN_VERSION, item.getObjectMessage().getVersion());
|
||||||
values.put(COLUMN_NONCE_TRIALS_PER_BYTE, item.nonceTrialsPerByte);
|
values.put(COLUMN_NONCE_TRIALS_PER_BYTE, item.getNonceTrialsPerByte());
|
||||||
values.put(COLUMN_EXTRA_BYTES, item.extraBytes);
|
values.put(COLUMN_EXTRA_BYTES, item.getExtraBytes());
|
||||||
if (item.message != null) {
|
if (item.getMessage() != null) {
|
||||||
values.put(COLUMN_EXPIRATION_TIME, item.expirationTime);
|
values.put(COLUMN_EXPIRATION_TIME, item.getExpirationTime());
|
||||||
values.put(COLUMN_MESSAGE_ID, (Long) item.message.getId());
|
values.put(COLUMN_MESSAGE_ID, (Long) item.getMessage().getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
db.insertOrThrow(TABLE_NAME, null, values);
|
db.insertOrThrow(TABLE_NAME, null, values);
|
||||||
|
@ -100,7 +100,7 @@ public class BitmessageService extends Service {
|
|||||||
if (bmc != null) {
|
if (bmc != null) {
|
||||||
return bmc.status();
|
return bmc.status();
|
||||||
} else {
|
} else {
|
||||||
return new Property("bitmessage context", null);
|
return new Property("bitmessage context");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -99,12 +99,12 @@ public class Singleton {
|
|||||||
return messageListener;
|
return messageListener;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static MessageRepository getMessageRepository(Context ctx) {
|
public static AndroidMessageRepository getMessageRepository(Context ctx) {
|
||||||
return getBitmessageContext(ctx).messages();
|
return (AndroidMessageRepository) getBitmessageContext(ctx).messages();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static AddressRepository getAddressRepository(Context ctx) {
|
public static AndroidAddressRepository getAddressRepository(Context ctx) {
|
||||||
return getBitmessageContext(ctx).addresses();
|
return (AndroidAddressRepository) getBitmessageContext(ctx).addresses();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ProofOfWorkRepository getProofOfWorkRepository(Context ctx) {
|
public static ProofOfWorkRepository getProofOfWorkRepository(Context ctx) {
|
||||||
|
@ -109,6 +109,7 @@ public class SyncAdapter extends AbstractThreadedSyncAdapter {
|
|||||||
LOG.info("Looking for completed POW");
|
LOG.info("Looking for completed POW");
|
||||||
|
|
||||||
BitmessageAddress identity = Singleton.getIdentity(getContext());
|
BitmessageAddress identity = Singleton.getIdentity(getContext());
|
||||||
|
@SuppressWarnings("ConstantConditions")
|
||||||
byte[] privateKey = identity.getPrivateKey().getPrivateEncryptionKey();
|
byte[] privateKey = identity.getPrivateKey().getPrivateEncryptionKey();
|
||||||
byte[] signingKey = cryptography().createPublicKey(identity.getPublicDecryptionKey());
|
byte[] signingKey = cryptography().createPublicKey(identity.getPublicDecryptionKey());
|
||||||
ProofOfWorkRequest.Reader reader = new ProofOfWorkRequest.Reader(identity);
|
ProofOfWorkRequest.Reader reader = new ProofOfWorkRequest.Reader(identity);
|
||||||
@ -116,8 +117,7 @@ public class SyncAdapter extends AbstractThreadedSyncAdapter {
|
|||||||
List<byte[]> items = powRepo.getItems();
|
List<byte[]> items = powRepo.getItems();
|
||||||
for (byte[] initialHash : items) {
|
for (byte[] initialHash : items) {
|
||||||
ProofOfWorkRepository.Item item = powRepo.getItem(initialHash);
|
ProofOfWorkRepository.Item item = powRepo.getItem(initialHash);
|
||||||
byte[] target = cryptography().getProofOfWorkTarget(item.object, item
|
byte[] target = cryptography().getProofOfWorkTarget(item.getObjectMessage(), item.getNonceTrialsPerByte(), item.getExtraBytes());
|
||||||
.nonceTrialsPerByte, item.extraBytes);
|
|
||||||
CryptoCustomMessage<ProofOfWorkRequest> cryptoMsg = new CryptoCustomMessage<>(
|
CryptoCustomMessage<ProofOfWorkRequest> cryptoMsg = new CryptoCustomMessage<>(
|
||||||
new ProofOfWorkRequest(identity, initialHash, CALCULATE, target));
|
new ProofOfWorkRequest(identity, initialHash, CALCULATE, target));
|
||||||
cryptoMsg.signAndEncrypt(identity, signingKey);
|
cryptoMsg.signAndEncrypt(identity, signingKey);
|
||||||
|
@ -34,12 +34,10 @@ import org.slf4j.Logger;
|
|||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import ch.dissem.apps.abit.Identicon;
|
import ch.dissem.apps.abit.Identicon;
|
||||||
import ch.dissem.apps.abit.R;
|
import ch.dissem.apps.abit.R;
|
||||||
import ch.dissem.bitmessage.entity.BitmessageAddress;
|
import ch.dissem.bitmessage.entity.BitmessageAddress;
|
||||||
import ch.dissem.bitmessage.exception.ApplicationException;
|
|
||||||
|
|
||||||
import static android.graphics.Color.BLACK;
|
import static android.graphics.Color.BLACK;
|
||||||
import static android.graphics.Color.WHITE;
|
import static android.graphics.Color.WHITE;
|
||||||
@ -83,11 +81,7 @@ public class Drawables {
|
|||||||
if (address.getPubkey() != null) {
|
if (address.getPubkey() != null) {
|
||||||
link.append(address.getAlias() == null ? '?' : '&');
|
link.append(address.getAlias() == null ? '?' : '&');
|
||||||
ByteArrayOutputStream pubkey = new ByteArrayOutputStream();
|
ByteArrayOutputStream pubkey = new ByteArrayOutputStream();
|
||||||
try {
|
address.getPubkey().writeUnencrypted(pubkey);
|
||||||
address.getPubkey().writeUnencrypted(pubkey);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new ApplicationException(e);
|
|
||||||
}
|
|
||||||
link.append("pubkey=").append(Base64.encodeToString(pubkey.toByteArray(), URL_SAFE | NO_WRAP));
|
link.append("pubkey=").append(Base64.encodeToString(pubkey.toByteArray(), URL_SAFE | NO_WRAP));
|
||||||
}
|
}
|
||||||
BitMatrix result;
|
BitMatrix result;
|
||||||
|
@ -15,9 +15,13 @@ import java.util.UUID;
|
|||||||
* </p>
|
* </p>
|
||||||
*/
|
*/
|
||||||
public class UuidUtils {
|
public class UuidUtils {
|
||||||
|
/**
|
||||||
|
* @param bytes that represent a UUID, or null for a random UUID
|
||||||
|
* @return the UUID from the given bytes, or a random UUID if bytes is null.
|
||||||
|
*/
|
||||||
public static UUID asUuid(byte[] bytes) {
|
public static UUID asUuid(byte[] bytes) {
|
||||||
if (bytes == null) {
|
if (bytes == null) {
|
||||||
return null;
|
return UUID.randomUUID();
|
||||||
}
|
}
|
||||||
ByteBuffer bb = ByteBuffer.wrap(bytes);
|
ByteBuffer bb = ByteBuffer.wrap(bytes);
|
||||||
long firstLong = bb.getLong();
|
long firstLong = bb.getLong();
|
||||||
|
12
app/src/main/res/drawable/avatar_placeholder.xml
Normal file
12
app/src/main/res/drawable/avatar_placeholder.xml
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="oval">
|
||||||
|
|
||||||
|
<solid
|
||||||
|
android:color="@color/colorAccent"/>
|
||||||
|
|
||||||
|
<size
|
||||||
|
android:width="40dp"
|
||||||
|
android:height="40dp"/>
|
||||||
|
</shape>
|
@ -29,7 +29,7 @@
|
|||||||
android:layout_alignParentStart="true"
|
android:layout_alignParentStart="true"
|
||||||
android:layout_alignParentTop="true"
|
android:layout_alignParentTop="true"
|
||||||
android:layout_margin="16dp"
|
android:layout_margin="16dp"
|
||||||
android:src="@color/colorAccent"
|
android:src="@drawable/avatar_placeholder"
|
||||||
tools:ignore="ContentDescription"/>
|
tools:ignore="ContentDescription"/>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
@ -65,7 +65,7 @@
|
|||||||
<string name="pubkey_available">Public key available</string>
|
<string name="pubkey_available">Public key available</string>
|
||||||
<string name="pubkey_not_available">Public key not yet available</string>
|
<string name="pubkey_not_available">Public key not yet available</string>
|
||||||
<string name="alt_qr_code">QR code</string>
|
<string name="alt_qr_code">QR code</string>
|
||||||
<string name="add_identity_warning">Having more identities will reequire more resources. If you are sure you want to add an identity, please select what exactly you want to do:</string>
|
<string name="add_identity_warning">Having more identities will require more resources. If you are sure you want to add an identity, please select what exactly you want to do:</string>
|
||||||
<string name="share">Share</string>
|
<string name="share">Share</string>
|
||||||
<string name="delete_identity_warning">Are you sure you want to delete this identity? You won\'t be able to receive any messages sent to this address and can\'t undo this operation.</string>
|
<string name="delete_identity_warning">Are you sure you want to delete this identity? You won\'t be able to receive any messages sent to this address and can\'t undo this operation.</string>
|
||||||
<string name="delete_contact_warning">Are you sure you want to delete this contact?</string>
|
<string name="delete_contact_warning">Are you sure you want to delete this contact?</string>
|
||||||
|
@ -9,7 +9,7 @@ buildscript {
|
|||||||
jcenter()
|
jcenter()
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:2.3.2'
|
classpath 'com.android.tools.build:gradle:2.3.3'
|
||||||
classpath 'com.github.ben-manes:gradle-versions-plugin:0.14.0'
|
classpath 'com.github.ben-manes:gradle-versions-plugin:0.14.0'
|
||||||
|
|
||||||
// NOTE: Do not place your application dependencies here; they belong
|
// NOTE: Do not place your application dependencies here; they belong
|
||||||
|
Loading…
Reference in New Issue
Block a user