diff --git a/app/src/main/java/ch/dissem/apps/abit/notification/AbstractNotification.java b/app/src/main/java/ch/dissem/apps/abit/notification/AbstractNotification.java
deleted file mode 100644
index 7573dc9..0000000
--- a/app/src/main/java/ch/dissem/apps/abit/notification/AbstractNotification.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright 2016 Christian Basler
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package ch.dissem.apps.abit.notification;
-
-import android.app.Notification;
-import android.app.NotificationManager;
-import android.content.Context;
-
-/**
- * Some base class to create and handle notifications.
- */
-public abstract class AbstractNotification {
- protected final Context ctx;
- protected final NotificationManager manager;
- protected Notification notification;
-
-
- public AbstractNotification(Context ctx) {
- this.ctx = ctx.getApplicationContext();
- this.manager = (NotificationManager) ctx.getSystemService(Context.NOTIFICATION_SERVICE);
- }
-
- /**
- * @return an id unique to this notification class
- */
- protected abstract int getNotificationId();
-
- public Notification getNotification() {
- return notification;
- }
-
- public void show() {
- manager.notify(getNotificationId(), notification);
- }
-
- public void hide() {
- manager.cancel(getNotificationId());
- }
-}
diff --git a/app/src/main/java/ch/dissem/apps/abit/notification/AbstractNotification.kt b/app/src/main/java/ch/dissem/apps/abit/notification/AbstractNotification.kt
new file mode 100644
index 0000000..2da0e98
--- /dev/null
+++ b/app/src/main/java/ch/dissem/apps/abit/notification/AbstractNotification.kt
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2016 Christian Basler
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.dissem.apps.abit.notification
+
+import android.app.Notification
+import android.app.NotificationManager
+import android.content.Context
+
+/**
+ * Some base class to create and handle notifications.
+ */
+abstract class AbstractNotification(ctx: Context) {
+ protected val ctx = ctx.applicationContext
+ protected val manager = ctx.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
+ var notification: Notification? = null
+ protected set
+ protected var showing = false
+ private set
+
+ /**
+ * @return an id unique to this notification class
+ */
+ protected abstract val notificationId: Int
+
+ open fun show() {
+ manager.notify(notificationId, notification)
+ showing = true
+ }
+
+ fun hide() {
+ showing = false
+ manager.cancel(notificationId)
+ }
+}
diff --git a/app/src/main/java/ch/dissem/apps/abit/notification/ErrorNotification.java b/app/src/main/java/ch/dissem/apps/abit/notification/ErrorNotification.java
deleted file mode 100644
index e7a0654..0000000
--- a/app/src/main/java/ch/dissem/apps/abit/notification/ErrorNotification.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright 2016 Christian Basler
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package ch.dissem.apps.abit.notification;
-
-import android.content.Context;
-import android.support.annotation.StringRes;
-import android.support.v7.app.NotificationCompat;
-
-import ch.dissem.apps.abit.R;
-
-/**
- * Easily create notifications with error messages. Use carefully, users probably won't like them.
- * (But they are useful during development/testing)
- *
- * @author Christian Basler
- */
-public class ErrorNotification extends AbstractNotification {
- public static final int ERROR_NOTIFICATION_ID = 4;
-
- private final NotificationCompat.Builder builder;
-
- public ErrorNotification(Context ctx) {
- super(ctx);
- builder = new NotificationCompat.Builder(ctx);
- builder.setContentTitle(ctx.getString(R.string.app_name))
- .setVisibility(NotificationCompat.VISIBILITY_PUBLIC);
- }
-
- public ErrorNotification setWarning(@StringRes int resId, Object... args) {
- builder.setSmallIcon(R.drawable.ic_notification_warning)
- .setContentText(ctx.getString(resId, args));
- notification = builder.build();
- return this;
- }
-
- public ErrorNotification setError(@StringRes int resId, Object... args) {
- builder.setSmallIcon(R.drawable.ic_notification_error)
- .setContentText(ctx.getString(resId, args));
- notification = builder.build();
- return this;
- }
-
- @Override
- protected int getNotificationId() {
- return ERROR_NOTIFICATION_ID;
- }
-}
diff --git a/app/src/main/java/ch/dissem/apps/abit/notification/ErrorNotification.kt b/app/src/main/java/ch/dissem/apps/abit/notification/ErrorNotification.kt
new file mode 100644
index 0000000..a652cfe
--- /dev/null
+++ b/app/src/main/java/ch/dissem/apps/abit/notification/ErrorNotification.kt
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2016 Christian Basler
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.dissem.apps.abit.notification
+
+import android.content.Context
+import android.support.annotation.StringRes
+import android.support.v7.app.NotificationCompat
+
+import ch.dissem.apps.abit.R
+
+/**
+ * Easily create notifications with error messages. Use carefully, users probably won't like them.
+ * (But they are useful during development/testing)
+
+ * @author Christian Basler
+ */
+class ErrorNotification(ctx: Context) : AbstractNotification(ctx) {
+
+ private val builder = NotificationCompat.Builder(ctx)
+ .setContentTitle(ctx.getString(R.string.app_name))
+ .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
+
+ fun setWarning(@StringRes resId: Int, vararg args: Any): ErrorNotification {
+ builder.setSmallIcon(R.drawable.ic_notification_warning)
+ .setContentText(ctx.getString(resId, *args))
+ notification = builder.build()
+ return this
+ }
+
+ fun setError(@StringRes resId: Int, vararg args: Any): ErrorNotification {
+ builder.setSmallIcon(R.drawable.ic_notification_error)
+ .setContentText(ctx.getString(resId, *args))
+ notification = builder.build()
+ return this
+ }
+
+ override val notificationId = ERROR_NOTIFICATION_ID
+
+ companion object {
+ val ERROR_NOTIFICATION_ID = 4
+ }
+}
diff --git a/app/src/main/java/ch/dissem/apps/abit/notification/NetworkNotification.java b/app/src/main/java/ch/dissem/apps/abit/notification/NetworkNotification.java
deleted file mode 100644
index 2bce79b..0000000
--- a/app/src/main/java/ch/dissem/apps/abit/notification/NetworkNotification.java
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * Copyright 2016 Christian Basler
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package ch.dissem.apps.abit.notification;
-
-import android.annotation.SuppressLint;
-import android.app.PendingIntent;
-import android.content.Context;
-import android.content.Intent;
-import android.support.v7.app.NotificationCompat;
-
-import java.util.Timer;
-import java.util.TimerTask;
-
-import ch.dissem.apps.abit.MainActivity;
-import ch.dissem.apps.abit.R;
-import ch.dissem.apps.abit.service.BitmessageIntentService;
-import ch.dissem.apps.abit.service.BitmessageService;
-import ch.dissem.bitmessage.utils.Property;
-
-import static android.app.PendingIntent.FLAG_UPDATE_CURRENT;
-
-/**
- * Shows the network status (as long as the client is connected as a full node)
- */
-public class NetworkNotification extends AbstractNotification {
- public static final int NETWORK_NOTIFICATION_ID = 2;
-
- private final NotificationCompat.Builder builder;
- private Timer timer;
-
- public NetworkNotification(Context ctx) {
- super(ctx);
- Intent showAppIntent = new Intent(ctx, MainActivity.class);
- PendingIntent pendingIntent = PendingIntent.getActivity(ctx, 1, showAppIntent, 0);
- builder = new NotificationCompat.Builder(ctx);
- builder.setSmallIcon(R.drawable.ic_notification_full_node)
- .setContentTitle(ctx.getString(R.string.bitmessage_full_node))
- .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
- .setShowWhen(false)
- .setContentIntent(pendingIntent);
- }
-
- @SuppressLint("StringFormatMatches")
- @SuppressWarnings("BooleanMethodIsAlwaysInverted")
- private boolean update() {
- boolean running = BitmessageService.isRunning();
- builder.setOngoing(running);
- Property connections = BitmessageService.getStatus().getProperty("network", "connections");
- if (!running) {
- builder.setContentText(ctx.getString(R.string.connection_info_disconnected));
- } else if (connections.getProperties().length == 0) {
- builder.setContentText(ctx.getString(R.string.connection_info_pending));
- } else {
- StringBuilder info = new StringBuilder();
- for (Property stream : connections.getProperties()) {
- int streamNumber = Integer.parseInt(stream.getName().substring("stream ".length()));
- Integer nodeCount = (Integer) stream.getProperty("nodes").getValue();
- if (nodeCount == 1) {
- info.append(ctx.getString(R.string.connection_info_1,
- streamNumber));
- } else {
- info.append(ctx.getString(R.string.connection_info_n,
- streamNumber, nodeCount));
- }
- info.append('\n');
- }
- builder.setContentText(info);
- }
- builder.mActions.clear();
- Intent intent = new Intent(ctx, BitmessageIntentService.class);
- if (running) {
- intent.putExtra(BitmessageIntentService.EXTRA_SHUTDOWN_NODE, true);
- builder.addAction(R.drawable.ic_notification_node_stop,
- ctx.getString(R.string.full_node_stop),
- PendingIntent.getService(ctx, 0, intent, FLAG_UPDATE_CURRENT));
- } else {
- intent.putExtra(BitmessageIntentService.EXTRA_STARTUP_NODE, true);
- builder.addAction(R.drawable.ic_notification_node_start,
- ctx.getString(R.string.full_node_restart),
- PendingIntent.getService(ctx, 1, intent, FLAG_UPDATE_CURRENT));
- }
- notification = builder.build();
- return running;
- }
-
- @Override
- public void show() {
- super.show();
-
- timer = new Timer();
- timer.schedule(new TimerTask() {
- @Override
- public void run() {
- if (!update()) {
- cancel();
- ctx.stopService(new Intent(ctx, BitmessageService.class));
- }
- NetworkNotification.super.show();
- }
- }, 10_000, 10_000);
- }
-
- public void showShutdown() {
- if (timer != null) {
- timer.cancel();
- }
- update();
- super.show();
- }
-
- @Override
- protected int getNotificationId() {
- return NETWORK_NOTIFICATION_ID;
- }
-
- public void connecting() {
- builder.setOngoing(true);
- builder.setContentText(ctx.getString(R.string.connection_info_pending));
- Intent intent = new Intent(ctx, BitmessageIntentService.class);
- intent.putExtra(BitmessageIntentService.EXTRA_SHUTDOWN_NODE, true);
- builder.mActions.clear();
- builder.addAction(R.drawable.ic_notification_node_stop,
- ctx.getString(R.string.full_node_stop),
- PendingIntent.getService(ctx, 0, intent, FLAG_UPDATE_CURRENT));
- notification = builder.build();
- }
-}
diff --git a/app/src/main/java/ch/dissem/apps/abit/notification/NetworkNotification.kt b/app/src/main/java/ch/dissem/apps/abit/notification/NetworkNotification.kt
new file mode 100644
index 0000000..0e268a7
--- /dev/null
+++ b/app/src/main/java/ch/dissem/apps/abit/notification/NetworkNotification.kt
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2016 Christian Basler
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.dissem.apps.abit.notification
+
+import android.annotation.SuppressLint
+import android.app.PendingIntent
+import android.app.PendingIntent.FLAG_UPDATE_CURRENT
+import android.content.Context
+import android.content.Intent
+import android.support.v7.app.NotificationCompat
+import ch.dissem.apps.abit.MainActivity
+import ch.dissem.apps.abit.R
+import ch.dissem.apps.abit.service.BitmessageIntentService
+import ch.dissem.apps.abit.service.BitmessageService
+import java.util.*
+import kotlin.concurrent.fixedRateTimer
+
+/**
+ * Shows the network status (as long as the client is connected as a full node)
+ */
+class NetworkNotification(ctx: Context) : AbstractNotification(ctx) {
+
+ private val builder = NotificationCompat.Builder(ctx)
+ private var timer: Timer? = null
+
+ init {
+ val showAppIntent = Intent(ctx, MainActivity::class.java)
+ val pendingIntent = PendingIntent.getActivity(ctx, 1, showAppIntent, 0)
+ builder
+ .setSmallIcon(R.drawable.ic_notification_full_node)
+ .setContentTitle(ctx.getString(R.string.bitmessage_full_node))
+ .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
+ .setShowWhen(false)
+ .setContentIntent(pendingIntent)
+ }
+
+ @SuppressLint("StringFormatMatches")
+ private fun update(): Boolean {
+ val running = BitmessageService.isRunning
+ builder.setOngoing(running)
+ val connections = BitmessageService.status.getProperty("network", "connections")
+ if (!running) {
+ builder.setContentText(ctx.getString(R.string.connection_info_disconnected))
+ } else if (connections!!.properties.isEmpty()) {
+ builder.setContentText(ctx.getString(R.string.connection_info_pending))
+ } else {
+ val info = StringBuilder()
+ for (stream in connections.properties) {
+ val streamNumber = Integer.parseInt(stream.name.substring("stream ".length))
+ val nodeCount = stream.getProperty("nodes")!!.value as Int?
+ if (nodeCount == 1) {
+ info.append(ctx.getString(R.string.connection_info_1,
+ streamNumber))
+ } else {
+ info.append(ctx.getString(R.string.connection_info_n,
+ streamNumber, nodeCount))
+ }
+ info.append('\n')
+ }
+ builder.setContentText(info)
+ }
+ builder.mActions.clear()
+ val intent = Intent(ctx, BitmessageIntentService::class.java)
+ if (running) {
+ intent.putExtra(BitmessageIntentService.EXTRA_SHUTDOWN_NODE, true)
+ builder.addAction(R.drawable.ic_notification_node_stop,
+ ctx.getString(R.string.full_node_stop),
+ PendingIntent.getService(ctx, 0, intent, FLAG_UPDATE_CURRENT))
+ } else {
+ intent.putExtra(BitmessageIntentService.EXTRA_STARTUP_NODE, true)
+ builder.addAction(R.drawable.ic_notification_node_start,
+ ctx.getString(R.string.full_node_restart),
+ PendingIntent.getService(ctx, 1, intent, FLAG_UPDATE_CURRENT))
+ }
+ notification = builder.build()
+ return running
+ }
+
+ override fun show() {
+ super.show()
+
+ timer = fixedRateTimer(initialDelay = 10000, period = 10000) {
+ if (!update()) {
+ cancel()
+ ctx.stopService(Intent(ctx, BitmessageService::class.java))
+ }
+ super@NetworkNotification.show()
+ }
+ }
+
+ fun showShutdown() {
+ timer?.cancel()
+ update()
+ super.show()
+ }
+
+ override val notificationId = NETWORK_NOTIFICATION_ID
+
+ fun connecting() {
+ builder.setOngoing(true)
+ builder.setContentText(ctx.getString(R.string.connection_info_pending))
+ val intent = Intent(ctx, BitmessageIntentService::class.java)
+ intent.putExtra(BitmessageIntentService.EXTRA_SHUTDOWN_NODE, true)
+ builder.mActions.clear()
+ builder.addAction(R.drawable.ic_notification_node_stop,
+ ctx.getString(R.string.full_node_stop),
+ PendingIntent.getService(ctx, 0, intent, FLAG_UPDATE_CURRENT))
+ notification = builder.build()
+ }
+
+ companion object {
+ val NETWORK_NOTIFICATION_ID = 2
+ }
+}
diff --git a/app/src/main/java/ch/dissem/apps/abit/notification/NewMessageNotification.java b/app/src/main/java/ch/dissem/apps/abit/notification/NewMessageNotification.java
deleted file mode 100644
index 3bddc2e..0000000
--- a/app/src/main/java/ch/dissem/apps/abit/notification/NewMessageNotification.java
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright 2016 Christian Basler
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package ch.dissem.apps.abit.notification;
-
-import android.app.PendingIntent;
-import android.content.Context;
-import android.content.Intent;
-import android.graphics.Typeface;
-import android.support.v7.app.NotificationCompat;
-import android.text.Spannable;
-import android.text.SpannableString;
-import android.text.Spanned;
-import android.text.style.StyleSpan;
-
-import java.util.Collection;
-
-import ch.dissem.apps.abit.Identicon;
-import ch.dissem.apps.abit.MainActivity;
-import ch.dissem.apps.abit.R;
-import ch.dissem.apps.abit.service.BitmessageIntentService;
-import ch.dissem.bitmessage.entity.Plaintext;
-
-import static android.app.PendingIntent.FLAG_UPDATE_CURRENT;
-import static ch.dissem.apps.abit.MainActivity.EXTRA_REPLY_TO_MESSAGE;
-import static ch.dissem.apps.abit.MainActivity.EXTRA_SHOW_MESSAGE;
-import static ch.dissem.apps.abit.service.BitmessageIntentService.EXTRA_DELETE_MESSAGE;
-import static ch.dissem.apps.abit.util.Drawables.toBitmap;
-
-public class NewMessageNotification extends AbstractNotification {
- private static final int NEW_MESSAGE_NOTIFICATION_ID = 1;
- private static final StyleSpan SPAN_EMPHASIS = new StyleSpan(Typeface.BOLD);
-
- public NewMessageNotification(Context ctx) {
- super(ctx);
- }
-
- public NewMessageNotification singleNotification(Plaintext plaintext) {
- NotificationCompat.Builder builder = new NotificationCompat.Builder(ctx);
- Spannable bigText = new SpannableString(plaintext.getSubject() + "\n" + plaintext.getText
- ());
- bigText.setSpan(SPAN_EMPHASIS, 0, plaintext.getSubject().length(), Spanned
- .SPAN_INCLUSIVE_EXCLUSIVE);
- builder.setSmallIcon(R.drawable.ic_notification_new_message)
- .setLargeIcon(toBitmap(new Identicon(plaintext.getFrom()), 192))
- .setContentTitle(plaintext.getFrom().toString())
- .setContentText(plaintext.getSubject())
- .setStyle(new NotificationCompat.BigTextStyle().bigText(bigText))
- .setContentInfo("Info");
-
- builder.setContentIntent(
- 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(R.drawable.ic_action_delete, ctx.getString(R.string.delete),
- createServiceIntent(ctx, EXTRA_DELETE_MESSAGE, plaintext));
- notification = builder.build();
- return this;
- }
-
- private PendingIntent createActivityIntent(String action, Plaintext message) {
- Intent intent = new Intent(ctx, MainActivity.class);
- intent.putExtra(action, message);
- return PendingIntent.getActivity(ctx, action.hashCode(), intent, FLAG_UPDATE_CURRENT);
- }
-
- private PendingIntent createServiceIntent(Context ctx, String action, Plaintext message) {
- Intent intent = new Intent(ctx, BitmessageIntentService.class);
- intent.putExtra(action, message);
- return PendingIntent.getService(ctx, action.hashCode(), intent, FLAG_UPDATE_CURRENT);
- }
-
- /**
- * @param unacknowledged will be accessed from different threads, so make sure wherever it's
- * accessed it will be in a synchronized(unacknowledged)
- * {}
block
- */
- public NewMessageNotification multiNotification(Collection unacknowledged, int
- numberOfUnacknowledgedMessages) {
- NotificationCompat.Builder builder = new NotificationCompat.Builder(ctx);
- builder.setSmallIcon(R.drawable.ic_notification_new_message)
- .setContentTitle(ctx.getString(R.string.n_new_messages, numberOfUnacknowledgedMessages))
- .setContentText(ctx.getString(R.string.app_name));
-
- NotificationCompat.InboxStyle inboxStyle = new NotificationCompat.InboxStyle();
- //noinspection SynchronizationOnLocalVariableOrMethodParameter
- synchronized (unacknowledged) {
- for (Plaintext msg : unacknowledged) {
- Spannable sb = new SpannableString(msg.getFrom() + " " + msg.getSubject());
- sb.setSpan(SPAN_EMPHASIS, 0, String.valueOf(msg.getFrom()).length(), Spannable
- .SPAN_INCLUSIVE_EXCLUSIVE);
- inboxStyle.addLine(sb);
- }
- }
- builder.setStyle(inboxStyle);
-
- Intent intent = new Intent(ctx, MainActivity.class);
- intent.setAction(MainActivity.ACTION_SHOW_INBOX);
- PendingIntent pendingIntent = PendingIntent.getActivity(ctx, 1, intent, 0);
- builder.setContentIntent(pendingIntent);
- notification = builder.build();
- return this;
- }
-
- @Override
- protected int getNotificationId() {
- return NEW_MESSAGE_NOTIFICATION_ID;
- }
-}
diff --git a/app/src/main/java/ch/dissem/apps/abit/notification/NewMessageNotification.kt b/app/src/main/java/ch/dissem/apps/abit/notification/NewMessageNotification.kt
new file mode 100644
index 0000000..c603684
--- /dev/null
+++ b/app/src/main/java/ch/dissem/apps/abit/notification/NewMessageNotification.kt
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2016 Christian Basler
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.dissem.apps.abit.notification
+
+import android.app.PendingIntent
+import android.content.Context
+import android.content.Intent
+import android.graphics.Typeface
+import android.support.v7.app.NotificationCompat
+import android.support.v4.app.NotificationCompat.BigTextStyle
+import android.support.v4.app.NotificationCompat.InboxStyle
+import android.text.Spannable
+import android.text.SpannableString
+import android.text.Spanned
+import android.text.style.StyleSpan
+
+import ch.dissem.apps.abit.Identicon
+import ch.dissem.apps.abit.MainActivity
+import ch.dissem.apps.abit.R
+import ch.dissem.apps.abit.service.BitmessageIntentService
+import ch.dissem.bitmessage.entity.Plaintext
+
+import android.app.PendingIntent.FLAG_UPDATE_CURRENT
+import ch.dissem.apps.abit.MainActivity.EXTRA_REPLY_TO_MESSAGE
+import ch.dissem.apps.abit.MainActivity.EXTRA_SHOW_MESSAGE
+import ch.dissem.apps.abit.service.BitmessageIntentService.EXTRA_DELETE_MESSAGE
+import ch.dissem.apps.abit.util.Drawables.toBitmap
+
+class NewMessageNotification(ctx: Context) : AbstractNotification(ctx) {
+
+ fun singleNotification(plaintext: Plaintext): NewMessageNotification {
+ val builder = NotificationCompat.Builder(ctx)
+ val bigText = SpannableString(plaintext.subject + "\n" + plaintext.text)
+ bigText.setSpan(SPAN_EMPHASIS, 0, plaintext.subject!!.length, Spanned
+ .SPAN_INCLUSIVE_EXCLUSIVE)
+ builder.setSmallIcon(R.drawable.ic_notification_new_message)
+ .setLargeIcon(toBitmap(Identicon(plaintext.from), 192))
+ .setContentTitle(plaintext.from.toString())
+ .setContentText(plaintext.subject)
+ .setStyle(BigTextStyle().bigText(bigText))
+ .setContentInfo("Info")
+
+ builder.setContentIntent(
+ 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(R.drawable.ic_action_delete, ctx.getString(R.string.delete),
+ createServiceIntent(ctx, EXTRA_DELETE_MESSAGE, plaintext))
+ notification = builder.build()
+ return this
+ }
+
+ private fun createActivityIntent(action: String, message: Plaintext): PendingIntent {
+ val intent = Intent(ctx, MainActivity::class.java)
+ intent.putExtra(action, message)
+ return PendingIntent.getActivity(ctx, action.hashCode(), intent, FLAG_UPDATE_CURRENT)
+ }
+
+ private fun createServiceIntent(ctx: Context, action: String, message: Plaintext): PendingIntent {
+ val intent = Intent(ctx, BitmessageIntentService::class.java)
+ intent.putExtra(action, message)
+ return PendingIntent.getService(ctx, action.hashCode(), intent, FLAG_UPDATE_CURRENT)
+ }
+
+ /**
+ * @param unacknowledged will be accessed from different threads, so make sure wherever it's
+ * * accessed it will be in a `synchronized(unacknowledged)
+ * * {}` block
+ */
+ fun multiNotification(unacknowledged: Collection, numberOfUnacknowledgedMessages: Int): NewMessageNotification {
+ val builder = NotificationCompat.Builder(ctx)
+ builder.setSmallIcon(R.drawable.ic_notification_new_message)
+ .setContentTitle(ctx.getString(R.string.n_new_messages, numberOfUnacknowledgedMessages))
+ .setContentText(ctx.getString(R.string.app_name))
+
+ val inboxStyle = InboxStyle()
+
+ synchronized(unacknowledged) {
+ for (msg in unacknowledged) {
+ val sb = SpannableString(msg.from.toString() + " " + msg.subject)
+ sb.setSpan(SPAN_EMPHASIS, 0, msg.from.toString().length, Spannable
+ .SPAN_INCLUSIVE_EXCLUSIVE)
+ inboxStyle.addLine(sb)
+ }
+ }
+ builder.setStyle(inboxStyle)
+
+ val intent = Intent(ctx, MainActivity::class.java)
+ intent.action = MainActivity.ACTION_SHOW_INBOX
+ val pendingIntent = PendingIntent.getActivity(ctx, 1, intent, 0)
+ builder.setContentIntent(pendingIntent)
+ notification = builder.build()
+ return this
+ }
+
+ override val notificationId = NEW_MESSAGE_NOTIFICATION_ID
+
+ companion object {
+ private val NEW_MESSAGE_NOTIFICATION_ID = 1
+ private val SPAN_EMPHASIS = StyleSpan(Typeface.BOLD)
+ }
+}
diff --git a/app/src/main/java/ch/dissem/apps/abit/notification/ProofOfWorkNotification.kt b/app/src/main/java/ch/dissem/apps/abit/notification/ProofOfWorkNotification.kt
index 5076097..e2190ec 100644
--- a/app/src/main/java/ch/dissem/apps/abit/notification/ProofOfWorkNotification.kt
+++ b/app/src/main/java/ch/dissem/apps/abit/notification/ProofOfWorkNotification.kt
@@ -23,36 +23,44 @@ import android.support.v7.app.NotificationCompat
import ch.dissem.apps.abit.MainActivity
import ch.dissem.apps.abit.R
+import ch.dissem.apps.abit.service.ProofOfWorkService
+import ch.dissem.apps.abit.util.PowStats
+import java.util.*
+import kotlin.concurrent.fixedRateTimer
/**
* Ongoing notification while proof of work is in progress.
*/
class ProofOfWorkNotification(ctx: Context) : AbstractNotification(ctx) {
+ private val builder = NotificationCompat.Builder(ctx)
+ .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
+ .setUsesChronometer(true)
+ .setOngoing(true)
+ .setSmallIcon(R.drawable.ic_notification_proof_of_work)
+ .setContentTitle(ctx.getString(R.string.proof_of_work_title))
+ private var startTime = 0L
+ private var progress = 0
+ private var progressMax = 0
+
+ private var timer: Timer? = null
+
init {
update(0)
}
- override fun getNotificationId(): Int {
- return ONGOING_NOTIFICATION_ID
- }
+ override val notificationId = ONGOING_NOTIFICATION_ID
fun update(numberOfItems: Int): ProofOfWorkNotification {
- val builder = NotificationCompat.Builder(ctx)
val showMessageIntent = Intent(ctx, MainActivity::class.java)
val pendingIntent = PendingIntent.getActivity(ctx, 0, showMessageIntent,
PendingIntent.FLAG_UPDATE_CURRENT)
- builder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
- .setUsesChronometer(true)
- .setOngoing(true)
- .setSmallIcon(R.drawable.ic_notification_proof_of_work)
- .setContentTitle(ctx.getString(R.string.proof_of_work_title))
- .setContentText(if (numberOfItems == 0)
- ctx.getString(R.string.proof_of_work_text_0)
- else
- ctx.getString(R.string.proof_of_work_text_n, numberOfItems))
+ builder.setContentText(if (numberOfItems == 0)
+ ctx.getString(R.string.proof_of_work_text_0)
+ else
+ ctx.getString(R.string.proof_of_work_text_n, numberOfItems))
.setContentIntent(pendingIntent)
notification = builder.build()
@@ -62,4 +70,35 @@ class ProofOfWorkNotification(ctx: Context) : AbstractNotification(ctx) {
companion object {
@JvmField val ONGOING_NOTIFICATION_ID = 3
}
+
+ fun start(item: ProofOfWorkService.PowItem) {
+ val expectedPowTimeInMilliseconds = PowStats.getExpectedPowTimeInMilliseconds(ctx, item.targetValue)
+ val delta = (expectedPowTimeInMilliseconds / 2).toInt()
+ startTime = System.currentTimeMillis()
+ progress = 0
+ progressMax = delta
+ builder.setProgress(progressMax, progress, false)
+ notification = builder.build()
+ show()
+
+ timer = fixedRateTimer(initialDelay = 5000, period = 5000){
+ val elapsedTime = System.currentTimeMillis() - startTime
+ progress = elapsedTime.toInt()
+ progressMax = progress + delta
+ builder.setProgress(progressMax, progress, false)
+ notification = builder.build()
+ show()
+ }
+ }
+
+ fun finished(item: ProofOfWorkService.PowItem) {
+ timer?.cancel()
+ progress = 0
+ progressMax = 0
+ if (showing) {
+ builder.setProgress(0, 0, false)
+ notification = builder.build()
+ show()
+ }
+ }
}
diff --git a/app/src/main/java/ch/dissem/apps/abit/service/BitmessageService.kt b/app/src/main/java/ch/dissem/apps/abit/service/BitmessageService.kt
index 5bd0339..3058152 100644
--- a/app/src/main/java/ch/dissem/apps/abit/service/BitmessageService.kt
+++ b/app/src/main/java/ch/dissem/apps/abit/service/BitmessageService.kt
@@ -20,7 +20,7 @@ import android.app.Service
import android.content.Intent
import android.os.Handler
import ch.dissem.apps.abit.notification.NetworkNotification
-import ch.dissem.apps.abit.notification.NetworkNotification.NETWORK_NOTIFICATION_ID
+import ch.dissem.apps.abit.notification.NetworkNotification.Companion.NETWORK_NOTIFICATION_ID
import ch.dissem.bitmessage.BitmessageContext
import ch.dissem.bitmessage.utils.Property
diff --git a/app/src/main/java/ch/dissem/apps/abit/service/ProofOfWorkService.kt b/app/src/main/java/ch/dissem/apps/abit/service/ProofOfWorkService.kt
index 0f3f6c5..443e59c 100644
--- a/app/src/main/java/ch/dissem/apps/abit/service/ProofOfWorkService.kt
+++ b/app/src/main/java/ch/dissem/apps/abit/service/ProofOfWorkService.kt
@@ -69,9 +69,11 @@ class ProofOfWorkService : Service() {
data class PowItem(val initialHash: ByteArray, val targetValue: ByteArray, val callback: ProofOfWorkEngine.Callback)
private fun calculateNonce(item: PowItem) {
+ notification.start(item)
val startTime = System.currentTimeMillis()
engine.calculateNonce(item.initialHash, item.targetValue, object : ProofOfWorkEngine.Callback {
override fun onNonceCalculated(initialHash: ByteArray, nonce: ByteArray) {
+ notification.finished(item)
val time = System.currentTimeMillis() - startTime
PowStats.addPow(this@ProofOfWorkService, time, item.targetValue)
try {
diff --git a/app/src/main/java/ch/dissem/apps/abit/util/PowStats.kt b/app/src/main/java/ch/dissem/apps/abit/util/PowStats.kt
index 25892d4..af9ec7f 100644
--- a/app/src/main/java/ch/dissem/apps/abit/util/PowStats.kt
+++ b/app/src/main/java/ch/dissem/apps/abit/util/PowStats.kt
@@ -1,31 +1,47 @@
package ch.dissem.apps.abit.util
import android.content.Context
+import android.preference.PreferenceManager
+import ch.dissem.apps.abit.util.Constants.PREFERENCE_POW_AVERAGE
+import ch.dissem.apps.abit.util.Constants.PREFERENCE_POW_COUNT
+import java.math.BigInteger
/**
- * Created by chrigu on 02.08.17.
+ * POW statistics that might help estimate the POW time, depending on
*/
object PowStats {
- var powUnitTime: Long = 0
- var powCount: Long = 0
+ private val TWO_POW_64 = BigInteger.valueOf(2).pow(64)!!
+
+ var averagePowUnitTime = 0L
+ var powCount = 0L
@JvmStatic
- fun getExpectedPowTime(ctx: Context, target: ByteArray): Long {
-// val preferences = PreferenceManager.getDefaultSharedPreferences(ctx)
-// return preferences.getLong(Constants.PREFERENCE_POW_AVERAGE, 0L)
- return 0
+ fun getExpectedPowTimeInMilliseconds(ctx: Context, target: ByteArray): Long {
+ if (averagePowUnitTime == 0L) {
+ val preferences = PreferenceManager.getDefaultSharedPreferences(ctx)
+ synchronized(this) {
+ averagePowUnitTime = preferences.getLong(PREFERENCE_POW_AVERAGE, 0L)
+ powCount = preferences.getLong(PREFERENCE_POW_COUNT, 0L)
+ }
+ }
+ return (BigInteger.valueOf(averagePowUnitTime) * BigInteger(target) / TWO_POW_64).toLong()
}
-// fun updatePowTelemetry(ctx: Context, averagePowTime: Long, powCount: Long) {
-// val preferences = PreferenceManager.getDefaultSharedPreferences(ctx)
-// preferences.edit()
-// .putLong(Constants.PREFERENCE_POW_AVERAGE, averagePowTime)
-// .putLong(Constants.PREFERENCE_POW_COUNT, powCount)
-// .apply()
-// }
-
@JvmStatic
fun addPow(ctx: Context, time: Long, target: ByteArray) {
- powCount++
+ val targetBigInt = BigInteger(target)
+ val powCountBefore = BigInteger.valueOf(powCount)
+ synchronized(this) {
+ powCount++
+ averagePowUnitTime = (
+ (BigInteger.valueOf(averagePowUnitTime) * powCountBefore + (BigInteger.valueOf(time) * TWO_POW_64 / targetBigInt)) / BigInteger.valueOf(powCount)
+ ).toLong()
+
+ val preferences = PreferenceManager.getDefaultSharedPreferences(ctx)
+ preferences.edit()
+ .putLong(PREFERENCE_POW_AVERAGE, averagePowUnitTime)
+ .putLong(PREFERENCE_POW_COUNT, powCount)
+ .apply()
+ }
}
}