Compare commits
10 Commits
1.0-beta18
...
1.0-beta20
Author | SHA1 | Date | |
---|---|---|---|
8a668f4af2 | |||
6829614da0 | |||
1906a2e13c | |||
708529fc0a | |||
b5dbbeb46a | |||
b368c8251d | |||
6986d9a2df | |||
35249a0145 | |||
2a1aa736cc | |||
9f26ade617 |
@ -20,8 +20,8 @@ android {
|
|||||||
applicationId "ch.dissem.apps.${appName.toLowerCase()}"
|
applicationId "ch.dissem.apps.${appName.toLowerCase()}"
|
||||||
minSdkVersion 19
|
minSdkVersion 19
|
||||||
targetSdkVersion 27
|
targetSdkVersion 27
|
||||||
versionCode 18
|
versionCode 20
|
||||||
versionName "1.0-beta18"
|
versionName "1.0-beta20"
|
||||||
multiDexEnabled true
|
multiDexEnabled true
|
||||||
}
|
}
|
||||||
compileOptions {
|
compileOptions {
|
||||||
|
@ -220,6 +220,7 @@ class MainActivity : AppCompatActivity(), ListSelectionListener<Serializable> {
|
|||||||
|
|
||||||
val drawerItems = ArrayList<IDrawerItem<*, *>>()
|
val drawerItems = ArrayList<IDrawerItem<*, *>>()
|
||||||
drawerItems.add(PrimaryDrawerItem()
|
drawerItems.add(PrimaryDrawerItem()
|
||||||
|
.withIdentifier(LABEL_ARCHIVE.id as Long)
|
||||||
.withName(R.string.archive)
|
.withName(R.string.archive)
|
||||||
.withTag(LABEL_ARCHIVE)
|
.withTag(LABEL_ARCHIVE)
|
||||||
.withIcon(CommunityMaterial.Icon.cmd_archive)
|
.withIcon(CommunityMaterial.Icon.cmd_archive)
|
||||||
@ -343,7 +344,7 @@ class MainActivity : AppCompatActivity(), ListSelectionListener<Serializable> {
|
|||||||
}
|
}
|
||||||
Singleton.getMessageListener(this).resetNotification()
|
Singleton.getMessageListener(this).resetNotification()
|
||||||
currentLabel.addObserver(this) { label ->
|
currentLabel.addObserver(this) { label ->
|
||||||
if (label != null) {
|
if (label != null && label.id is Long) {
|
||||||
drawer.setSelection(label.id as Long)
|
drawer.setSelection(label.id as Long)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,8 +19,8 @@ package ch.dissem.apps.abit.listener
|
|||||||
import android.content.BroadcastReceiver
|
import android.content.BroadcastReceiver
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import ch.dissem.apps.abit.service.BitmessageService
|
|
||||||
import ch.dissem.apps.abit.service.Singleton
|
import ch.dissem.apps.abit.service.Singleton
|
||||||
|
import ch.dissem.apps.abit.util.NetworkUtils
|
||||||
import ch.dissem.apps.abit.util.Preferences
|
import ch.dissem.apps.abit.util.Preferences
|
||||||
import org.jetbrains.anko.connectivityManager
|
import org.jetbrains.anko.connectivityManager
|
||||||
|
|
||||||
@ -29,7 +29,7 @@ class WifiReceiver : BroadcastReceiver() {
|
|||||||
if ("android.net.conn.CONNECTIVITY_CHANGE" == intent.action) {
|
if ("android.net.conn.CONNECTIVITY_CHANGE" == intent.action) {
|
||||||
val bmc = Singleton.getBitmessageContext(ctx)
|
val bmc = Singleton.getBitmessageContext(ctx)
|
||||||
if (Preferences.isFullNodeActive(ctx) && !bmc.isRunning() && !(Preferences.isWifiOnly(ctx) && ctx.connectivityManager.isActiveNetworkMetered)) {
|
if (Preferences.isFullNodeActive(ctx) && !bmc.isRunning() && !(Preferences.isWifiOnly(ctx) && ctx.connectivityManager.isActiveNetworkMetered)) {
|
||||||
ctx.startService(Intent(ctx, BitmessageService::class.java))
|
NetworkUtils.doStartBitmessageService(ctx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,8 +17,13 @@
|
|||||||
package ch.dissem.apps.abit.notification
|
package ch.dissem.apps.abit.notification
|
||||||
|
|
||||||
import android.app.Notification
|
import android.app.Notification
|
||||||
|
import android.app.NotificationChannel
|
||||||
import android.app.NotificationManager
|
import android.app.NotificationManager
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.os.Build
|
||||||
|
import android.support.annotation.ColorRes
|
||||||
|
import android.support.v4.content.ContextCompat
|
||||||
|
import ch.dissem.apps.abit.R
|
||||||
import org.jetbrains.anko.notificationManager
|
import org.jetbrains.anko.notificationManager
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -46,4 +51,30 @@ abstract class AbstractNotification(ctx: Context) {
|
|||||||
showing = false
|
showing = false
|
||||||
manager.cancel(notificationId)
|
manager.cancel(notificationId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected fun initChannel(channelId: String, @ColorRes color: Int = R.color.colorPrimary) {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
|
ctx.notificationManager.createNotificationChannel(
|
||||||
|
NotificationChannel(
|
||||||
|
channelId,
|
||||||
|
ctx.getText(R.string.app_name),
|
||||||
|
NotificationManager.IMPORTANCE_LOW
|
||||||
|
).apply {
|
||||||
|
lightColor = ContextCompat.getColor(ctx, color)
|
||||||
|
lockscreenVisibility = Notification.VISIBILITY_PRIVATE
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
internal const val ONGOING_CHANNEL_ID = "abit.ongoing"
|
||||||
|
internal const val MESSAGE_CHANNEL_ID = "abit.message"
|
||||||
|
internal const val ERROR_CHANNEL_ID = "abit.error"
|
||||||
|
|
||||||
|
init {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,10 +30,14 @@ import ch.dissem.apps.abit.R
|
|||||||
*/
|
*/
|
||||||
class ErrorNotification(ctx: Context) : AbstractNotification(ctx) {
|
class ErrorNotification(ctx: Context) : AbstractNotification(ctx) {
|
||||||
|
|
||||||
private val builder = NotificationCompat.Builder(ctx, "abit.error")
|
private val builder = NotificationCompat.Builder(ctx, ERROR_CHANNEL_ID)
|
||||||
.setContentTitle(ctx.getString(R.string.app_name))
|
.setContentTitle(ctx.getString(R.string.app_name))
|
||||||
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
|
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
|
||||||
|
|
||||||
|
init {
|
||||||
|
initChannel(ERROR_CHANNEL_ID, R.color.colorPrimaryDark)
|
||||||
|
}
|
||||||
|
|
||||||
fun setWarning(@StringRes resId: Int, vararg args: Any): ErrorNotification {
|
fun setWarning(@StringRes resId: Int, vararg args: Any): ErrorNotification {
|
||||||
builder.setSmallIcon(R.drawable.ic_notification_warning)
|
builder.setSmallIcon(R.drawable.ic_notification_warning)
|
||||||
.setContentText(ctx.getString(resId, *args))
|
.setContentText(ctx.getString(resId, *args))
|
||||||
|
@ -34,10 +34,11 @@ import kotlin.concurrent.fixedRateTimer
|
|||||||
*/
|
*/
|
||||||
class NetworkNotification(ctx: Context) : AbstractNotification(ctx) {
|
class NetworkNotification(ctx: Context) : AbstractNotification(ctx) {
|
||||||
|
|
||||||
private val builder = NotificationCompat.Builder(ctx, "abit.network")
|
private val builder = NotificationCompat.Builder(ctx, ONGOING_CHANNEL_ID)
|
||||||
private var timer: Timer? = null
|
private var timer: Timer? = null
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
initChannel(ONGOING_CHANNEL_ID, R.color.colorAccent)
|
||||||
val showAppIntent = Intent(ctx, MainActivity::class.java)
|
val showAppIntent = Intent(ctx, MainActivity::class.java)
|
||||||
val pendingIntent = PendingIntent.getActivity(ctx, 1, showAppIntent, 0)
|
val pendingIntent = PendingIntent.getActivity(ctx, 1, showAppIntent, 0)
|
||||||
builder
|
builder
|
||||||
@ -63,11 +64,19 @@ class NetworkNotification(ctx: Context) : AbstractNotification(ctx) {
|
|||||||
val streamNumber = Integer.parseInt(stream.name.substring("stream ".length))
|
val streamNumber = Integer.parseInt(stream.name.substring("stream ".length))
|
||||||
val nodeCount = stream.getProperty("nodes")!!.value as Int?
|
val nodeCount = stream.getProperty("nodes")!!.value as Int?
|
||||||
if (nodeCount == 1) {
|
if (nodeCount == 1) {
|
||||||
info.append(ctx.getString(R.string.connection_info_1,
|
info.append(
|
||||||
streamNumber))
|
ctx.getString(
|
||||||
|
R.string.connection_info_1,
|
||||||
|
streamNumber
|
||||||
|
)
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
info.append(ctx.getString(R.string.connection_info_n,
|
info.append(
|
||||||
streamNumber, nodeCount))
|
ctx.getString(
|
||||||
|
R.string.connection_info_n,
|
||||||
|
streamNumber, nodeCount
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
info.append('\n')
|
info.append('\n')
|
||||||
}
|
}
|
||||||
@ -77,14 +86,18 @@ class NetworkNotification(ctx: Context) : AbstractNotification(ctx) {
|
|||||||
val intent = Intent(ctx, BitmessageIntentService::class.java)
|
val intent = Intent(ctx, BitmessageIntentService::class.java)
|
||||||
if (running) {
|
if (running) {
|
||||||
intent.putExtra(BitmessageIntentService.EXTRA_SHUTDOWN_NODE, true)
|
intent.putExtra(BitmessageIntentService.EXTRA_SHUTDOWN_NODE, true)
|
||||||
builder.addAction(R.drawable.ic_notification_node_stop,
|
builder.addAction(
|
||||||
|
R.drawable.ic_notification_node_stop,
|
||||||
ctx.getString(R.string.full_node_stop),
|
ctx.getString(R.string.full_node_stop),
|
||||||
PendingIntent.getService(ctx, 0, intent, FLAG_UPDATE_CURRENT))
|
PendingIntent.getService(ctx, 0, intent, FLAG_UPDATE_CURRENT)
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
intent.putExtra(BitmessageIntentService.EXTRA_STARTUP_NODE, true)
|
intent.putExtra(BitmessageIntentService.EXTRA_STARTUP_NODE, true)
|
||||||
builder.addAction(R.drawable.ic_notification_node_start,
|
builder.addAction(
|
||||||
|
R.drawable.ic_notification_node_start,
|
||||||
ctx.getString(R.string.full_node_restart),
|
ctx.getString(R.string.full_node_restart),
|
||||||
PendingIntent.getService(ctx, 1, intent, FLAG_UPDATE_CURRENT))
|
PendingIntent.getService(ctx, 1, intent, FLAG_UPDATE_CURRENT)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
notification = builder.build()
|
notification = builder.build()
|
||||||
return running
|
return running
|
||||||
@ -116,13 +129,15 @@ class NetworkNotification(ctx: Context) : AbstractNotification(ctx) {
|
|||||||
val intent = Intent(ctx, BitmessageIntentService::class.java)
|
val intent = Intent(ctx, BitmessageIntentService::class.java)
|
||||||
intent.putExtra(BitmessageIntentService.EXTRA_SHUTDOWN_NODE, true)
|
intent.putExtra(BitmessageIntentService.EXTRA_SHUTDOWN_NODE, true)
|
||||||
builder.mActions.clear()
|
builder.mActions.clear()
|
||||||
builder.addAction(R.drawable.ic_notification_node_stop,
|
builder.addAction(
|
||||||
|
R.drawable.ic_notification_node_stop,
|
||||||
ctx.getString(R.string.full_node_stop),
|
ctx.getString(R.string.full_node_stop),
|
||||||
PendingIntent.getService(ctx, 0, intent, FLAG_UPDATE_CURRENT))
|
PendingIntent.getService(ctx, 0, intent, FLAG_UPDATE_CURRENT)
|
||||||
|
)
|
||||||
notification = builder.build()
|
notification = builder.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val NETWORK_NOTIFICATION_ID = 2
|
const val NETWORK_NOTIFICATION_ID = 2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,8 +42,12 @@ import ch.dissem.apps.abit.util.Drawables.toBitmap
|
|||||||
|
|
||||||
class NewMessageNotification(ctx: Context) : AbstractNotification(ctx) {
|
class NewMessageNotification(ctx: Context) : AbstractNotification(ctx) {
|
||||||
|
|
||||||
|
init {
|
||||||
|
initChannel(MESSAGE_CHANNEL_ID, R.color.colorPrimary)
|
||||||
|
}
|
||||||
|
|
||||||
fun singleNotification(plaintext: Plaintext): NewMessageNotification {
|
fun singleNotification(plaintext: Plaintext): NewMessageNotification {
|
||||||
val builder = NotificationCompat.Builder(ctx, CHANNEL_ID)
|
val builder = NotificationCompat.Builder(ctx, MESSAGE_CHANNEL_ID)
|
||||||
val bigText = SpannableString(plaintext.subject + "\n" + plaintext.text)
|
val bigText = SpannableString(plaintext.subject + "\n" + plaintext.text)
|
||||||
plaintext.subject?.let { subject ->
|
plaintext.subject?.let { subject ->
|
||||||
bigText.setSpan(SPAN_EMPHASIS, 0, subject.length, Spanned.SPAN_INCLUSIVE_EXCLUSIVE)
|
bigText.setSpan(SPAN_EMPHASIS, 0, subject.length, Spanned.SPAN_INCLUSIVE_EXCLUSIVE)
|
||||||
@ -56,22 +60,30 @@ class NewMessageNotification(ctx: Context) : AbstractNotification(ctx) {
|
|||||||
.setContentInfo("Info")
|
.setContentInfo("Info")
|
||||||
|
|
||||||
builder.setContentIntent(
|
builder.setContentIntent(
|
||||||
createActivityIntent(EXTRA_SHOW_MESSAGE, plaintext))
|
createActivityIntent(EXTRA_SHOW_MESSAGE, plaintext)
|
||||||
builder.addAction(R.drawable.ic_action_reply, ctx.getString(R.string.reply),
|
)
|
||||||
createActivityIntent(EXTRA_REPLY_TO_MESSAGE, plaintext))
|
builder.addAction(
|
||||||
builder.addAction(R.drawable.ic_action_delete, ctx.getString(R.string.delete),
|
R.drawable.ic_action_reply, ctx.getString(R.string.reply),
|
||||||
createServiceIntent(ctx, EXTRA_DELETE_MESSAGE, plaintext))
|
createActivityIntent(EXTRA_REPLY_TO_MESSAGE, plaintext)
|
||||||
|
)
|
||||||
|
builder.addAction(
|
||||||
|
R.drawable.ic_action_delete, ctx.getString(R.string.delete),
|
||||||
|
createServiceIntent(ctx, EXTRA_DELETE_MESSAGE, plaintext)
|
||||||
|
)
|
||||||
notification = builder.build()
|
notification = builder.build()
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createActivityIntent(action: String, message: Plaintext): PendingIntent {
|
private fun createActivityIntent(action: String, message: Plaintext): PendingIntent {
|
||||||
val intent = Intent(ctx, MainActivity::class.java)
|
val intent = Intent(ctx, MainActivity::class.java).putExtra(action, message)
|
||||||
intent.putExtra(action, message)
|
|
||||||
return PendingIntent.getActivity(ctx, action.hashCode(), intent, FLAG_UPDATE_CURRENT)
|
return PendingIntent.getActivity(ctx, action.hashCode(), intent, FLAG_UPDATE_CURRENT)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createServiceIntent(ctx: Context, action: String, message: Plaintext): PendingIntent {
|
private fun createServiceIntent(
|
||||||
|
ctx: Context,
|
||||||
|
action: String,
|
||||||
|
message: Plaintext
|
||||||
|
): PendingIntent {
|
||||||
val intent = Intent(ctx, BitmessageIntentService::class.java)
|
val intent = Intent(ctx, BitmessageIntentService::class.java)
|
||||||
intent.putExtra(action, message)
|
intent.putExtra(action, message)
|
||||||
return PendingIntent.getService(ctx, action.hashCode(), intent, FLAG_UPDATE_CURRENT)
|
return PendingIntent.getService(ctx, action.hashCode(), intent, FLAG_UPDATE_CURRENT)
|
||||||
@ -82,8 +94,11 @@ class NewMessageNotification(ctx: Context) : AbstractNotification(ctx) {
|
|||||||
* * accessed it will be in a `synchronized(unacknowledged)
|
* * accessed it will be in a `synchronized(unacknowledged)
|
||||||
* * {}` block
|
* * {}` block
|
||||||
*/
|
*/
|
||||||
fun multiNotification(unacknowledged: Collection<Plaintext>, numberOfUnacknowledgedMessages: Int): NewMessageNotification {
|
fun multiNotification(
|
||||||
val builder = NotificationCompat.Builder(ctx, CHANNEL_ID)
|
unacknowledged: Collection<Plaintext>,
|
||||||
|
numberOfUnacknowledgedMessages: Int
|
||||||
|
): NewMessageNotification {
|
||||||
|
val builder = NotificationCompat.Builder(ctx, MESSAGE_CHANNEL_ID)
|
||||||
builder.setSmallIcon(R.drawable.ic_notification_new_message)
|
builder.setSmallIcon(R.drawable.ic_notification_new_message)
|
||||||
.setContentTitle(ctx.getString(R.string.n_new_messages, numberOfUnacknowledgedMessages))
|
.setContentTitle(ctx.getString(R.string.n_new_messages, numberOfUnacknowledgedMessages))
|
||||||
.setContentText(ctx.getString(R.string.app_name))
|
.setContentText(ctx.getString(R.string.app_name))
|
||||||
@ -93,8 +108,10 @@ class NewMessageNotification(ctx: Context) : AbstractNotification(ctx) {
|
|||||||
synchronized(unacknowledged) {
|
synchronized(unacknowledged) {
|
||||||
for (msg in unacknowledged) {
|
for (msg in unacknowledged) {
|
||||||
val sb = SpannableString(msg.from.toString() + " " + msg.subject)
|
val sb = SpannableString(msg.from.toString() + " " + msg.subject)
|
||||||
sb.setSpan(SPAN_EMPHASIS, 0, msg.from.toString().length, Spannable
|
sb.setSpan(
|
||||||
.SPAN_INCLUSIVE_EXCLUSIVE)
|
SPAN_EMPHASIS, 0, msg.from.toString().length, Spannable
|
||||||
|
.SPAN_INCLUSIVE_EXCLUSIVE
|
||||||
|
)
|
||||||
inboxStyle.addLine(sb)
|
inboxStyle.addLine(sb)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -113,6 +130,5 @@ class NewMessageNotification(ctx: Context) : AbstractNotification(ctx) {
|
|||||||
companion object {
|
companion object {
|
||||||
private val NEW_MESSAGE_NOTIFICATION_ID = 1
|
private val NEW_MESSAGE_NOTIFICATION_ID = 1
|
||||||
private val SPAN_EMPHASIS = StyleSpan(Typeface.BOLD)
|
private val SPAN_EMPHASIS = StyleSpan(Typeface.BOLD)
|
||||||
private val CHANNEL_ID = "abit.message"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,7 @@ import kotlin.concurrent.fixedRateTimer
|
|||||||
*/
|
*/
|
||||||
class ProofOfWorkNotification(ctx: Context) : AbstractNotification(ctx) {
|
class ProofOfWorkNotification(ctx: Context) : AbstractNotification(ctx) {
|
||||||
|
|
||||||
private val builder = NotificationCompat.Builder(ctx, "abit.pow")
|
private val builder = NotificationCompat.Builder(ctx, ONGOING_CHANNEL_ID)
|
||||||
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
|
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
|
||||||
.setUsesChronometer(true)
|
.setUsesChronometer(true)
|
||||||
.setOngoing(true)
|
.setOngoing(true)
|
||||||
@ -46,6 +46,7 @@ class ProofOfWorkNotification(ctx: Context) : AbstractNotification(ctx) {
|
|||||||
private var timer: Timer? = null
|
private var timer: Timer? = null
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
initChannel(ONGOING_CHANNEL_ID, R.color.colorAccent)
|
||||||
update(0)
|
update(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,10 +68,6 @@ class ProofOfWorkNotification(ctx: Context) : AbstractNotification(ctx) {
|
|||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
|
||||||
const val ONGOING_NOTIFICATION_ID = 3
|
|
||||||
}
|
|
||||||
|
|
||||||
fun start(item: ProofOfWorkService.PowItem) {
|
fun start(item: ProofOfWorkService.PowItem) {
|
||||||
val expectedPowTimeInMilliseconds = PowStats.getExpectedPowTimeInMilliseconds(ctx, item.targetValue)
|
val expectedPowTimeInMilliseconds = PowStats.getExpectedPowTimeInMilliseconds(ctx, item.targetValue)
|
||||||
val delta = (expectedPowTimeInMilliseconds / 3).toInt()
|
val delta = (expectedPowTimeInMilliseconds / 3).toInt()
|
||||||
@ -101,4 +98,8 @@ class ProofOfWorkNotification(ctx: Context) : AbstractNotification(ctx) {
|
|||||||
show()
|
show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val ONGOING_NOTIFICATION_ID = 3
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -86,8 +86,7 @@ class AndroidAddressRepository(private val sql: SqlHelper) : AddressRepository {
|
|||||||
// you will actually use after this query.
|
// you will actually use after this query.
|
||||||
val projection = arrayOf(COLUMN_ADDRESS)
|
val projection = arrayOf(COLUMN_ADDRESS)
|
||||||
|
|
||||||
val db = sql.readableDatabase
|
sql.readableDatabase.query(
|
||||||
db.query(
|
|
||||||
TABLE_NAME, projection,
|
TABLE_NAME, projection,
|
||||||
where, null, null, null,
|
where, null, null, null,
|
||||||
orderBy
|
orderBy
|
||||||
@ -106,8 +105,7 @@ class AndroidAddressRepository(private val sql: SqlHelper) : AddressRepository {
|
|||||||
// you will actually use after this query.
|
// you will actually use after this query.
|
||||||
val projection = arrayOf(COLUMN_ADDRESS, COLUMN_ALIAS, COLUMN_PUBLIC_KEY, COLUMN_PRIVATE_KEY, COLUMN_SUBSCRIBED, COLUMN_CHAN)
|
val projection = arrayOf(COLUMN_ADDRESS, COLUMN_ALIAS, COLUMN_PUBLIC_KEY, COLUMN_PRIVATE_KEY, COLUMN_SUBSCRIBED, COLUMN_CHAN)
|
||||||
|
|
||||||
val db = sql.readableDatabase
|
sql.readableDatabase.query(
|
||||||
db.query(
|
|
||||||
TABLE_NAME, projection,
|
TABLE_NAME, projection,
|
||||||
where, null, null, null, null
|
where, null, null, null, null
|
||||||
).use { c ->
|
).use { c ->
|
||||||
@ -154,8 +152,7 @@ class AndroidAddressRepository(private val sql: SqlHelper) : AddressRepository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun exists(address: BitmessageAddress): Boolean {
|
private fun exists(address: BitmessageAddress): Boolean {
|
||||||
val db = sql.readableDatabase
|
sql.readableDatabase.rawQuery(
|
||||||
db.rawQuery(
|
|
||||||
"SELECT COUNT(*) FROM Address WHERE address=?",
|
"SELECT COUNT(*) FROM Address WHERE address=?",
|
||||||
arrayOf(address.address)
|
arrayOf(address.address)
|
||||||
).use { cursor ->
|
).use { cursor ->
|
||||||
@ -165,49 +162,45 @@ class AndroidAddressRepository(private val sql: SqlHelper) : AddressRepository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun update(address: BitmessageAddress) {
|
private fun update(address: BitmessageAddress) {
|
||||||
val db = sql.writableDatabase
|
|
||||||
// Create a new map of values, where column names are the keys
|
// Create a new map of values, where column names are the keys
|
||||||
val values = getContentValues(address)
|
val values = getContentValues(address)
|
||||||
|
|
||||||
val update = db.update(TABLE_NAME, values, "address=?", arrayOf(address.address))
|
val update = sql.writableDatabase.update(TABLE_NAME, values, "address=?", arrayOf(address.address))
|
||||||
if (update < 0) {
|
if (update < 0) {
|
||||||
LOG.error("Could not update address {}", address)
|
LOG.error("Could not update address {}", address)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun insert(address: BitmessageAddress) {
|
private fun insert(address: BitmessageAddress) {
|
||||||
val db = sql.writableDatabase
|
|
||||||
// Create a new map of values, where column names are the keys
|
// Create a new map of values, where column names are the keys
|
||||||
val values = getContentValues(address)
|
val values = getContentValues(address).apply {
|
||||||
values.put(COLUMN_ADDRESS, address.address)
|
put(COLUMN_ADDRESS, address.address)
|
||||||
values.put(COLUMN_VERSION, address.version)
|
put(COLUMN_VERSION, address.version)
|
||||||
values.put(COLUMN_CHAN, address.isChan)
|
put(COLUMN_CHAN, address.isChan)
|
||||||
|
}
|
||||||
|
|
||||||
val insert = db.insert(TABLE_NAME, null, values)
|
val insert = sql.writableDatabase.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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getContentValues(address: BitmessageAddress): ContentValues {
|
private fun getContentValues(address: BitmessageAddress) = ContentValues().apply {
|
||||||
val values = ContentValues()
|
address.alias?.let { put(COLUMN_ALIAS, it) }
|
||||||
address.alias?.let { values.put(COLUMN_ALIAS, it) }
|
|
||||||
address.pubkey?.let { pubkey ->
|
address.pubkey?.let { pubkey ->
|
||||||
val out = ByteArrayOutputStream()
|
val out = ByteArrayOutputStream()
|
||||||
pubkey.writer().writeUnencrypted(out)
|
pubkey.writer().writeUnencrypted(out)
|
||||||
values.put(COLUMN_PUBLIC_KEY, out.toByteArray())
|
put(COLUMN_PUBLIC_KEY, out.toByteArray())
|
||||||
}
|
}
|
||||||
address.privateKey?.let { values.put(COLUMN_PRIVATE_KEY, Encode.bytes(it)) }
|
address.privateKey?.let { put(COLUMN_PRIVATE_KEY, Encode.bytes(it)) }
|
||||||
if (address.isChan) {
|
if (address.isChan) {
|
||||||
values.put(COLUMN_CHAN, true)
|
put(COLUMN_CHAN, true)
|
||||||
}
|
}
|
||||||
values.put(COLUMN_SUBSCRIBED, address.isSubscribed)
|
put(COLUMN_SUBSCRIBED, address.isSubscribed)
|
||||||
return values
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun remove(address: BitmessageAddress) {
|
override fun remove(address: BitmessageAddress) {
|
||||||
val db = sql.writableDatabase
|
sql.writableDatabase.delete(TABLE_NAME, "address = ?", arrayOf(address.address))
|
||||||
db.delete(TABLE_NAME, "address = ?", arrayOf(address.address))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getAddress(address: String) = find("address = '$address'").firstOrNull()
|
override fun getAddress(address: String) = find("address = '$address'").firstOrNull()
|
||||||
|
@ -57,8 +57,8 @@ class AndroidInventory(private val sql: SqlHelper) : Inventory {
|
|||||||
cache.put(stream, result)
|
cache.put(stream, result)
|
||||||
|
|
||||||
val projection = arrayOf(COLUMN_HASH, COLUMN_EXPIRES)
|
val projection = arrayOf(COLUMN_HASH, COLUMN_EXPIRES)
|
||||||
val db = sql.readableDatabase
|
|
||||||
db.query(
|
sql.readableDatabase.query(
|
||||||
TABLE_NAME, projection,
|
TABLE_NAME, projection,
|
||||||
"stream = $stream", null, null, null, null
|
"stream = $stream", null, null, null, null
|
||||||
).use { c ->
|
).use { c ->
|
||||||
@ -84,8 +84,7 @@ class AndroidInventory(private val sql: SqlHelper) : Inventory {
|
|||||||
// you will actually use after this query.
|
// you will actually use after this query.
|
||||||
val projection = arrayOf(COLUMN_VERSION, COLUMN_DATA)
|
val projection = arrayOf(COLUMN_VERSION, COLUMN_DATA)
|
||||||
|
|
||||||
val db = sql.readableDatabase
|
sql.readableDatabase.query(
|
||||||
db.query(
|
|
||||||
TABLE_NAME, projection,
|
TABLE_NAME, projection,
|
||||||
"hash = X'$vector'", null, null, null, null
|
"hash = X'$vector'", null, null, null, null
|
||||||
).use { c ->
|
).use { c ->
|
||||||
@ -115,9 +114,8 @@ class AndroidInventory(private val sql: SqlHelper) : Inventory {
|
|||||||
where.append(" AND type IN (").append(types.joinToString(separator = "', '", prefix = "'", postfix = "'", transform = { it.number.toString() })).append(")")
|
where.append(" AND type IN (").append(types.joinToString(separator = "', '", prefix = "'", postfix = "'", transform = { it.number.toString() })).append(")")
|
||||||
}
|
}
|
||||||
|
|
||||||
val db = sql.readableDatabase
|
|
||||||
val result = LinkedList<ObjectMessage>()
|
val result = LinkedList<ObjectMessage>()
|
||||||
db.query(
|
sql.readableDatabase.query(
|
||||||
TABLE_NAME, projection,
|
TABLE_NAME, projection,
|
||||||
where.toString(), null, null, null, null
|
where.toString(), null, null, null, null
|
||||||
).use { c ->
|
).use { c ->
|
||||||
@ -139,31 +137,29 @@ class AndroidInventory(private val sql: SqlHelper) : Inventory {
|
|||||||
LOG.trace("Storing object {}", iv)
|
LOG.trace("Storing object {}", iv)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
val db = sql.writableDatabase
|
|
||||||
// Create a new map of values, where column names are the keys
|
// Create a new map of values, where column names are the keys
|
||||||
val values = ContentValues()
|
val values = ContentValues().apply {
|
||||||
values.put(COLUMN_HASH, objectMessage.inventoryVector.hash)
|
put(COLUMN_HASH, objectMessage.inventoryVector.hash)
|
||||||
values.put(COLUMN_STREAM, objectMessage.stream)
|
put(COLUMN_STREAM, objectMessage.stream)
|
||||||
values.put(COLUMN_EXPIRES, objectMessage.expiresTime)
|
put(COLUMN_EXPIRES, objectMessage.expiresTime)
|
||||||
values.put(COLUMN_DATA, Encode.bytes(objectMessage))
|
put(COLUMN_DATA, Encode.bytes(objectMessage))
|
||||||
values.put(COLUMN_TYPE, objectMessage.type)
|
put(COLUMN_TYPE, objectMessage.type)
|
||||||
values.put(COLUMN_VERSION, objectMessage.version)
|
put(COLUMN_VERSION, objectMessage.version)
|
||||||
|
}
|
||||||
|
|
||||||
db.insertOrThrow(TABLE_NAME, null, values)
|
sql.writableDatabase.insertOrThrow(TABLE_NAME, null, values)
|
||||||
|
|
||||||
getCache(objectMessage.stream).put(iv, objectMessage.expiresTime)
|
getCache(objectMessage.stream).put(iv, objectMessage.expiresTime)
|
||||||
} catch (e: SQLiteConstraintException) {
|
} catch (e: SQLiteConstraintException) {
|
||||||
LOG.trace(e.message, e)
|
LOG.trace(e.message, e)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun contains(objectMessage: ObjectMessage) = getCache(objectMessage.stream).keys.contains(objectMessage.inventoryVector)
|
override fun contains(objectMessage: ObjectMessage) = getCache(objectMessage.stream).keys.contains(objectMessage.inventoryVector)
|
||||||
|
|
||||||
override fun cleanup() {
|
override fun cleanup() {
|
||||||
val fiveMinutesAgo = now - 5 * MINUTE
|
val fiveMinutesAgo = now - 5 * MINUTE
|
||||||
val db = sql.writableDatabase
|
sql.writableDatabase.delete(TABLE_NAME, "expires < ?", arrayOf(fiveMinutesAgo.toString()))
|
||||||
db.delete(TABLE_NAME, "expires < ?", arrayOf(fiveMinutesAgo.toString()))
|
|
||||||
|
|
||||||
cache.values.map { it.entries }.forEach { entries -> entries.removeAll { it.value < fiveMinutesAgo } }
|
cache.values.map { it.entries }.forEach { entries -> entries.removeAll { it.value < fiveMinutesAgo } }
|
||||||
}
|
}
|
||||||
|
@ -85,7 +85,7 @@ class AndroidLabelRepository(private val sql: SqlHelper, private val context: Co
|
|||||||
internal fun findLabels(msgId: Any) = find("id IN (SELECT label_id FROM Message_Label WHERE message_id=$msgId)")
|
internal fun findLabels(msgId: Any) = find("id IN (SELECT label_id FROM Message_Label WHERE message_id=$msgId)")
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val LABEL_ARCHIVE = Label("archive", null, 0)
|
val LABEL_ARCHIVE = Label("archive", null, 0).apply { id = Long.MAX_VALUE }
|
||||||
|
|
||||||
private const val TABLE_NAME = "Label"
|
private const val TABLE_NAME = "Label"
|
||||||
private const val COLUMN_ID = "id"
|
private const val COLUMN_ID = "id"
|
||||||
|
@ -19,7 +19,6 @@ 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.DatabaseUtils
|
import android.database.DatabaseUtils
|
||||||
import android.database.sqlite.SQLiteConstraintException
|
|
||||||
import android.database.sqlite.SQLiteDatabase
|
import android.database.sqlite.SQLiteDatabase
|
||||||
import ch.dissem.apps.abit.repository.AndroidLabelRepository.Companion.LABEL_ARCHIVE
|
import ch.dissem.apps.abit.repository.AndroidLabelRepository.Companion.LABEL_ARCHIVE
|
||||||
import ch.dissem.apps.abit.util.UuidUtils
|
import ch.dissem.apps.abit.util.UuidUtils
|
||||||
@ -29,7 +28,6 @@ import ch.dissem.bitmessage.entity.Plaintext
|
|||||||
import ch.dissem.bitmessage.entity.valueobject.InventoryVector
|
import ch.dissem.bitmessage.entity.valueobject.InventoryVector
|
||||||
import ch.dissem.bitmessage.entity.valueobject.Label
|
import ch.dissem.bitmessage.entity.valueobject.Label
|
||||||
import ch.dissem.bitmessage.ports.AbstractMessageRepository
|
import ch.dissem.bitmessage.ports.AbstractMessageRepository
|
||||||
import ch.dissem.bitmessage.ports.AlreadyStoredException
|
|
||||||
import ch.dissem.bitmessage.ports.MessageRepository
|
import ch.dissem.bitmessage.ports.MessageRepository
|
||||||
import ch.dissem.bitmessage.utils.Encode
|
import ch.dissem.bitmessage.utils.Encode
|
||||||
import ch.dissem.bitmessage.utils.Strings.hex
|
import ch.dissem.bitmessage.utils.Strings.hex
|
||||||
@ -137,8 +135,7 @@ class AndroidMessageRepository(private val sql: SqlHelper) : AbstractMessageRepo
|
|||||||
// you will actually use after this query.
|
// you will actually use after this query.
|
||||||
val projection = arrayOf(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_CONVERSATION)
|
val projection = arrayOf(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_CONVERSATION)
|
||||||
|
|
||||||
val db = sql.readableDatabase
|
sql.readableDatabase.query(
|
||||||
db.query(
|
|
||||||
TABLE_NAME, projection,
|
TABLE_NAME, projection,
|
||||||
where, null, null, null,
|
where, null, null, null,
|
||||||
"$COLUMN_RECEIVED DESC, $COLUMN_SENT DESC",
|
"$COLUMN_RECEIVED DESC, $COLUMN_SENT DESC",
|
||||||
@ -206,23 +203,21 @@ class AndroidMessageRepository(private val sql: SqlHelper) : AbstractMessageRepo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getValues(message: Plaintext): ContentValues {
|
private fun getValues(message: Plaintext) = ContentValues(14).apply {
|
||||||
val values = ContentValues()
|
put(COLUMN_IV, message.inventoryVector?.hash)
|
||||||
values.put(COLUMN_IV, message.inventoryVector?.hash)
|
put(COLUMN_TYPE, message.type.name)
|
||||||
values.put(COLUMN_TYPE, message.type.name)
|
put(COLUMN_SENDER, message.from.address)
|
||||||
values.put(COLUMN_SENDER, message.from.address)
|
put(COLUMN_RECIPIENT, message.to?.address)
|
||||||
values.put(COLUMN_RECIPIENT, message.to?.address)
|
put(COLUMN_DATA, Encode.bytes(message))
|
||||||
values.put(COLUMN_DATA, Encode.bytes(message))
|
put(COLUMN_ACK_DATA, message.ackData)
|
||||||
values.put(COLUMN_ACK_DATA, message.ackData)
|
put(COLUMN_SENT, message.sent)
|
||||||
values.put(COLUMN_SENT, message.sent)
|
put(COLUMN_RECEIVED, message.received)
|
||||||
values.put(COLUMN_RECEIVED, message.received)
|
put(COLUMN_STATUS, message.status.name)
|
||||||
values.put(COLUMN_STATUS, message.status.name)
|
put(COLUMN_INITIAL_HASH, message.initialHash)
|
||||||
values.put(COLUMN_INITIAL_HASH, message.initialHash)
|
put(COLUMN_TTL, message.ttl)
|
||||||
values.put(COLUMN_TTL, message.ttl)
|
put(COLUMN_RETRIES, message.retries)
|
||||||
values.put(COLUMN_RETRIES, message.retries)
|
put(COLUMN_NEXT_TRY, message.nextTry)
|
||||||
values.put(COLUMN_NEXT_TRY, message.nextTry)
|
put(COLUMN_CONVERSATION, UuidUtils.asBytes(message.conversationId))
|
||||||
values.put(COLUMN_CONVERSATION, UuidUtils.asBytes(message.conversationId))
|
|
||||||
return values
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun insert(db: SQLiteDatabase, message: Plaintext) {
|
private fun insert(db: SQLiteDatabase, message: Plaintext) {
|
||||||
@ -235,8 +230,7 @@ class AndroidMessageRepository(private val sql: SqlHelper) : AbstractMessageRepo
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun remove(message: Plaintext) {
|
override fun remove(message: Plaintext) {
|
||||||
val db = sql.writableDatabase
|
sql.writableDatabase.delete(TABLE_NAME, "id = ?", arrayOf(message.id.toString()))
|
||||||
db.delete(TABLE_NAME, "id = ?", arrayOf(message.id.toString()))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
@ -5,7 +5,6 @@ import android.database.sqlite.SQLiteConstraintException
|
|||||||
import android.database.sqlite.SQLiteDoneException
|
import android.database.sqlite.SQLiteDoneException
|
||||||
import android.database.sqlite.SQLiteStatement
|
import android.database.sqlite.SQLiteStatement
|
||||||
import ch.dissem.bitmessage.entity.valueobject.NetworkAddress
|
import ch.dissem.bitmessage.entity.valueobject.NetworkAddress
|
||||||
import ch.dissem.bitmessage.exception.ApplicationException
|
|
||||||
import ch.dissem.bitmessage.ports.NodeRegistry
|
import ch.dissem.bitmessage.ports.NodeRegistry
|
||||||
import ch.dissem.bitmessage.ports.NodeRegistryHelper.loadStableNodes
|
import ch.dissem.bitmessage.ports.NodeRegistryHelper.loadStableNodes
|
||||||
import ch.dissem.bitmessage.utils.Collections
|
import ch.dissem.bitmessage.utils.Collections
|
||||||
@ -120,12 +119,12 @@ class AndroidNodeRegistry(private val sql: SqlHelper) : NodeRegistry {
|
|||||||
private fun insert(node: NetworkAddress) {
|
private fun insert(node: NetworkAddress) {
|
||||||
try {
|
try {
|
||||||
// Create a new map of values, where column names are the keys
|
// Create a new map of values, where column names are the keys
|
||||||
val values = ContentValues()
|
val values = ContentValues().apply {
|
||||||
values.put(COLUMN_STREAM, node.stream)
|
put(COLUMN_STREAM, node.stream)
|
||||||
values.put(COLUMN_ADDRESS, node.IPv6)
|
put(COLUMN_ADDRESS, node.IPv6)
|
||||||
values.put(COLUMN_PORT, node.port)
|
put(COLUMN_PORT, node.port)
|
||||||
values.put(COLUMN_SERVICES, node.services)
|
put(COLUMN_SERVICES, node.services)
|
||||||
values.put(COLUMN_TIME,
|
put(COLUMN_TIME,
|
||||||
if (node.time > UnixTime.now) {
|
if (node.time > UnixTime.now) {
|
||||||
// This might be an attack, let's not use those nodes with priority
|
// This might be an attack, let's not use those nodes with priority
|
||||||
UnixTime.now - 7 * UnixTime.DAY
|
UnixTime.now - 7 * UnixTime.DAY
|
||||||
@ -133,6 +132,7 @@ class AndroidNodeRegistry(private val sql: SqlHelper) : NodeRegistry {
|
|||||||
node.time
|
node.time
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
sql.writableDatabase.insertOrThrow(TABLE_NAME, null, values)
|
sql.writableDatabase.insertOrThrow(TABLE_NAME, null, values)
|
||||||
} catch (e: SQLiteConstraintException) {
|
} catch (e: SQLiteConstraintException) {
|
||||||
@ -150,9 +150,10 @@ class AndroidNodeRegistry(private val sql: SqlHelper) : NodeRegistry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create a new map of values, where column names are the keys
|
// Create a new map of values, where column names are the keys
|
||||||
val values = ContentValues()
|
val values = ContentValues().apply {
|
||||||
values.put(COLUMN_SERVICES, node.services)
|
put(COLUMN_SERVICES, node.services)
|
||||||
values.put(COLUMN_TIME, max(node.time, time))
|
put(COLUMN_TIME, max(node.time, time))
|
||||||
|
}
|
||||||
|
|
||||||
sql.writableDatabase.update(
|
sql.writableDatabase.update(
|
||||||
TABLE_NAME,
|
TABLE_NAME,
|
||||||
|
@ -48,8 +48,7 @@ class AndroidProofOfWorkRepository(private val sql: SqlHelper) : ProofOfWorkRepo
|
|||||||
// you will actually use after this query.
|
// you will actually use after this query.
|
||||||
val projection = arrayOf(COLUMN_DATA, COLUMN_VERSION, COLUMN_NONCE_TRIALS_PER_BYTE, COLUMN_EXTRA_BYTES, COLUMN_EXPIRATION_TIME, COLUMN_MESSAGE_ID)
|
val projection = arrayOf(COLUMN_DATA, COLUMN_VERSION, COLUMN_NONCE_TRIALS_PER_BYTE, COLUMN_EXTRA_BYTES, COLUMN_EXPIRATION_TIME, COLUMN_MESSAGE_ID)
|
||||||
|
|
||||||
val db = sql.readableDatabase
|
sql.readableDatabase.query(
|
||||||
db.query(
|
|
||||||
TABLE_NAME, projection,
|
TABLE_NAME, projection,
|
||||||
"initial_hash=X'${hex(initialHash)}'",
|
"initial_hash=X'${hex(initialHash)}'",
|
||||||
null, null, null, null
|
null, null, null, null
|
||||||
@ -82,9 +81,8 @@ class AndroidProofOfWorkRepository(private val sql: SqlHelper) : ProofOfWorkRepo
|
|||||||
// you will actually use after this query.
|
// you will actually use after this query.
|
||||||
val projection = arrayOf(COLUMN_INITIAL_HASH)
|
val projection = arrayOf(COLUMN_INITIAL_HASH)
|
||||||
|
|
||||||
val db = sql.readableDatabase
|
|
||||||
val result = LinkedList<ByteArray>()
|
val result = LinkedList<ByteArray>()
|
||||||
db.query(
|
sql.readableDatabase.query(
|
||||||
TABLE_NAME, projection, null, null, null, null, null
|
TABLE_NAME, projection, null, null, null, null, null
|
||||||
).use { c ->
|
).use { c ->
|
||||||
while (c.moveToNext()) {
|
while (c.moveToNext()) {
|
||||||
@ -97,20 +95,20 @@ class AndroidProofOfWorkRepository(private val sql: SqlHelper) : ProofOfWorkRepo
|
|||||||
|
|
||||||
override fun putObject(item: ProofOfWorkRepository.Item) {
|
override fun putObject(item: ProofOfWorkRepository.Item) {
|
||||||
try {
|
try {
|
||||||
val db = sql.writableDatabase
|
|
||||||
// Create a new map of values, where column names are the keys
|
// Create a new map of values, where column names are the keys
|
||||||
val values = ContentValues()
|
val values = ContentValues().apply {
|
||||||
values.put(COLUMN_INITIAL_HASH, cryptography().getInitialHash(item.objectMessage))
|
put(COLUMN_INITIAL_HASH, cryptography().getInitialHash(item.objectMessage))
|
||||||
values.put(COLUMN_DATA, Encode.bytes(item.objectMessage))
|
put(COLUMN_DATA, Encode.bytes(item.objectMessage))
|
||||||
values.put(COLUMN_VERSION, item.objectMessage.version)
|
put(COLUMN_VERSION, item.objectMessage.version)
|
||||||
values.put(COLUMN_NONCE_TRIALS_PER_BYTE, item.nonceTrialsPerByte)
|
put(COLUMN_NONCE_TRIALS_PER_BYTE, item.nonceTrialsPerByte)
|
||||||
values.put(COLUMN_EXTRA_BYTES, item.extraBytes)
|
put(COLUMN_EXTRA_BYTES, item.extraBytes)
|
||||||
item.message?.let { message ->
|
item.message?.let { message ->
|
||||||
values.put(COLUMN_EXPIRATION_TIME, item.expirationTime)
|
put(COLUMN_EXPIRATION_TIME, item.expirationTime)
|
||||||
values.put(COLUMN_MESSAGE_ID, message.id as Long?)
|
put(COLUMN_MESSAGE_ID, message.id as Long?)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
db.insertOrThrow(TABLE_NAME, null, values)
|
sql.writableDatabase.insertOrThrow(TABLE_NAME, null, values)
|
||||||
} catch (e: SQLiteConstraintException) {
|
} catch (e: SQLiteConstraintException) {
|
||||||
LOG.trace(e.message, e)
|
LOG.trace(e.message, e)
|
||||||
}
|
}
|
||||||
@ -121,8 +119,7 @@ class AndroidProofOfWorkRepository(private val sql: SqlHelper) : ProofOfWorkRepo
|
|||||||
putObject(ProofOfWorkRepository.Item(objectMessage, nonceTrialsPerByte, extraBytes))
|
putObject(ProofOfWorkRepository.Item(objectMessage, nonceTrialsPerByte, extraBytes))
|
||||||
|
|
||||||
override fun removeObject(initialHash: ByteArray) {
|
override fun removeObject(initialHash: ByteArray) {
|
||||||
val db = sql.writableDatabase
|
sql.writableDatabase.delete(TABLE_NAME, "initial_hash=X'${hex(initialHash)}'", null)
|
||||||
db.delete(TABLE_NAME, "initial_hash=X'${hex(initialHash)}'", null)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
@ -76,8 +76,9 @@ class SqlHelper(private val ctx: Context) : SQLiteOpenHelper(ctx, DATABASE_NAME,
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun setMissingConversationId(id: Long, db: SQLiteDatabase) {
|
private fun setMissingConversationId(id: Long, db: SQLiteDatabase) {
|
||||||
val values = ContentValues(1)
|
val values = ContentValues(1).apply {
|
||||||
values.put("conversation", UuidUtils.asBytes(UUID.randomUUID()))
|
put("conversation", UuidUtils.asBytes(UUID.randomUUID()))
|
||||||
|
}
|
||||||
db.update("Message", values, "id=?", arrayOf(id.toString()))
|
db.update("Message", values, "id=?", arrayOf(id.toString()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,6 +25,8 @@ import android.net.ConnectivityManager
|
|||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import ch.dissem.apps.abit.notification.NetworkNotification
|
import ch.dissem.apps.abit.notification.NetworkNotification
|
||||||
import ch.dissem.apps.abit.notification.NetworkNotification.Companion.NETWORK_NOTIFICATION_ID
|
import ch.dissem.apps.abit.notification.NetworkNotification.Companion.NETWORK_NOTIFICATION_ID
|
||||||
|
import ch.dissem.apps.abit.util.NetworkUtils
|
||||||
|
import ch.dissem.apps.abit.util.Preferences
|
||||||
import ch.dissem.bitmessage.BitmessageContext
|
import ch.dissem.bitmessage.BitmessageContext
|
||||||
import ch.dissem.bitmessage.utils.Property
|
import ch.dissem.bitmessage.utils.Property
|
||||||
import org.jetbrains.anko.connectivityManager
|
import org.jetbrains.anko.connectivityManager
|
||||||
@ -39,9 +41,9 @@ class BitmessageService : Service() {
|
|||||||
private val bmc: BitmessageContext by lazy { Singleton.getBitmessageContext(this) }
|
private val bmc: BitmessageContext by lazy { Singleton.getBitmessageContext(this) }
|
||||||
private lateinit var notification: NetworkNotification
|
private lateinit var notification: NetworkNotification
|
||||||
|
|
||||||
private val connectivityReceiver: BroadcastReceiver = object: BroadcastReceiver() {
|
private val connectivityReceiver: BroadcastReceiver = object : BroadcastReceiver() {
|
||||||
override fun onReceive(context: Context?, intent: Intent?) {
|
override fun onReceive(context: Context, intent: Intent?) {
|
||||||
if (bmc.isRunning() && connectivityManager.isActiveNetworkMetered){
|
if (bmc.isRunning() && !Preferences.isConnectionAllowed(this@BitmessageService)) {
|
||||||
bmc.shutdown()
|
bmc.shutdown()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -58,7 +60,10 @@ class BitmessageService : Service() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
registerReceiver(connectivityReceiver, IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION))
|
registerReceiver(
|
||||||
|
connectivityReceiver,
|
||||||
|
IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)
|
||||||
|
)
|
||||||
notification = NetworkNotification(this)
|
notification = NetworkNotification(this)
|
||||||
running = false
|
running = false
|
||||||
}
|
}
|
||||||
@ -85,13 +90,15 @@ class BitmessageService : Service() {
|
|||||||
notification.showShutdown()
|
notification.showShutdown()
|
||||||
cleanupHandler.removeCallbacks(cleanupTask)
|
cleanupHandler.removeCallbacks(cleanupTask)
|
||||||
bmc.cleanup()
|
bmc.cleanup()
|
||||||
|
unregisterReceiver(connectivityReceiver)
|
||||||
stopSelf()
|
stopSelf()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBind(intent: Intent) = null
|
override fun onBind(intent: Intent) = null
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@Volatile private var running = false
|
@Volatile
|
||||||
|
private var running = false
|
||||||
|
|
||||||
val isRunning: Boolean
|
val isRunning: Boolean
|
||||||
get() = running && Singleton.bitmessageContext?.isRunning() == true
|
get() = running && Singleton.bitmessageContext?.isRunning() == true
|
||||||
|
@ -20,6 +20,7 @@ import android.app.Service
|
|||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Binder
|
import android.os.Binder
|
||||||
import android.os.IBinder
|
import android.os.IBinder
|
||||||
|
import android.support.v4.content.ContextCompat
|
||||||
import ch.dissem.apps.abit.notification.ProofOfWorkNotification
|
import ch.dissem.apps.abit.notification.ProofOfWorkNotification
|
||||||
import ch.dissem.apps.abit.notification.ProofOfWorkNotification.Companion.ONGOING_NOTIFICATION_ID
|
import ch.dissem.apps.abit.notification.ProofOfWorkNotification.Companion.ONGOING_NOTIFICATION_ID
|
||||||
import ch.dissem.apps.abit.util.PowStats
|
import ch.dissem.apps.abit.util.PowStats
|
||||||
@ -44,9 +45,14 @@ class ProofOfWorkService : Service() {
|
|||||||
private val notification = service.notification
|
private val notification = service.notification
|
||||||
|
|
||||||
fun process(item: PowItem) = synchronized(queue) {
|
fun process(item: PowItem) = synchronized(queue) {
|
||||||
service.startService(Intent(service, ProofOfWorkService::class.java))
|
ContextCompat.startForegroundService(
|
||||||
service.startForeground(ONGOING_NOTIFICATION_ID,
|
service,
|
||||||
notification.notification)
|
Intent(service, ProofOfWorkService::class.java)
|
||||||
|
)
|
||||||
|
service.startForeground(
|
||||||
|
ONGOING_NOTIFICATION_ID,
|
||||||
|
notification.notification
|
||||||
|
)
|
||||||
if (!calculating) {
|
if (!calculating) {
|
||||||
calculating = true
|
calculating = true
|
||||||
service.calculateNonce(item)
|
service.calculateNonce(item)
|
||||||
@ -58,7 +64,11 @@ class ProofOfWorkService : Service() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
data class PowItem(val initialHash: ByteArray, val targetValue: ByteArray, val callback: ProofOfWorkEngine.Callback) {
|
data class PowItem(
|
||||||
|
val initialHash: ByteArray,
|
||||||
|
val targetValue: ByteArray,
|
||||||
|
val callback: ProofOfWorkEngine.Callback
|
||||||
|
) {
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
if (this === other) return true
|
if (this === other) return true
|
||||||
if (javaClass != other?.javaClass) return false
|
if (javaClass != other?.javaClass) return false
|
||||||
@ -81,7 +91,10 @@ class ProofOfWorkService : Service() {
|
|||||||
private fun calculateNonce(item: PowItem) {
|
private fun calculateNonce(item: PowItem) {
|
||||||
notification.start(item)
|
notification.start(item)
|
||||||
val startTime = System.currentTimeMillis()
|
val startTime = System.currentTimeMillis()
|
||||||
engine.calculateNonce(item.initialHash, item.targetValue, object : ProofOfWorkEngine.Callback {
|
engine.calculateNonce(
|
||||||
|
item.initialHash,
|
||||||
|
item.targetValue,
|
||||||
|
object : ProofOfWorkEngine.Callback {
|
||||||
override fun onNonceCalculated(initialHash: ByteArray, nonce: ByteArray) {
|
override fun onNonceCalculated(initialHash: ByteArray, nonce: ByteArray) {
|
||||||
notification.finished()
|
notification.finished()
|
||||||
val time = System.currentTimeMillis() - startTime
|
val time = System.currentTimeMillis() - startTime
|
||||||
|
@ -50,6 +50,8 @@ object Singleton {
|
|||||||
private var swipeableMessageAdapter: WeakReference<SwipeableMessageAdapter>? = null
|
private var swipeableMessageAdapter: WeakReference<SwipeableMessageAdapter>? = null
|
||||||
val labeler = DefaultLabeler().apply {
|
val labeler = DefaultLabeler().apply {
|
||||||
listener = { message, added, removed ->
|
listener = { message, added, removed ->
|
||||||
|
MainActivity.apply {
|
||||||
|
runOnUiThread {
|
||||||
swipeableMessageAdapter?.get()?.let { swipeableMessageAdapter ->
|
swipeableMessageAdapter?.get()?.let { swipeableMessageAdapter ->
|
||||||
currentLabel.value?.let { label ->
|
currentLabel.value?.let { label ->
|
||||||
when {
|
when {
|
||||||
@ -78,8 +80,8 @@ object Singleton {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (removed.any { it.type == Label.Type.UNREAD } || added.any { it.type == Label.Type.UNREAD }) {
|
if (removed.any { it.type == Label.Type.UNREAD } || added.any { it.type == Label.Type.UNREAD }) {
|
||||||
MainActivity.apply {
|
|
||||||
updateUnread()
|
updateUnread()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ import android.app.job.JobService
|
|||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.support.annotation.RequiresApi
|
import android.support.annotation.RequiresApi
|
||||||
|
import ch.dissem.apps.abit.util.NetworkUtils
|
||||||
import ch.dissem.apps.abit.util.Preferences
|
import ch.dissem.apps.abit.util.Preferences
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -19,7 +20,7 @@ class StartupNodeOnWifiService : JobService() {
|
|||||||
override fun onStartJob(params: JobParameters?): Boolean {
|
override fun onStartJob(params: JobParameters?): Boolean {
|
||||||
val bmc = Singleton.getBitmessageContext(this)
|
val bmc = Singleton.getBitmessageContext(this)
|
||||||
if (Preferences.isFullNodeActive(this) && !bmc.isRunning()) {
|
if (Preferences.isFullNodeActive(this) && !bmc.isRunning()) {
|
||||||
applicationContext.startService(Intent(this, BitmessageService::class.java))
|
NetworkUtils.doStartBitmessageService(applicationContext)
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ import android.content.Context
|
|||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.support.annotation.RequiresApi
|
import android.support.annotation.RequiresApi
|
||||||
|
import android.support.v4.content.ContextCompat
|
||||||
import ch.dissem.apps.abit.MainActivity
|
import ch.dissem.apps.abit.MainActivity
|
||||||
import ch.dissem.apps.abit.dialog.FullNodeDialogActivity
|
import ch.dissem.apps.abit.dialog.FullNodeDialogActivity
|
||||||
import ch.dissem.apps.abit.service.BitmessageService
|
import ch.dissem.apps.abit.service.BitmessageService
|
||||||
@ -23,7 +24,7 @@ object NetworkUtils {
|
|||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||||
scheduleNodeStart(ctx)
|
scheduleNodeStart(ctx)
|
||||||
} else {
|
} else {
|
||||||
ctx.startService(Intent(ctx, BitmessageService::class.java))
|
doStartBitmessageService(ctx)
|
||||||
MainActivity.updateNodeSwitch()
|
MainActivity.updateNodeSwitch()
|
||||||
}
|
}
|
||||||
} else if (ask) {
|
} else if (ask) {
|
||||||
@ -37,11 +38,15 @@ object NetworkUtils {
|
|||||||
scheduleNodeStart(ctx)
|
scheduleNodeStart(ctx)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ctx.startService(Intent(ctx, BitmessageService::class.java))
|
doStartBitmessageService(ctx)
|
||||||
MainActivity.updateNodeSwitch()
|
MainActivity.updateNodeSwitch()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun doStartBitmessageService(ctx: Context) {
|
||||||
|
ContextCompat.startForegroundService(ctx, Intent(ctx, BitmessageService::class.java))
|
||||||
|
}
|
||||||
|
|
||||||
fun disableNode(ctx: Context) {
|
fun disableNode(ctx: Context) {
|
||||||
Preferences.setFullNodeActive(ctx, false)
|
Preferences.setFullNodeActive(ctx, false)
|
||||||
ctx.stopService(Intent(ctx, BitmessageService::class.java))
|
ctx.stopService(Intent(ctx, BitmessageService::class.java))
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
buildscript {
|
buildscript {
|
||||||
ext.kotlin_version = '1.2.10'
|
ext.kotlin_version = '1.2.20'
|
||||||
ext.anko_version = '0.10.4'
|
ext.anko_version = '0.10.4'
|
||||||
repositories {
|
repositories {
|
||||||
jcenter()
|
jcenter()
|
||||||
|
Reference in New Issue
Block a user