Replaced weak listeners with local broadcasts.

This commit is contained in:
Felix Ableitner 2015-07-24 01:39:20 +02:00
parent 9959453c38
commit 62e54a1c02
6 changed files with 58 additions and 87 deletions

View file

@ -15,8 +15,7 @@ import com.nutomic.ensichat.util.{Database, UsersAdapter}
/**
* Lists all nearby, connected devices and allows adding them to be added as contacts.
*/
class AddContactsActivity extends EnsichatActivity with ChatService.OnConnectionsChangedListener
with OnItemClickListener {
class AddContactsActivity extends EnsichatActivity with OnItemClickListener {
private val Tag = "AddContactsActivity"
@ -37,20 +36,18 @@ class AddContactsActivity extends EnsichatActivity with ChatService.OnConnection
list.setOnItemClickListener(this)
list.setEmptyView(findViewById(android.R.id.empty))
runOnServiceConnected(() => {
service.registerConnectionListener(AddContactsActivity.this)
})
val filter = new IntentFilter()
filter.addAction(ChatService.ActionConnectionsChanged)
filter.addAction(Database.ActionContactsUpdated)
LocalBroadcastManager.getInstance(this)
.registerReceiver(onContactsUpdatedListener, new IntentFilter(Database.ActionContactsUpdated))
.registerReceiver(onContactsUpdatedReceiver, filter)
}
override def onDestroy(): Unit = {
super.onDestroy()
LocalBroadcastManager.getInstance(this).unregisterReceiver(onContactsUpdatedListener)
LocalBroadcastManager.getInstance(this).unregisterReceiver(onContactsUpdatedReceiver)
}
override def onConnectionsChanged() = onContactsUpdatedListener.onReceive(null, null)
/**
* Initiates adding the device as contact if it hasn't been added yet.
*/
@ -73,7 +70,7 @@ class AddContactsActivity extends EnsichatActivity with ChatService.OnConnection
/**
* Fetches connections and displays them (excluding contacts).
*/
private val onContactsUpdatedListener = new BroadcastReceiver() {
private val onContactsUpdatedReceiver = new BroadcastReceiver() {
override def onReceive(context: Context, intent: Intent): Unit = {
runOnUiThread(new Runnable {
override def run(): Unit = {

View file

@ -1,7 +1,9 @@
package com.nutomic.ensichat.fragments
import android.app.ListFragment
import android.content.{IntentFilter, Intent, Context, BroadcastReceiver}
import android.os.Bundle
import android.support.v4.content.LocalBroadcastManager
import android.view.View.OnClickListener
import android.view.inputmethod.EditorInfo
import android.view.{KeyEvent, LayoutInflater, View, ViewGroup}
@ -9,7 +11,6 @@ import android.widget.TextView.OnEditorActionListener
import android.widget._
import com.nutomic.ensichat.R
import com.nutomic.ensichat.activities.EnsichatActivity
import com.nutomic.ensichat.protocol.ChatService.OnMessageReceivedListener
import com.nutomic.ensichat.protocol.body.Text
import com.nutomic.ensichat.protocol.{Message, Address, ChatService}
import com.nutomic.ensichat.util.{Database, MessagesAdapter}
@ -17,8 +18,7 @@ import com.nutomic.ensichat.util.{Database, MessagesAdapter}
/**
* Represents a single chat with another specific device.
*/
class ChatFragment extends ListFragment with OnClickListener
with OnMessageReceivedListener {
class ChatFragment extends ListFragment with OnClickListener {
/**
* Fragments need to have a default constructor, so this is optional.
@ -40,7 +40,7 @@ class ChatFragment extends ListFragment with OnClickListener
private var listView: ListView = _
private var adapter: ArrayAdapter[Message] = _
private var adapter: MessagesAdapter = _
override def onActivityCreated(savedInstanceState: Bundle): Unit = {
super.onActivityCreated(savedInstanceState)
@ -53,7 +53,6 @@ class ChatFragment extends ListFragment with OnClickListener
// Read local device ID from service,
adapter = new MessagesAdapter(getActivity, address)
chatService.registerMessageListener(ChatFragment.this)
database.getMessages(address, 15).foreach(adapter.add)
if (listView != null) {
@ -87,6 +86,9 @@ class ChatFragment extends ListFragment with OnClickListener
if (savedInstanceState != null)
address = new Address(savedInstanceState.getByteArray("address"))
LocalBroadcastManager.getInstance(getActivity)
.registerReceiver(onMessageReceivedReceiver, new IntentFilter(ChatService.ActionMessageReceived))
}
override def onSaveInstanceState(outState: Bundle): Unit = {
@ -94,6 +96,11 @@ class ChatFragment extends ListFragment with OnClickListener
outState.putByteArray("address", address.bytes)
}
override def onDestroy(): Unit = {
super.onDestroy()
LocalBroadcastManager.getInstance(getActivity).unregisterReceiver(onMessageReceivedReceiver)
}
/**
* Send message if send button was clicked.
*/
@ -110,13 +117,16 @@ class ChatFragment extends ListFragment with OnClickListener
/**
* Displays new messages in UI.
*/
override def onMessageReceived(msg: Message): Unit = {
if (!Set(msg.header.origin, msg.header.target).contains(address))
return
private val onMessageReceivedReceiver = new BroadcastReceiver {
override def onReceive(context: Context, intent: Intent): Unit = {
val msg = intent.getSerializableExtra(ChatService.ExtraMessage).asInstanceOf[Message]
if (!Set(msg.header.origin, msg.header.target).contains(address))
return
msg.body match {
case _: Text => adapter.add(msg)
case _ =>
msg.body match {
case _: Text => adapter.add(msg)
case _ =>
}
}
}

View file

@ -7,23 +7,26 @@ import android.app.{Notification, NotificationManager, PendingIntent, Service}
import android.content.{Context, Intent}
import android.os.Handler
import android.preference.PreferenceManager
import android.support.v4.content.LocalBroadcastManager
import android.util.Log
import com.nutomic.ensichat.R
import com.nutomic.ensichat.activities.MainActivity
import com.nutomic.ensichat.bluetooth.BluetoothInterface
import com.nutomic.ensichat.fragments.SettingsFragment
import com.nutomic.ensichat.protocol.ChatService.{OnConnectionsChangedListener, OnMessageReceivedListener}
import com.nutomic.ensichat.protocol.body.{ConnectionInfo, MessageBody, UserInfo}
import com.nutomic.ensichat.protocol.header.ContentHeader
import com.nutomic.ensichat.util.{AddContactsHandler, Database, NotificationHandler}
import scala.collection.mutable
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future
object ChatService {
val ActionStopService = "stop_service"
val ActionStopService = "stop_service"
val ActionMessageReceived = "message_received"
val ActionConnectionsChanged = "connections_changed"
val ExtraMessage = "extra_message"
abstract class InterfaceHandler {
@ -35,18 +38,6 @@ object ChatService {
}
trait OnMessageReceivedListener {
def onMessageReceived(messages: Message): Unit
}
/**
* Used with [[ChatService.registerConnectionListener]], called when a Bluetooth device
* connects or disconnects
*/
trait OnConnectionsChangedListener {
def onConnectionsChanged(): Unit
}
}
/**
@ -77,15 +68,6 @@ class ChatService extends Service {
private lazy val seqNumGenerator = new SeqNumGenerator(this)
/**
* For this (and [[messageListeners]], functions would be useful instead of instances,
* but on a Nexus S (Android 4.1.2), these functions are garbage collected even when
* referenced.
*/
private var connectionListeners = new mutable.WeakHashMap[OnConnectionsChangedListener, Unit].keySet
private var messageListeners = new mutable.WeakHashMap[OnMessageReceivedListener, Unit].keySet
private lazy val notificationManager =
getSystemService(Context.NOTIFICATION_SERVICE).asInstanceOf[NotificationManager]
@ -106,9 +88,6 @@ class ChatService extends Service {
Future {
crypto.generateLocalKeys()
registerMessageListener(database)
registerMessageListener(notificationHandler)
registerMessageListener(addContactsHandler)
btInterface.create()
Log.i(Tag, "Service started, address is " + crypto.localAddress)
@ -136,21 +115,6 @@ class ChatService extends Service {
override def onBind(intent: Intent) = binder
/**
* Registers a listener that is called whenever a new message is sent or received.
*/
def registerMessageListener(listener: OnMessageReceivedListener): Unit = {
messageListeners += listener
}
/**
* Registers a listener that is called whenever a new device is connected.
*/
def registerConnectionListener(listener: OnConnectionsChangedListener): Unit = {
connectionListeners += listener
listener.onConnectionsChanged()
}
/**
* Sends a new message to the given target address.
*/
@ -200,10 +164,13 @@ class ChatService extends Service {
callConnectionListeners()
case _ =>
mainHandler.post(new Runnable {
override def run(): Unit =
messageListeners.foreach(_.onMessageReceived(msg))
})
database.onMessageReceived(msg)
notificationHandler.onMessageReceived(msg)
addContactsHandler.onMessageReceived(msg)
val i = new Intent(ChatService.ActionMessageReceived)
i.putExtra(ChatService.ExtraMessage, msg)
LocalBroadcastManager.getInstance(this)
.sendBroadcast(i)
}
/**
@ -249,14 +216,9 @@ class ChatService extends Service {
true
}
/**
* Calls all [[connectionListeners]] with the currently active connections.
*
* Should be called whenever a neighbor connects or disconnects.
*/
def callConnectionListeners(): Unit = {
connectionListeners
.foreach(_.onConnectionsChanged())
LocalBroadcastManager.getInstance(this)
.sendBroadcast(new Intent(ChatService.ActionConnectionsChanged))
}
def connections() =

View file

@ -2,12 +2,13 @@ package com.nutomic.ensichat.util
import android.app.{NotificationManager, PendingIntent}
import android.content.{Context, Intent}
import android.os
import android.os.{Handler, Looper}
import android.support.v4.app.NotificationCompat
import android.util.Log
import android.widget.Toast
import com.nutomic.ensichat.R
import com.nutomic.ensichat.activities.ConfirmAddContactActivity
import com.nutomic.ensichat.protocol.ChatService.OnMessageReceivedListener
import com.nutomic.ensichat.protocol.body.{RequestAddContact, ResultAddContact}
import com.nutomic.ensichat.protocol.{Address, Message, User}
@ -17,8 +18,7 @@ import com.nutomic.ensichat.protocol.{Address, Message, User}
* @param getUser Returns info about a given address.
* @param localAddress Address of the local device.
*/
class AddContactsHandler(context: Context, getUser: (Address) => User, localAddress: Address)
extends OnMessageReceivedListener {
class AddContactsHandler(context: Context, getUser: (Address) => User, localAddress: Address) {
private val Tag = "AddContactsHandler"
@ -93,9 +93,14 @@ class AddContactsHandler(context: Context, getUser: (Address) => User, localAddr
if (info.localConfirmed && info.remoteConfirmed) {
Log.i(Tag, "Adding new contact " + user.toString)
database.addContact(user)
Toast
.makeText(context, context.getString(R.string.contact_added, user.name), Toast.LENGTH_SHORT)
.show()
new Handler(Looper.getMainLooper).post(new Runnable {
override def run(): Unit = {
Toast
.makeText(context,
context.getString(R.string.contact_added, user.name), Toast.LENGTH_SHORT)
.show()
}
})
currentlyAdding -= address
}
}

View file

@ -5,7 +5,6 @@ import java.util.Date
import android.content.{Intent, ContentValues, Context}
import android.database.sqlite.{SQLiteDatabase, SQLiteOpenHelper}
import android.support.v4.content.LocalBroadcastManager
import com.nutomic.ensichat.protocol.ChatService.OnMessageReceivedListener
import com.nutomic.ensichat.protocol._
import com.nutomic.ensichat.protocol.body.{Text, ResultAddContact, RequestAddContact}
import com.nutomic.ensichat.protocol.header.ContentHeader
@ -15,7 +14,7 @@ import scala.collection.{SortedSet, mutable}
object Database {
val ActionContactsUpdated = "Contacts_Updated"
val ActionContactsUpdated = "contacts_updated"
private val DatabaseName = "message_store.db"
@ -44,8 +43,7 @@ object Database {
* Stores all messages and contacts in SQL database.
*/
class Database(context: Context)
extends SQLiteOpenHelper(context, Database.DatabaseName, null, Database.DatabaseVersion)
with OnMessageReceivedListener {
extends SQLiteOpenHelper(context, Database.DatabaseName, null, Database.DatabaseVersion) {
override def onCreate(db: SQLiteDatabase): Unit = {
db.execSQL(Database.CreateContactsTable)
@ -79,7 +77,7 @@ class Database(context: Context)
/**
* Inserts the given new message into the database.
*/
override def onMessageReceived(msg: Message): Unit = msg.body match {
def onMessageReceived(msg: Message): Unit = msg.body match {
case text: Text =>
val cv = new ContentValues()
val ch = msg.header.asInstanceOf[ContentHeader]

View file

@ -6,7 +6,6 @@ import android.preference.PreferenceManager
import android.support.v4.app.NotificationCompat
import com.nutomic.ensichat.R
import com.nutomic.ensichat.activities.MainActivity
import com.nutomic.ensichat.protocol.ChatService.OnMessageReceivedListener
import com.nutomic.ensichat.protocol.body.Text
import com.nutomic.ensichat.protocol.{Crypto, Message}
@ -21,7 +20,7 @@ object NotificationHandler {
/**
* Displays notifications for new messages.
*/
class NotificationHandler(context: Context) extends OnMessageReceivedListener {
class NotificationHandler(context: Context) {
def onMessageReceived(msg: Message): Unit = msg.body match {
case text: Text =>