From 8c71c3418f7f97f72a4686d7c0d362cfd0ecaa85 Mon Sep 17 00:00:00 2001 From: Jeremy Lakeman Date: Wed, 25 Jun 2014 12:54:52 +0930 Subject: [PATCH] Use HTTP API for sending and reading MeshMS, ensure I/O is only done on background threads --- jni/serval-dna | 2 +- .../ServalBatPhoneApplication.java | 13 +++ .../messages/MessagesListActivity.java | 42 +++++-- .../messages/ShowConversationActivity.java | 107 +++++++++++------- src/org/servalproject/rhizome/MeshMS.java | 35 +++--- src/org/servalproject/rhizome/Rhizome.java | 15 +-- .../rhizome/RhizomeManifest_File.java | 2 +- .../servald/PeerListService.java | 8 +- 8 files changed, 142 insertions(+), 82 deletions(-) diff --git a/jni/serval-dna b/jni/serval-dna index 0cb68c98..82b13caa 160000 --- a/jni/serval-dna +++ b/jni/serval-dna @@ -1 +1 @@ -Subproject commit 0cb68c98a33eb4737d5d2a7a8a5151e79928f481 +Subproject commit 82b13caac4c2386a096acc5c72ebde2b4871c245 diff --git a/src/org/servalproject/ServalBatPhoneApplication.java b/src/org/servalproject/ServalBatPhoneApplication.java index 57e0eefc..810842ea 100644 --- a/src/org/servalproject/ServalBatPhoneApplication.java +++ b/src/org/servalproject/ServalBatPhoneApplication.java @@ -46,6 +46,7 @@ import android.net.Uri; import android.os.Environment; import android.os.Handler; +import android.os.HandlerThread; import android.os.Looper; import android.os.Message; import android.preference.PreferenceManager; @@ -104,6 +105,8 @@ public class ServalBatPhoneApplication extends Application { public Control controlService = null; public MeshMS meshMS; public ServalD server; + private Handler backgroundHandler; + private HandlerThread backgroundThread; public static String version="Unknown"; public static long lastModified; @@ -175,6 +178,11 @@ public void mainIdentityUpdated(Identity identity){ public boolean getReady() { if (Looper.myLooper() == null) Looper.prepare(); + + backgroundThread = new HandlerThread("Background"); + backgroundThread.start(); + backgroundHandler = new Handler(backgroundThread.getLooper()); + ChipsetDetection detection = ChipsetDetection.getDetection(); String chipset = settings.getString("chipset", "Automatic"); @@ -584,6 +592,11 @@ public boolean isMainThread() { return this.getMainLooper().getThread().equals(Thread.currentThread()); } + public void runOnBackgroundThread(Runnable r){ + backgroundHandler.removeCallbacks(r); + backgroundHandler.post(r); + } + private Toast toast = null; // Display Toast-Message diff --git a/src/org/servalproject/messages/MessagesListActivity.java b/src/org/servalproject/messages/MessagesListActivity.java index f17d8836..985b2444 100644 --- a/src/org/servalproject/messages/MessagesListActivity.java +++ b/src/org/servalproject/messages/MessagesListActivity.java @@ -26,6 +26,7 @@ import android.content.IntentFilter; import android.graphics.Bitmap; import android.graphics.Typeface; +import android.os.AsyncTask; import android.os.Bundle; import android.util.Log; import android.view.View; @@ -45,6 +46,8 @@ import org.servalproject.servaldna.meshms.MeshMSConversationList; import org.servalproject.ui.SimpleAdapter; +import java.util.List; + /** * main activity to display the list of messages */ @@ -60,9 +63,8 @@ public class MessagesListActivity extends ListActivity implements BroadcastReceiver receiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { - if (intent.getAction().equals(MeshMS.NEW_MESSAGES)) { + if (intent.getAction().equals(MeshMS.NEW_MESSAGES)) populateList(); - } } }; @@ -83,13 +85,35 @@ protected void onCreate(Bundle savedInstanceState) { * get the required data and populate the cursor */ private void populateList() { - try { - MeshMSConversationList conversations = app.server.getRestfulClient().meshmsListConversations(identity.subscriberId); - this.adapter.setItems(conversations.toList()); - setListAdapter(adapter); - } catch (Exception e) { - Log.e(TAG, e.getMessage(), e); - } + if (!app.isMainThread()) + runOnUiThread(new Runnable() { + @Override + public void run() { + populateList(); + } + }); + + new AsyncTask>() { + @Override + protected void onPostExecute(List meshMSConversations) { + if (meshMSConversations!=null) { + adapter.setItems(meshMSConversations); + setListAdapter(adapter); + } + } + + @Override + protected List doInBackground(Void... voids) { + try{ + MeshMSConversationList conversations = app.server.getRestfulClient().meshmsListConversations(identity.subscriberId); + return conversations.toList(); + } catch (Exception e) { + app.displayToastMessage(e.getMessage()); + Log.e(TAG, e.getMessage(), e); + } + return null; + } + }.execute(); } /* diff --git a/src/org/servalproject/messages/ShowConversationActivity.java b/src/org/servalproject/messages/ShowConversationActivity.java index be7418d9..cb485598 100644 --- a/src/org/servalproject/messages/ShowConversationActivity.java +++ b/src/org/servalproject/messages/ShowConversationActivity.java @@ -25,6 +25,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.net.Uri; +import android.os.AsyncTask; import android.os.Bundle; import android.util.Log; import android.view.View; @@ -40,7 +41,6 @@ import org.servalproject.servald.Identity; import org.servalproject.servald.Peer; import org.servalproject.servald.PeerListService; -import org.servalproject.servaldna.ServalDCommand; import org.servalproject.servaldna.SubscriberId; import org.servalproject.servaldna.meshms.MeshMSMessage; import org.servalproject.servaldna.meshms.MeshMSMessageList; @@ -48,6 +48,7 @@ import java.util.ArrayList; import java.util.LinkedList; +import java.util.List; /** * activity to show a conversation thread @@ -170,20 +171,30 @@ protected void onCreate(Bundle savedInstanceState) { private void sendMessage() { // send the message - try { CharSequence messageText = message.getText(); if (messageText==null || "".equals(messageText.toString())) return; - ServalDCommand.sendMessage(identity.subscriberId, recipient.sid, messageText.toString()); - - message.setText(""); - populateList(); + new AsyncTask(){ + @Override + protected void onPostExecute(Boolean ret) { + if (ret) { + message.setText(""); + populateList(); + } + } - } catch (Exception e) { - Log.e(TAG, e.getMessage(), e); - ServalBatPhoneApplication.context.displayToastMessage(e - .getMessage()); - } + @Override + protected Boolean doInBackground(String... args) { + try { + app.server.getRestfulClient().meshmsSendMessage(identity.subscriberId, recipient.sid, args[0]); + return true; + } catch (Exception e) { + Log.e(TAG, e.getMessage(), e); + app.displayToastMessage(e.getMessage()); + } + return false; + } + }.execute(messageText.toString()); } /* @@ -200,36 +211,49 @@ public void run() { }); return; } - try{ - MeshMSMessageList results = app.server.getRestfulClient().meshmsListMessages(identity.subscriberId, recipient.sid); - MeshMSMessage item; - LinkedList listItems = new LinkedList(); - boolean firstRead=true, firstDelivered=true; - while((item = results.nextMessage())!=null){ - switch(item.type){ - case MESSAGE_SENT: - if (item.isDelivered && firstDelivered){ - listItems.addFirst(getString(R.string.meshms_delivered)); - firstDelivered=false; - } - break; - case MESSAGE_RECEIVED: - if (item.isRead && firstRead){ - listItems.addFirst(getString(R.string.meshms_read)); - firstRead=false; + new AsyncTask>(){ + @Override + protected void onPostExecute(List listItems) { + if (listItems!=null) { + adapter.setItems(listItems); + setListAdapter(adapter); + } + } + + @Override + protected List doInBackground(Void... voids) { + try{ + MeshMSMessageList results = app.server.getRestfulClient().meshmsListMessages(identity.subscriberId, recipient.sid); + MeshMSMessage item; + LinkedList listItems = new LinkedList(); + boolean firstRead=true, firstDelivered=true; + while((item = results.nextMessage())!=null){ + switch(item.type){ + case MESSAGE_SENT: + if (item.isDelivered && firstDelivered){ + listItems.addFirst(getString(R.string.meshms_delivered)); + firstDelivered=false; + } + break; + case MESSAGE_RECEIVED: + if (item.isRead && firstRead){ + listItems.addFirst(getString(R.string.meshms_read)); + firstRead=false; + } + break; + default: + continue; } - break; - default: - continue; + listItems.addFirst(item); + } + return new ArrayList(listItems); + }catch(Exception e) { + Log.e(TAG, e.getMessage(), e); + app.displayToastMessage(e.getMessage()); } - listItems.addFirst(item); + return null; } - adapter.setItems(new ArrayList(listItems)); - setListAdapter(adapter); - }catch(Exception e){ - Log.e(TAG, e.getMessage(), e); - app.displayToastMessage(e.getMessage()); - } + }.execute(); } /* @@ -241,7 +265,12 @@ public void run() { public void onPause() { PeerListService.removeListener(this); this.unregisterReceiver(receiver); - app.meshMS.markRead(recipient.sid); + app.runOnBackgroundThread(new Runnable() { + @Override + public void run() { + app.meshMS.markRead(recipient.sid); + } + }); super.onPause(); } diff --git a/src/org/servalproject/rhizome/MeshMS.java b/src/org/servalproject/rhizome/MeshMS.java index 244452b4..06b9ef61 100644 --- a/src/org/servalproject/rhizome/MeshMS.java +++ b/src/org/servalproject/rhizome/MeshMS.java @@ -16,8 +16,6 @@ import org.servalproject.messages.ShowConversationActivity; import org.servalproject.servald.Identity; import org.servalproject.servald.ServalD; -import org.servalproject.servaldna.ServalDCommand; -import org.servalproject.servaldna.ServalDFailureException; import org.servalproject.servaldna.SubscriberId; import org.servalproject.servaldna.meshms.MeshMSConversation; import org.servalproject.servaldna.meshms.MeshMSConversationList; @@ -40,8 +38,9 @@ public void bundleArrived(RhizomeManifest_MeshMS meshms){ public void markRead(SubscriberId recipient){ try { - ServalDCommand.readMessage(identity.subscriberId, recipient); - } catch (ServalDFailureException e) { + app.server.getRestfulClient().meshmsMarkAllMessagesRead(identity.subscriberId, recipient); + } catch (Exception e) { + app.displayToastMessage(e.getMessage()); Log.e(TAG, e.getMessage(), e); } cancelNotification(); @@ -63,23 +62,29 @@ public void initialiseNotification() { MeshMSConversation conv; while ((conv = conversations.nextConversation()) != null) { // detect when the number of incoming messages has changed - if (conv.lastMessageOffset > 0) - messageHash = (messageHash << 25) ^ (messageHash >>> 7) ^ conv.theirSid.hashCode() ^ - (int) ((conv.lastMessageOffset & 0xFFFFFFFF) ^ ((conv.lastMessageOffset >> 32) & 0xFFFFFFFF)); - if (!conv.isRead) { - // remember the recipient, if it is the only recipient with unread messages - if (unread) { - recipient = null; - } else { - recipient = conv.theirSid; - } - unread = true; + if (conv.isRead) + continue; + + messageHash = + conv.theirSid.hashCode() ^ + (int) conv.lastMessageOffset ^ + (int) (conv.lastMessageOffset >> 32); + + Log.v(TAG, conv.theirSid.abbreviation()+", lastOffset = "+conv.lastMessageOffset+", hash = "+messageHash+", read = "+conv.isRead); + + // remember the recipient, if it is the only recipient with unread messages + if (unread) { + recipient = null; + } else { + recipient = conv.theirSid; } + unread = true; } } catch (Exception e) { Log.e(TAG, e.getMessage(), e); } + Log.v(TAG, "unread = "+unread+", hash = "+messageHash+", lastHash = "+lastMessageHash); if (!unread){ cancelNotification(); return; diff --git a/src/org/servalproject/rhizome/Rhizome.java b/src/org/servalproject/rhizome/Rhizome.java index 0b7164d9..5bffe95e 100644 --- a/src/org/servalproject/rhizome/Rhizome.java +++ b/src/org/servalproject/rhizome/Rhizome.java @@ -322,18 +322,6 @@ public static boolean safeDelete(File f) { return false; } - /** Invoked by the servald monitor thread whenever a new bundle has been added to the Rhizome - * store. That monitor thread must remain highly responsive for the sake of voice call - * performance, so the significant work that rhizome needs to do is done in a separate thread - * that is started here. - * - * @author Andrew Bettison - * @throws RhizomeManifestParseException - */ - public static void notifyIncomingBundle(RhizomeManifest manifest) { - new Thread(new ExamineBundle(manifest)).start(); - } - /** Invoked in a thread whenever a new bundle appears in the rhizome store. */ private static class ExamineBundle implements Runnable { @@ -449,7 +437,8 @@ public int message(String cmd, Iterator args, InputStream in, int dataBy } else { manifest = readManifest(bid); } - notifyIncomingBundle(manifest); + + ServalBatPhoneApplication.context.runOnBackgroundThread(new ExamineBundle(manifest)); } catch (Exception e) { Log.v(TAG, e.getMessage(), e); } diff --git a/src/org/servalproject/rhizome/RhizomeManifest_File.java b/src/org/servalproject/rhizome/RhizomeManifest_File.java index e7cc0cc3..603a3ec2 100644 --- a/src/org/servalproject/rhizome/RhizomeManifest_File.java +++ b/src/org/servalproject/rhizome/RhizomeManifest_File.java @@ -76,7 +76,7 @@ public void setName(String name) { @Override public String getDisplayName() { - if (mName != null) + if (mName != null && !"".equals(mName)) return mName; return super.getDisplayName(); } diff --git a/src/org/servalproject/servald/PeerListService.java b/src/org/servalproject/servald/PeerListService.java index 050ca588..817b0267 100644 --- a/src/org/servalproject/servald/PeerListService.java +++ b/src/org/servalproject/servald/PeerListService.java @@ -120,12 +120,12 @@ public static void resolve(final Peer p){ return; if (ServalBatPhoneApplication.context.isMainThread()){ - new Thread(new Runnable() { + ServalBatPhoneApplication.context.runOnBackgroundThread(new Runnable() { @Override public void run() { resolve(p); } - }).start(); + }); return; } @@ -183,12 +183,12 @@ public void result(ServalDCommand.LookupResult nextResult) { private static void closeSocket(){ if (ServalBatPhoneApplication.context.isMainThread()){ - new Thread(new Runnable() { + ServalBatPhoneApplication.context.runOnBackgroundThread(new Runnable() { @Override public void run() { closeSocket(); } - }).start(); + }); return; } if (lookupSocket!=null){