Added a service based POW engine, so it shouldn't be killed by the system, at least not that easily. (WIP)
This commit is contained in:
		| @@ -102,7 +102,8 @@ | ||||
|                 <category android:name="android.intent.category.BROWSABLE" /> | ||||
|             </intent-filter> | ||||
|         </activity> | ||||
|         <service android:name=".synchronization.BitmessageService" /> | ||||
|         <service android:name=".service.BitmessageService" /> | ||||
|         <service android:name=".service.ProofOfWorkService" /> | ||||
|  | ||||
|         <!-- Synchronization --> | ||||
|         <provider | ||||
|   | ||||
| @@ -40,22 +40,23 @@ import org.slf4j.Logger; | ||||
| import org.slf4j.LoggerFactory; | ||||
|  | ||||
| import java.io.Serializable; | ||||
| import java.lang.ref.WeakReference; | ||||
| import java.util.ArrayList; | ||||
|  | ||||
| import ch.dissem.apps.abit.listener.ActionBarListener; | ||||
| import ch.dissem.apps.abit.listener.ListSelectionListener; | ||||
| import ch.dissem.apps.abit.service.BitmessageService; | ||||
| import ch.dissem.apps.abit.service.Singleton; | ||||
| import ch.dissem.apps.abit.synchronization.Authenticator; | ||||
| import ch.dissem.apps.abit.synchronization.BitmessageService; | ||||
| import ch.dissem.bitmessage.entity.BitmessageAddress; | ||||
| import ch.dissem.bitmessage.entity.Plaintext; | ||||
| import ch.dissem.bitmessage.entity.valueobject.Label; | ||||
| import ch.dissem.bitmessage.ports.AddressRepository; | ||||
| import ch.dissem.bitmessage.ports.MessageRepository; | ||||
|  | ||||
| import static ch.dissem.apps.abit.synchronization.BitmessageService.DATA_FIELD_IDENTITY; | ||||
| import static ch.dissem.apps.abit.synchronization.BitmessageService.MSG_START_NODE; | ||||
| import static ch.dissem.apps.abit.synchronization.BitmessageService.MSG_STOP_NODE; | ||||
| import static ch.dissem.apps.abit.service.BitmessageService.DATA_FIELD_IDENTITY; | ||||
| import static ch.dissem.apps.abit.service.BitmessageService.MSG_START_NODE; | ||||
| import static ch.dissem.apps.abit.service.BitmessageService.MSG_STOP_NODE; | ||||
| import static ch.dissem.apps.abit.synchronization.StubProvider.AUTHORITY; | ||||
|  | ||||
|  | ||||
| @@ -82,7 +83,7 @@ public class MessageListActivity extends AppCompatActivity | ||||
|     public static final String ACTION_SHOW_INBOX = "ch.dissem.abit.ShowInbox"; | ||||
|  | ||||
|     private static final Logger LOG = LoggerFactory.getLogger(MessageListActivity.class); | ||||
|     private static final long SYNC_FREQUENCY = 15;// FIXME * 60; // seconds | ||||
|     private static final long SYNC_FREQUENCY = 15 * 60; // seconds | ||||
|     private static final int ADD_IDENTITY = 1; | ||||
|  | ||||
|     /** | ||||
| @@ -91,14 +92,15 @@ public class MessageListActivity extends AppCompatActivity | ||||
|      */ | ||||
|     private boolean twoPane; | ||||
|  | ||||
|     private Messenger messenger = new Messenger(new IncomingHandler()); | ||||
|     private Messenger service; | ||||
|     private boolean bound; | ||||
|     private ServiceConnection connection = new ServiceConnection() { | ||||
|     private static IncomingHandler incomingHandler = new IncomingHandler(); | ||||
|     private static Messenger messenger = new Messenger(incomingHandler); | ||||
|     private static Messenger service; | ||||
|     private static boolean bound; | ||||
|     private static ServiceConnection connection = new ServiceConnection() { | ||||
|         @Override | ||||
|         public void onServiceConnected(ComponentName name, IBinder service) { | ||||
|             MessageListActivity.this.service = new Messenger(service); | ||||
|             MessageListActivity.this.bound = true; | ||||
|             MessageListActivity.service = new Messenger(service); | ||||
|             MessageListActivity.bound = true; | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
| @@ -108,7 +110,6 @@ public class MessageListActivity extends AppCompatActivity | ||||
|         } | ||||
|     }; | ||||
|  | ||||
|     private AccountHeader accountHeader; | ||||
|     private Label selectedLabel; | ||||
|  | ||||
|     private MessageRepository messageRepo; | ||||
| @@ -208,7 +209,7 @@ public class MessageListActivity extends AppCompatActivity | ||||
|                         .withIcon(GoogleMaterial.Icon.gmd_settings) | ||||
|         ); | ||||
|         // Create the AccountHeader | ||||
|         accountHeader = new AccountHeaderBuilder() | ||||
|         AccountHeader accountHeader = new AccountHeaderBuilder() | ||||
|                 .withActivity(this) | ||||
|                 .withHeaderBackground(R.drawable.header) | ||||
|                 .withProfiles(profiles) | ||||
| @@ -229,6 +230,7 @@ public class MessageListActivity extends AppCompatActivity | ||||
|                     } | ||||
|                 }) | ||||
|                 .build(); | ||||
|         incomingHandler.updateAccountHeader(accountHeader); | ||||
|  | ||||
|         ArrayList<IDrawerItem> drawerItems = new ArrayList<>(); | ||||
|         for (Label label : messageRepo.getLabels()) { | ||||
| @@ -414,11 +416,24 @@ public class MessageListActivity extends AppCompatActivity | ||||
|         super.onStop(); | ||||
|     } | ||||
|  | ||||
|     private class IncomingHandler extends Handler { | ||||
|     private static class IncomingHandler extends Handler { | ||||
|         private WeakReference<AccountHeader> accountHeaderRef; | ||||
|  | ||||
|         private IncomingHandler() { | ||||
|             accountHeaderRef = new WeakReference<>(null); | ||||
|         } | ||||
|  | ||||
|         public void updateAccountHeader(AccountHeader accountHeader){ | ||||
|             accountHeaderRef = new WeakReference<>(accountHeader); | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public void handleMessage(Message msg) { | ||||
|             switch (msg.what) { | ||||
|                 case BitmessageService.MSG_CREATE_IDENTITY: { | ||||
|                     AccountHeader accountHeader = accountHeaderRef.get(); | ||||
|                     if (accountHeader == null) break; | ||||
|  | ||||
|                     Serializable data = msg.getData().getSerializable(DATA_FIELD_IDENTITY); | ||||
|                     if (data instanceof BitmessageAddress) { | ||||
|                         BitmessageAddress identity = (BitmessageAddress) data; | ||||
|   | ||||
| @@ -37,13 +37,13 @@ import android.widget.TextView; | ||||
| import org.slf4j.Logger; | ||||
| import org.slf4j.LoggerFactory; | ||||
|  | ||||
| import ch.dissem.apps.abit.synchronization.BitmessageService; | ||||
| import ch.dissem.apps.abit.service.BitmessageService; | ||||
| import ch.dissem.bitmessage.entity.BitmessageAddress; | ||||
|  | ||||
| import static ch.dissem.apps.abit.synchronization.BitmessageService.DATA_FIELD_ADDRESS; | ||||
| import static ch.dissem.apps.abit.synchronization.BitmessageService.MSG_ADD_CONTACT; | ||||
| import static ch.dissem.apps.abit.synchronization.BitmessageService.MSG_SUBSCRIBE; | ||||
| import static ch.dissem.apps.abit.synchronization.BitmessageService.MSG_SUBSCRIBE_AND_ADD_CONTACT; | ||||
| import static ch.dissem.apps.abit.service.BitmessageService.DATA_FIELD_ADDRESS; | ||||
| import static ch.dissem.apps.abit.service.BitmessageService.MSG_ADD_CONTACT; | ||||
| import static ch.dissem.apps.abit.service.BitmessageService.MSG_SUBSCRIBE; | ||||
| import static ch.dissem.apps.abit.service.BitmessageService.MSG_SUBSCRIBE_AND_ADD_CONTACT; | ||||
|  | ||||
| public class OpenBitmessageLinkActivity extends AppCompatActivity { | ||||
|     private static final Logger LOG = LoggerFactory.getLogger(OpenBitmessageLinkActivity.class); | ||||
|   | ||||
| @@ -14,7 +14,7 @@ public abstract class AbstractNotification { | ||||
|  | ||||
|  | ||||
|     public AbstractNotification(Context ctx) { | ||||
|         this.ctx = ctx; | ||||
|         this.ctx = ctx.getApplicationContext(); | ||||
|         this.manager = (NotificationManager) ctx.getSystemService(Context.NOTIFICATION_SERVICE); | ||||
|     } | ||||
|  | ||||
| @@ -23,6 +23,10 @@ public abstract class AbstractNotification { | ||||
|      */ | ||||
|     protected abstract int getNotificationId(); | ||||
|  | ||||
|     public Notification getNotification() { | ||||
|         return notification; | ||||
|     } | ||||
|  | ||||
|     public void show() { | ||||
|         manager.notify(getNotificationId(), notification); | ||||
|     } | ||||
|   | ||||
| @@ -1,6 +1,7 @@ | ||||
| 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; | ||||
| @@ -20,14 +21,14 @@ public class ErrorNotification extends AbstractNotification { | ||||
|                 .setVisibility(NotificationCompat.VISIBILITY_PUBLIC); | ||||
|     } | ||||
|  | ||||
|     public ErrorNotification setWarning(int resId, Object... args) { | ||||
|     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(int resId, Object... args) { | ||||
|     public ErrorNotification setError(@StringRes int resId, Object... args) { | ||||
|         builder.setSmallIcon(R.drawable.ic_notification_error) | ||||
|                 .setContentText(ctx.getString(resId, args)); | ||||
|         notification = builder.build(); | ||||
|   | ||||
| @@ -12,7 +12,6 @@ import java.util.TimerTask; | ||||
|  | ||||
| import ch.dissem.apps.abit.MessageListActivity; | ||||
| import ch.dissem.apps.abit.R; | ||||
| import ch.dissem.apps.abit.service.Singleton; | ||||
| import ch.dissem.bitmessage.BitmessageContext; | ||||
| import ch.dissem.bitmessage.utils.Property; | ||||
|  | ||||
| @@ -26,7 +25,7 @@ public class NetworkNotification extends AbstractNotification { | ||||
|     private NotificationCompat.Builder builder; | ||||
|  | ||||
|     public NetworkNotification(Context ctx, BitmessageContext bmc) { | ||||
|         super(ctx.getApplicationContext()); | ||||
|         super(ctx); | ||||
|         this.bmc = bmc; | ||||
|         builder = new NotificationCompat.Builder(ctx); | ||||
|         builder.setSmallIcon(R.drawable.ic_notification_full_node) | ||||
| @@ -34,6 +33,7 @@ public class NetworkNotification extends AbstractNotification { | ||||
|                 .setVisibility(NotificationCompat.VISIBILITY_PUBLIC); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public Notification getNotification() { | ||||
|         update(); | ||||
|         return notification; | ||||
|   | ||||
| @@ -0,0 +1,38 @@ | ||||
| package ch.dissem.apps.abit.notification; | ||||
|  | ||||
| import android.app.PendingIntent; | ||||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import android.support.v7.app.NotificationCompat; | ||||
|  | ||||
| import ch.dissem.apps.abit.MessageListActivity; | ||||
| import ch.dissem.apps.abit.R; | ||||
|  | ||||
| /** | ||||
|  * Ongoing notification while proof of work is in progress. | ||||
|  */ | ||||
| public class ProofOfWorkNotification extends AbstractNotification { | ||||
|     public static final int ONGOING_NOTIFICATION_ID = 3; | ||||
|  | ||||
|     public ProofOfWorkNotification(Context ctx) { | ||||
|         super(ctx); | ||||
|         NotificationCompat.Builder builder = new NotificationCompat.Builder(ctx); | ||||
|  | ||||
|         Intent showMessageIntent = new Intent(ctx, MessageListActivity.class); | ||||
|         PendingIntent pendingIntent = PendingIntent.getActivity(ctx, 0, showMessageIntent, PendingIntent.FLAG_UPDATE_CURRENT); | ||||
|  | ||||
|         builder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC) | ||||
|                 .setUsesChronometer(true) | ||||
|                 .setSmallIcon(R.drawable.ic_notification_proof_of_work) | ||||
|                 .setContentTitle(ctx.getString(R.string.proof_of_work_title)) | ||||
|                 .setContentText(ctx.getString(R.string.proof_of_work_text)) | ||||
|                 .setContentIntent(pendingIntent); | ||||
|  | ||||
|         notification = builder.build(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected int getNotificationId() { | ||||
|         return ONGOING_NOTIFICATION_ID; | ||||
|     } | ||||
| } | ||||
| @@ -1,25 +1,21 @@ | ||||
| package ch.dissem.apps.abit.synchronization; | ||||
| package ch.dissem.apps.abit.service; | ||||
| 
 | ||||
| import android.app.Service; | ||||
| import android.content.Intent; | ||||
| import android.content.SharedPreferences; | ||||
| import android.os.Bundle; | ||||
| import android.os.Handler; | ||||
| import android.os.IBinder; | ||||
| import android.os.Message; | ||||
| import android.os.Messenger; | ||||
| import android.os.RemoteException; | ||||
| import android.preference.PreferenceManager; | ||||
| 
 | ||||
| import org.slf4j.Logger; | ||||
| import org.slf4j.LoggerFactory; | ||||
| 
 | ||||
| import java.io.Serializable; | ||||
| import java.net.InetAddress; | ||||
| import java.net.UnknownHostException; | ||||
| import java.lang.ref.WeakReference; | ||||
| 
 | ||||
| import ch.dissem.apps.abit.notification.NetworkNotification; | ||||
| import ch.dissem.apps.abit.service.Singleton; | ||||
| import ch.dissem.bitmessage.BitmessageContext; | ||||
| import ch.dissem.bitmessage.entity.BitmessageAddress; | ||||
| 
 | ||||
| @@ -33,7 +29,6 @@ import static ch.dissem.apps.abit.notification.NetworkNotification.ONGOING_NOTIF | ||||
| public class BitmessageService extends Service { | ||||
|     public static final Logger LOG = LoggerFactory.getLogger(BitmessageService.class); | ||||
| 
 | ||||
|     public static final int MSG_SYNC = 2; | ||||
|     public static final int MSG_CREATE_IDENTITY = 10; | ||||
|     public static final int MSG_SUBSCRIBE = 20; | ||||
|     public static final int MSG_ADD_CONTACT = 21; | ||||
| @@ -68,7 +63,7 @@ public class BitmessageService extends Service { | ||||
|             if (bmc == null) { | ||||
|                 bmc = Singleton.getBitmessageContext(this); | ||||
|                 notification = new NetworkNotification(this, bmc); | ||||
|                 messenger = new Messenger(new IncomingHandler()); | ||||
|                 messenger = new Messenger(new IncomingHandler(this)); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| @@ -93,7 +88,13 @@ public class BitmessageService extends Service { | ||||
|         return messenger.getBinder(); | ||||
|     } | ||||
| 
 | ||||
|     private class IncomingHandler extends Handler { | ||||
|     private static class IncomingHandler extends Handler { | ||||
|         private WeakReference<BitmessageService> service; | ||||
| 
 | ||||
|         private IncomingHandler(BitmessageService service) { | ||||
|             this.service = new WeakReference<>(service); | ||||
|         } | ||||
| 
 | ||||
|         @Override | ||||
|         public void handleMessage(Message msg) { | ||||
|             switch (msg.what) { | ||||
| @@ -119,45 +120,6 @@ public class BitmessageService extends Service { | ||||
|                     } | ||||
|                     break; | ||||
|                 } | ||||
|                 case MSG_SYNC: { | ||||
|                     LOG.info("Synchronizing Bitmessage"); | ||||
|                     // If the Bitmessage context acts as a full node, synchronization isn't necessary | ||||
|                     if (bmc.isRunning()) break; | ||||
| 
 | ||||
|                     SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences( | ||||
|                             BitmessageService.this); | ||||
| 
 | ||||
|                     String trustedNode = preferences.getString("trusted_node", null); | ||||
|                     if (trustedNode == null) break; | ||||
|                     trustedNode = trustedNode.trim(); | ||||
|                     if (trustedNode.isEmpty()) break; | ||||
| 
 | ||||
|                     int port; | ||||
|                     if (trustedNode.matches("^(?![0-9a-fA-F]*:[0-9a-fA-F]*:).*(:[0-9]+)$")) { | ||||
|                         int index = trustedNode.lastIndexOf(':'); | ||||
|                         String portString = trustedNode.substring(index + 1); | ||||
|                         trustedNode = trustedNode.substring(0, index); | ||||
|                         try { | ||||
|                             port = Integer.parseInt(portString); | ||||
|                         } catch (NumberFormatException e) { | ||||
|                             LOG.error("Invalid port " + portString); | ||||
|                             // TODO: show error as notification | ||||
|                             return; | ||||
|                         } | ||||
|                     } else { | ||||
|                         port = 8444; | ||||
|                     } | ||||
|                     long timeoutInSeconds = preferences.getInt("sync_timeout", 120); | ||||
|                     try { | ||||
|                         LOG.info("Synchronization started"); | ||||
|                         bmc.synchronize(InetAddress.getByName(trustedNode), port, timeoutInSeconds, true); | ||||
|                         LOG.info("Synchronization finished"); | ||||
|                     } catch (UnknownHostException e) { | ||||
|                         LOG.error("Couldn't synchronize", e); | ||||
|                         // TODO: show error as notification | ||||
|                     } | ||||
|                     break; | ||||
|                 } | ||||
|                 case MSG_SEND_MESSAGE: { | ||||
|                     Serializable identity = msg.getData().getSerializable(DATA_FIELD_IDENTITY); | ||||
|                     Serializable address = msg.getData().getSerializable(DATA_FIELD_ADDRESS); | ||||
| @@ -182,17 +144,17 @@ public class BitmessageService extends Service { | ||||
|                 case MSG_START_NODE: | ||||
|                     // TODO: warn user, option to restrict to WiFi | ||||
|                     // (I'm not quite sure this can be done here, though) | ||||
|                     startService(new Intent(BitmessageService.this, BitmessageService.class)); | ||||
|                     service.get().startService(new Intent(service.get(), BitmessageService.class)); | ||||
|                     running = true; | ||||
|                     startForeground(ONGOING_NOTIFICATION_ID, notification.getNotification()); | ||||
|                     service.get().startForeground(ONGOING_NOTIFICATION_ID, notification.getNotification()); | ||||
|                     bmc.startup(); | ||||
|                     notification.show(); | ||||
|                     break; | ||||
|                 case MSG_STOP_NODE: | ||||
|                     bmc.shutdown(); | ||||
|                     running = false; | ||||
|                     stopForeground(false); | ||||
|                     stopService(new Intent(BitmessageService.this, BitmessageService.class)); | ||||
|                     service.get().stopForeground(false); | ||||
|                     service.get().stopSelf(); | ||||
|                     break; | ||||
|                 default: | ||||
|                     super.handleMessage(msg); | ||||
| @@ -0,0 +1,88 @@ | ||||
| package ch.dissem.apps.abit.service; | ||||
|  | ||||
| import android.app.Service; | ||||
| import android.content.Intent; | ||||
| import android.os.Binder; | ||||
| import android.os.IBinder; | ||||
| import android.support.annotation.Nullable; | ||||
|  | ||||
| import org.slf4j.Logger; | ||||
| import org.slf4j.LoggerFactory; | ||||
|  | ||||
| import java.lang.ref.WeakReference; | ||||
|  | ||||
| import ch.dissem.apps.abit.notification.ProofOfWorkNotification; | ||||
| import ch.dissem.bitmessage.ports.MultiThreadedPOWEngine; | ||||
| import ch.dissem.bitmessage.ports.ProofOfWorkEngine; | ||||
|  | ||||
| import static ch.dissem.apps.abit.notification.ProofOfWorkNotification.ONGOING_NOTIFICATION_ID; | ||||
|  | ||||
| /** | ||||
|  * The Proof of Work Service makes sure POW is done in a foreground process, so it shouldn't be | ||||
|  * killed by the system before the nonce is found. | ||||
|  */ | ||||
| public class ProofOfWorkService extends Service { | ||||
|     public static final Logger LOG = LoggerFactory.getLogger(ProofOfWorkService.class); | ||||
|  | ||||
|     // Object to use as a thread-safe lock | ||||
|     private static final Object lock = new Object(); | ||||
|     private static ProofOfWorkEngine engine; | ||||
|  | ||||
|     @Override | ||||
|     public void onCreate() { | ||||
|         synchronized (lock) { | ||||
|             if (engine == null) { | ||||
|                 engine = new MultiThreadedPOWEngine(); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Nullable | ||||
|     @Override | ||||
|     public IBinder onBind(Intent intent) { | ||||
|         return new PowBinder(engine, this); | ||||
|     } | ||||
|  | ||||
|     public static class PowBinder extends Binder { | ||||
|         private final ProofOfWorkEngine engine; | ||||
|  | ||||
|         private PowBinder(ProofOfWorkEngine engine, ProofOfWorkService service) { | ||||
|             this.engine = new EngineWrapper(engine, service); | ||||
|         } | ||||
|  | ||||
|         public ProofOfWorkEngine getEngine() { | ||||
|             return engine; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private static class EngineWrapper implements ProofOfWorkEngine { | ||||
|         private final ProofOfWorkNotification notification; | ||||
|         private final ProofOfWorkEngine engine; | ||||
|         private final WeakReference<ProofOfWorkService> serviceRef; | ||||
|  | ||||
|         private EngineWrapper(ProofOfWorkEngine engine, ProofOfWorkService service) { | ||||
|             this.engine = engine; | ||||
|             this.serviceRef = new WeakReference<>(service); | ||||
|             this.notification = new ProofOfWorkNotification(service); | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public void calculateNonce(byte[] initialHash, byte[] target, final Callback callback) { | ||||
|             final ProofOfWorkService service = serviceRef.get(); | ||||
|             service.startService(new Intent(service, ProofOfWorkService.class)); | ||||
|             service.startForeground(ONGOING_NOTIFICATION_ID, notification.getNotification()); | ||||
|             engine.calculateNonce(initialHash, target, new ProofOfWorkEngine.Callback() { | ||||
|                 @Override | ||||
|                 public void onNonceCalculated(byte[] nonce) { | ||||
|                     try { | ||||
|                         callback.onNonceCalculated(nonce); | ||||
|                     } finally { | ||||
|                         service.stopForeground(true); | ||||
|                         service.stopSelf(); | ||||
|                     } | ||||
|                 } | ||||
|             }); | ||||
|  | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,61 @@ | ||||
| package ch.dissem.apps.abit.service; | ||||
|  | ||||
| import android.content.ComponentName; | ||||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import android.content.ServiceConnection; | ||||
| import android.os.IBinder; | ||||
|  | ||||
| import java.util.concurrent.Semaphore; | ||||
|  | ||||
| import ch.dissem.apps.abit.service.ProofOfWorkService.PowBinder; | ||||
| import ch.dissem.bitmessage.ports.ProofOfWorkEngine; | ||||
|  | ||||
| import static android.content.Context.BIND_AUTO_CREATE; | ||||
|  | ||||
| /** | ||||
|  * Proof of Work engine that uses the Proof of Work service. | ||||
|  */ | ||||
| public class ServicePowEngine implements ProofOfWorkEngine, ProofOfWorkEngine.Callback { | ||||
|     private final Semaphore semaphore = new Semaphore(1, true); | ||||
|     private final Context ctx; | ||||
|  | ||||
|     private byte[] initialHash, targetValue; | ||||
|     private Callback callback; | ||||
|  | ||||
|     public ServicePowEngine(Context ctx) { | ||||
|         this.ctx = ctx; | ||||
|     } | ||||
|  | ||||
|     private ServiceConnection connection = new ServiceConnection() { | ||||
|         @Override | ||||
|         public void onServiceConnected(ComponentName name, IBinder service) { | ||||
|             ((PowBinder) service).getEngine().calculateNonce(initialHash, targetValue, ServicePowEngine.this); | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public void onServiceDisconnected(ComponentName name) { | ||||
|             semaphore.release(); | ||||
|         } | ||||
|     }; | ||||
|  | ||||
|     @Override | ||||
|     public void calculateNonce(byte[] initialHash, byte[] targetValue, Callback callback) { | ||||
|         try { | ||||
|             semaphore.acquire(); | ||||
|         } catch (InterruptedException e) { | ||||
|             throw new RuntimeException(e); | ||||
|         } | ||||
|         this.initialHash = initialHash; | ||||
|         this.targetValue = targetValue; | ||||
|         this.callback = callback; | ||||
|         ctx.bindService(new Intent(ctx, ProofOfWorkService.class), connection, BIND_AUTO_CREATE); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onNonceCalculated(byte[] bytes) { | ||||
|         callback.onNonceCalculated(bytes); | ||||
|         ctx.unbindService(connection); | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -2,9 +2,6 @@ package ch.dissem.apps.abit.service; | ||||
|  | ||||
| import android.content.Context; | ||||
|  | ||||
| import java.util.Objects; | ||||
|  | ||||
| import ch.dissem.apps.abit.MessageListActivity; | ||||
| import ch.dissem.apps.abit.listener.MessageListener; | ||||
| import ch.dissem.apps.abit.repository.AndroidAddressRepository; | ||||
| import ch.dissem.apps.abit.repository.AndroidInventory; | ||||
| @@ -15,7 +12,6 @@ import ch.dissem.bitmessage.networking.DefaultNetworkHandler; | ||||
| import ch.dissem.bitmessage.ports.AddressRepository; | ||||
| import ch.dissem.bitmessage.ports.MemoryNodeRegistry; | ||||
| import ch.dissem.bitmessage.ports.MessageRepository; | ||||
| import ch.dissem.bitmessage.ports.Security; | ||||
| import ch.dissem.bitmessage.security.sc.SpongySecurity; | ||||
|  | ||||
| /** | ||||
| @@ -33,6 +29,7 @@ public class Singleton { | ||||
|                     final Context ctx = context.getApplicationContext(); | ||||
|                     SqlHelper sqlHelper = new SqlHelper(ctx); | ||||
|                     bitmessageContext = new BitmessageContext.Builder() | ||||
|                             .proofOfWorkEngine(new ServicePowEngine(ctx)) | ||||
|                             .security(new SpongySecurity()) | ||||
|                             .nodeRegistry(new MemoryNodeRegistry()) | ||||
|                             .inventory(new AndroidInventory(sqlHelper)) | ||||
|   | ||||
| @@ -15,6 +15,8 @@ import org.slf4j.LoggerFactory; | ||||
| import java.net.InetAddress; | ||||
| import java.net.UnknownHostException; | ||||
|  | ||||
| import ch.dissem.apps.abit.R; | ||||
| import ch.dissem.apps.abit.notification.ErrorNotification; | ||||
| import ch.dissem.apps.abit.service.Singleton; | ||||
| import ch.dissem.bitmessage.BitmessageContext; | ||||
|  | ||||
| @@ -59,8 +61,9 @@ public class SyncAdapter extends AbstractThreadedSyncAdapter { | ||||
|             try { | ||||
|                 port = Integer.parseInt(portString); | ||||
|             } catch (NumberFormatException e) { | ||||
|                 LOG.error("Invalid port " + portString); | ||||
|                 // TODO: show error as notification | ||||
|                 new ErrorNotification(getContext()) | ||||
|                         .setError(R.string.error_invalid_sync_port, portString) | ||||
|                         .show(); | ||||
|                 return; | ||||
|             } | ||||
|         } else { | ||||
| @@ -72,8 +75,11 @@ public class SyncAdapter extends AbstractThreadedSyncAdapter { | ||||
|             bmc.synchronize(InetAddress.getByName(trustedNode), port, timeoutInSeconds, true); | ||||
|             LOG.info("Synchronization finished"); | ||||
|         } catch (UnknownHostException e) { | ||||
|             LOG.error("Couldn't synchronize", e); | ||||
|             // TODO: show error as notification | ||||
|             new ErrorNotification(getContext()) | ||||
|                     .setError(R.string.error_invalid_sync_host) | ||||
|                     .show(); | ||||
|         } catch (RuntimeException e) { | ||||
|             LOG.error(e.getMessage(), e); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -42,4 +42,8 @@ | ||||
|     <string name="connection_info_n">Stream %1$d: %2$d Verbindungen</string> | ||||
|     <string name="connection_info_disconnected">Getrennt</string> | ||||
|     <string name="connection_info_pending">Verbindung wird aufgebaut…</string> | ||||
|     <string name="proof_of_work_text">Warnung: dies könnte das Gerät erwärmen bis die Batterie leer ist.</string> | ||||
|     <string name="proof_of_work_title">Proof of Work</string> | ||||
|     <string name="error_invalid_sync_host">Synchronisation fehlgeschlagen: der vertrauenswürdige Knoten konnte nicht erreicht werden.</string> | ||||
|     <string name="error_invalid_sync_port">Ungültiger Port in den Synchronisationseinstellungen: %s</string> | ||||
| </resources> | ||||
| @@ -42,4 +42,8 @@ | ||||
|     <string name="send">Send</string> | ||||
|     <string name="connection_info_disconnected">Disconnected</string> | ||||
|     <string name="connection_info_pending">Connecting…</string> | ||||
|     <string name="proof_of_work_title">Proof of Work</string> | ||||
|     <string name="proof_of_work_text">Warning: This might heat your device until the battery\'s dead.</string> | ||||
|     <string name="error_invalid_sync_port">Invalid port in synchronization settings: %s</string> | ||||
|     <string name="error_invalid_sync_host">Synchronization failed: Trusted node could not be reached.</string> | ||||
| </resources> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user