Replaced weak listeners with local broadcasts.
This commit is contained in:
parent
9959453c38
commit
62e54a1c02
6 changed files with 58 additions and 87 deletions
|
@ -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 = {
|
||||
|
|
|
@ -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 _ =>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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() =
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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 =>
|
||||
|
|
Reference in a new issue