diff --git a/app/src/main/scala/com/nutomic/ensichat/activities/EnsiChatActivity.scala b/app/src/main/scala/com/nutomic/ensichat/activities/EnsiChatActivity.scala new file mode 100644 index 0000000..78ef79c --- /dev/null +++ b/app/src/main/scala/com/nutomic/ensichat/activities/EnsiChatActivity.scala @@ -0,0 +1,65 @@ +package com.nutomic.ensichat.activities + +import android.app.Activity +import android.content.{ComponentName, Context, Intent, ServiceConnection} +import android.os.{Bundle, IBinder} +import com.nutomic.ensichat.bluetooth.{ChatService, ChatServiceBinder} + +/** + * Connects to [[ChatService]] and provides access to it. + */ +class EnsiChatActivity extends Activity with ServiceConnection { + + var chatService: Option[ChatService] = None + + var listeners: List[() => Unit] = List.empty + + /** + * Starts service and connects to it. + */ + override def onCreate(savedInstanceState: Bundle): Unit = { + super.onCreate(savedInstanceState) + startService(new Intent(this, classOf[ChatService])) + bindService(new Intent(this, classOf[ChatService]), this, Context.BIND_AUTO_CREATE) + } + + /** + * Unbinds service. + */ + override def onDestroy(): Unit = { + super.onDestroy() + unbindService(this) + } + + /** + * Calls all listeners registered with [[runOnServiceConnected]]. + * + * Clears the list containing them. + */ + override def onServiceConnected(componentName: ComponentName, iBinder: IBinder): Unit = { + val binder = iBinder.asInstanceOf[ChatServiceBinder] + chatService = Option(binder.getService) + listeners.foreach(_()) + listeners = List.empty + } + + override def onServiceDisconnected(componentName: ComponentName) = + chatService = null + + /** + * Calls l as soon as [[ChatService]] first becomes available. + */ + def runOnServiceConnected(l: () => Unit): Unit = + chatService match { + case Some(s) => l() + case None => listeners :+= l + } + + /** + * Returns the [[ChatService]]. + * + * Should only be called after [[runOnServiceConnected]] callback was called. + */ + def service = chatService.get + +} diff --git a/app/src/main/scala/com/nutomic/ensichat/activities/MainActivity.scala b/app/src/main/scala/com/nutomic/ensichat/activities/MainActivity.scala index ab2012c..3526b88 100644 --- a/app/src/main/scala/com/nutomic/ensichat/activities/MainActivity.scala +++ b/app/src/main/scala/com/nutomic/ensichat/activities/MainActivity.scala @@ -12,7 +12,7 @@ import com.nutomic.ensichat.fragments.{ChatFragment, ContactsFragment} /** * Main activity, entry point for app start. */ -class MainActivity extends Activity { +class MainActivity extends EnsiChatActivity { private val RequestSetDiscoverable = 1 @@ -26,7 +26,6 @@ class MainActivity extends Activity { override def onCreate(savedInstanceState: Bundle): Unit = { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) - startService(new Intent(this, classOf[ChatService])) val intent: Intent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE) diff --git a/app/src/main/scala/com/nutomic/ensichat/fragments/ChatFragment.scala b/app/src/main/scala/com/nutomic/ensichat/fragments/ChatFragment.scala index 0250c51..876ece4 100644 --- a/app/src/main/scala/com/nutomic/ensichat/fragments/ChatFragment.scala +++ b/app/src/main/scala/com/nutomic/ensichat/fragments/ChatFragment.scala @@ -11,6 +11,7 @@ import android.view.{KeyEvent, LayoutInflater, View, ViewGroup} import android.widget.TextView.OnEditorActionListener import android.widget._ import com.nutomic.ensichat.R +import com.nutomic.ensichat.activities.EnsiChatActivity import com.nutomic.ensichat.bluetooth.ChatService.OnMessageReceivedListener import com.nutomic.ensichat.bluetooth.{ChatService, ChatServiceBinder, Device} import com.nutomic.ensichat.messages.{Message, TextMessage} @@ -41,21 +42,21 @@ class ChatFragment extends ListFragment with OnClickListener private var adapter: ArrayAdapter[TextMessage] = _ - private final val mChatServiceConnection: ServiceConnection = new ServiceConnection { - override def onServiceConnected(componentName: ComponentName, iBinder: IBinder): Unit = { - val binder: ChatServiceBinder = iBinder.asInstanceOf[ChatServiceBinder] - chatService = binder.getService + override def onActivityCreated(savedInstanceState: Bundle): Unit = { + super.onActivityCreated(savedInstanceState) + + val activity = getActivity.asInstanceOf[EnsiChatActivity] + activity.runOnServiceConnected(() => { + chatService = activity.service + // Read local device ID from service, adapter = new MessagesAdapter(getActivity, chatService.localDeviceId) chatService.registerMessageListener(device, ChatFragment.this) + if (listView != null) { listView.setAdapter(adapter) } - } - - override def onServiceDisconnected(componentName: ComponentName): Unit = { - chatService = null - } + }) } override def onCreateView(inflater: LayoutInflater, container: ViewGroup, @@ -81,9 +82,6 @@ class ChatFragment extends ListFragment with OnClickListener override def onCreate(savedInstanceState: Bundle): Unit = { super.onCreate(savedInstanceState) - getActivity.bindService(new Intent(getActivity, classOf[ChatService]), - mChatServiceConnection, Context.BIND_AUTO_CREATE) - if (savedInstanceState != null) { device = new Device.ID(savedInstanceState.getString("device")) } @@ -94,11 +92,6 @@ class ChatFragment extends ListFragment with OnClickListener outState.putString("device", device.toString) } - override def onDestroy(): Unit = { - super.onDestroy() - getActivity.unbindService(mChatServiceConnection) - } - /** * Send message if send button was clicked. */ diff --git a/app/src/main/scala/com/nutomic/ensichat/fragments/ContactsFragment.scala b/app/src/main/scala/com/nutomic/ensichat/fragments/ContactsFragment.scala index c46bf1a..80f2f0a 100644 --- a/app/src/main/scala/com/nutomic/ensichat/fragments/ContactsFragment.scala +++ b/app/src/main/scala/com/nutomic/ensichat/fragments/ContactsFragment.scala @@ -6,52 +6,37 @@ import android.os.{Bundle, IBinder} import android.view._ import android.widget.{ArrayAdapter, ListView} import com.nutomic.ensichat.R -import com.nutomic.ensichat.activities.MainActivity +import com.nutomic.ensichat.activities.{EnsiChatActivity, MainActivity} import com.nutomic.ensichat.bluetooth.{ChatService, ChatServiceBinder, Device} -import com.nutomic.ensichat.util.DevicesAdapter +import com.nutomic.ensichat.util.{MessagesAdapter, DevicesAdapter} /** * Lists all nearby, connected devices. */ class ContactsFragment extends ListFragment with ChatService.OnConnectionChangedListener { - private var chatService: ChatService = _ + private lazy val adapter = new DevicesAdapter(getActivity) - private final val ChatServiceConnection: ServiceConnection = new ServiceConnection { - override def onServiceConnected(componentName: ComponentName, iBinder: IBinder): Unit = { - val binder: ChatServiceBinder = iBinder.asInstanceOf[ChatServiceBinder] - chatService = binder.getService - chatService.registerConnectionListener(ContactsFragment.this) - } + override def onActivityCreated(savedInstanceState: Bundle): Unit = { + super.onActivityCreated(savedInstanceState) - override def onServiceDisconnected(componentName: ComponentName): Unit = { - chatService = null - } + val activity = getActivity.asInstanceOf[EnsiChatActivity] + activity.runOnServiceConnected(() => { + activity.service.registerConnectionListener(ContactsFragment.this) + }) } - private var adapter: ArrayAdapter[Device] = _ - override def onCreateView(inflater: LayoutInflater, container: ViewGroup, - savedInstanceState: Bundle): View = { - val view: View = inflater.inflate(R.layout.fragment_contacts, container, false) - view - } + savedInstanceState: Bundle): View = + inflater.inflate(R.layout.fragment_contacts, container, false) override def onCreate(savedInstanceState: Bundle): Unit = { super.onCreate(savedInstanceState) - adapter = new DevicesAdapter(getActivity) setListAdapter(adapter) - getActivity.bindService(new Intent(getActivity, classOf[ChatService]), - ChatServiceConnection, Context.BIND_AUTO_CREATE) setHasOptionsMenu(true) } - override def onDestroy(): Unit = { - super.onDestroy() - getActivity.unbindService(ChatServiceConnection) - } - override def onCreateOptionsMenu(menu: Menu, inflater: MenuInflater): Unit = { super.onCreateOptionsMenu(menu, inflater) inflater.inflate(R.menu.main, menu) @@ -87,8 +72,7 @@ class ContactsFragment extends ListFragment with ChatService.OnConnectionChanged /** * Opens a chat with the clicked device. */ - override def onListItemClick(l: ListView, v: View, position: Int, id: Long): Unit = { + override def onListItemClick(l: ListView, v: View, position: Int, id: Long): Unit = getActivity.asInstanceOf[MainActivity].openChat(adapter.getItem(position).id) - } }