From 35d7a7c4736e4924a8de15a233769c32d57215b2 Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Mon, 27 May 2019 21:34:11 +0200 Subject: [PATCH] Temp --- .idea/misc.xml | 2 +- app/build.gradle | 2 +- app/src/main/AndroidManifest.xml | 22 +- .../messenger/MercuryImApplication.java | 6 +- .../mercury_im/messenger/Notifications.java | 1 + .../messenger/di/component/AppComponent.java | 10 +- .../messenger/di/module/RepositoryModule.java | 10 +- .../messenger/di/module/RoomModule.java | 4 +- .../service/MessengerXmppConnection.java | 16 - .../messenger/service/XmppBoundService.java | 34 ++ .../service/XmppConnectionHolder.java | 27 -- .../messenger/service/XmppService.java | 229 -------------- .../messenger/service/XmppStartedService.java | 298 ++++++++++++++++++ .../mercury_im/messenger/ui/MainActivity.java | 30 +- .../messenger/ui/chat/ChatInputFragment.java | 6 +- .../ui/chatlist/ChatListViewModel.java | 7 + .../messenger/ui/login/LoginActivity.java | 42 +-- .../messenger/ui/roster/RosterFragment.java | 6 +- .../ui/roster/RosterRecyclerViewAdapter.java | 10 +- .../messenger/ui/roster/RosterViewModel.java | 12 +- .../RosterConnector.java | 78 +++++ app/src/main/res/layout/fragment_chat.xml | 3 +- app/src/main/res/layout/view_chat_field.xml | 38 +-- persistence-room/build.gradle | 8 + .../1.json | 175 ++++++++++ .../room/ExampleInstrumentedTest.java | 34 +- .../persistence/room/AppDatabase.java | 10 +- .../persistence/room/dao/AccountDao.java | 7 +- .../persistence/room/dao/BaseDao.java | 4 +- .../persistence/room/dao/ChatDao.java | 20 ++ .../persistence/room/dao/ContactDao.java | 31 ++ .../persistence/room/dao/RosterEntryDao.java | 35 -- .../persistence/room/model/RoomChatModel.java | 23 ++ ...rEntryModel.java => RoomContactModel.java} | 62 ++-- .../room/model/RoomXmppIdentityModel.java | 62 ++++ .../room/repository/IAccountRepository.java | 8 +- .../room/repository/IChatRepository.java | 7 + .../room/repository/IContactRepository.java | 30 ++ .../room/repository/IMessageRepository.java | 28 ++ .../repository/IRosterEntryRepository.java | 31 -- persistence/build.gradle | 1 + .../persistence/model/ChatModel.java | 14 + ...osterEntryModel.java => ContactModel.java} | 12 +- .../persistence/model/MessageModel.java | 10 +- .../persistence/model/XmppIdentityModel.java | 40 +++ .../repository/AccountRepository.java | 4 +- .../repository/ChatRepository.java | 18 ++ ...Repository.java => ContactRepository.java} | 4 +- .../repository/MessageRepository.java | 13 + .../repository/XmppIdentityRepository.java | 12 + settings.gradle | 2 +- version.gradle | 1 + xmpp_android/.gitignore | 1 + xmpp_android/build.gradle | 39 +++ xmpp_android/proguard-rules.pro | 21 ++ .../xmpp_android/ExampleInstrumentedTest.java | 27 ++ xmpp_android/src/main/AndroidManifest.xml | 2 + .../AndroidMercuryConnection.java | 11 + ...celableXMPPTCPConnectionConfiguration.java | 86 +++++ xmpp_android/src/main/res/values/strings.xml | 3 + .../xmpp_android/ExampleUnitTest.java | 17 + xmpp_core/build.gradle | 3 +- .../messenger/xmpp_core/ConnectionState.java | 43 +++ .../xmpp_core/MercuryConnection.java | 36 +++ .../messenger/xmpp_core/RosterHandler.java | 8 + .../xmpp_core/MercuryConnection.java | 16 - 66 files changed, 1400 insertions(+), 512 deletions(-) delete mode 100644 app/src/main/java/org/mercury_im/messenger/service/MessengerXmppConnection.java create mode 100644 app/src/main/java/org/mercury_im/messenger/service/XmppBoundService.java delete mode 100644 app/src/main/java/org/mercury_im/messenger/service/XmppConnectionHolder.java delete mode 100644 app/src/main/java/org/mercury_im/messenger/service/XmppService.java create mode 100644 app/src/main/java/org/mercury_im/messenger/service/XmppStartedService.java create mode 100644 app/src/main/java/org/mercury_im/messenger/ui/chatlist/ChatListViewModel.java create mode 100644 app/src/main/java/org/mercury_im/messenger/xmpp_database_connector/RosterConnector.java create mode 100644 persistence-room/schemas/org.mercury_im.messenger.persistence.room.AppDatabase/1.json create mode 100644 persistence-room/src/main/java/org/mercury_im/messenger/persistence/room/dao/ChatDao.java create mode 100644 persistence-room/src/main/java/org/mercury_im/messenger/persistence/room/dao/ContactDao.java delete mode 100644 persistence-room/src/main/java/org/mercury_im/messenger/persistence/room/dao/RosterEntryDao.java create mode 100644 persistence-room/src/main/java/org/mercury_im/messenger/persistence/room/model/RoomChatModel.java rename persistence-room/src/main/java/org/mercury_im/messenger/persistence/room/model/{RoomRosterEntryModel.java => RoomContactModel.java} (50%) create mode 100644 persistence-room/src/main/java/org/mercury_im/messenger/persistence/room/model/RoomXmppIdentityModel.java create mode 100644 persistence-room/src/main/java/org/mercury_im/messenger/persistence/room/repository/IChatRepository.java create mode 100644 persistence-room/src/main/java/org/mercury_im/messenger/persistence/room/repository/IContactRepository.java delete mode 100644 persistence-room/src/main/java/org/mercury_im/messenger/persistence/room/repository/IRosterEntryRepository.java create mode 100644 persistence/src/main/java/org/mercury_im/messenger/persistence/model/ChatModel.java rename persistence/src/main/java/org/mercury_im/messenger/persistence/model/{RosterEntryModel.java => ContactModel.java} (70%) create mode 100644 persistence/src/main/java/org/mercury_im/messenger/persistence/model/XmppIdentityModel.java create mode 100644 persistence/src/main/java/org/mercury_im/messenger/persistence/repository/ChatRepository.java rename persistence/src/main/java/org/mercury_im/messenger/persistence/repository/{RosterEntryRepository.java => ContactRepository.java} (62%) create mode 100644 persistence/src/main/java/org/mercury_im/messenger/persistence/repository/XmppIdentityRepository.java create mode 100644 xmpp_android/.gitignore create mode 100644 xmpp_android/build.gradle create mode 100644 xmpp_android/proguard-rules.pro create mode 100644 xmpp_android/src/androidTest/java/org/mercury_im/messenger/xmpp_android/ExampleInstrumentedTest.java create mode 100644 xmpp_android/src/main/AndroidManifest.xml create mode 100644 xmpp_android/src/main/java/org/mercury_im/messenger/xmpp_android/AndroidMercuryConnection.java create mode 100644 xmpp_android/src/main/java/org/mercury_im/messenger/xmpp_android/ParcelableXMPPTCPConnectionConfiguration.java create mode 100644 xmpp_android/src/main/res/values/strings.xml create mode 100644 xmpp_android/src/test/java/org/mercury_im/messenger/xmpp_android/ExampleUnitTest.java create mode 100644 xmpp_core/src/main/java/org/mercury_im/messenger/xmpp_core/ConnectionState.java create mode 100644 xmpp_core/src/main/java/org/mercury_im/messenger/xmpp_core/MercuryConnection.java create mode 100644 xmpp_core/src/main/java/org/mercury_im/messenger/xmpp_core/RosterHandler.java delete mode 100644 xmpp_core/src/main/java/org/mercury_im/xmpp_core/MercuryConnection.java diff --git a/.idea/misc.xml b/.idea/misc.xml index 84da703..2326c24 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,6 +1,6 @@ - + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index d67808a..8008107 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -72,7 +72,7 @@ check.configure { // Dependency versions are located in version.gradle dependencies { - implementation project(":xmpp_core") + implementation project(":xmpp_android") implementation(project(':persistence-room')) { transitive = true } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index b9356d0..bc54f7e 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,6 +1,7 @@ + @@ -9,36 +10,37 @@ - + android:theme="@style/AppTheme"> + - + - - - + \ No newline at end of file diff --git a/app/src/main/java/org/mercury_im/messenger/MercuryImApplication.java b/app/src/main/java/org/mercury_im/messenger/MercuryImApplication.java index 503edf5..c74b2fd 100644 --- a/app/src/main/java/org/mercury_im/messenger/MercuryImApplication.java +++ b/app/src/main/java/org/mercury_im/messenger/MercuryImApplication.java @@ -12,7 +12,7 @@ import org.mercury_im.messenger.di.component.DaggerAppComponent; import org.mercury_im.messenger.di.module.AppModule; import org.mercury_im.messenger.di.module.RepositoryModule; import org.mercury_im.messenger.di.module.RoomModule; -import org.mercury_im.messenger.service.XmppService; +import org.mercury_im.messenger.service.XmppStartedService; public class MercuryImApplication extends Application { @@ -39,9 +39,9 @@ public class MercuryImApplication extends Application { appComponent.inject(this); initializeNotificationChannels(this); - Intent serviceIntent = new Intent(getApplicationContext(), XmppService.class); + Intent serviceIntent = new Intent(getApplicationContext(), XmppStartedService.class); - serviceIntent.setAction(XmppService.ACTION_START); + serviceIntent.setAction(XmppStartedService.ACTION_START); if (Build.VERSION.SDK_INT < 26) { startService(serviceIntent); } else { diff --git a/app/src/main/java/org/mercury_im/messenger/Notifications.java b/app/src/main/java/org/mercury_im/messenger/Notifications.java index b61ce28..d525ce9 100644 --- a/app/src/main/java/org/mercury_im/messenger/Notifications.java +++ b/app/src/main/java/org/mercury_im/messenger/Notifications.java @@ -7,6 +7,7 @@ public class Notifications { public static final String NOTIFICATION_CHANNEL__INCOMING_CALL = "incoming_call"; // One day... public static final String NOTIFICATION_CHANNEL__DEBUG = "debug"; + // Notification IDs public static final int FOREGROUND_SERVICE_ID = 1; // must not be 0 diff --git a/app/src/main/java/org/mercury_im/messenger/di/component/AppComponent.java b/app/src/main/java/org/mercury_im/messenger/di/component/AppComponent.java index 08fcb25..cedb7f9 100644 --- a/app/src/main/java/org/mercury_im/messenger/di/component/AppComponent.java +++ b/app/src/main/java/org/mercury_im/messenger/di/component/AppComponent.java @@ -4,7 +4,7 @@ import org.mercury_im.messenger.MercuryImApplication; import org.mercury_im.messenger.di.module.AppModule; import org.mercury_im.messenger.di.module.RepositoryModule; import org.mercury_im.messenger.di.module.RoomModule; -import org.mercury_im.messenger.service.XmppService; +import org.mercury_im.messenger.service.XmppStartedService; import org.mercury_im.messenger.ui.MainActivity; import org.mercury_im.messenger.ui.chat.ChatActivity; import org.mercury_im.messenger.ui.chat.ChatInputFragment; @@ -13,6 +13,7 @@ import org.mercury_im.messenger.ui.chat.ChatViewModel; import org.mercury_im.messenger.ui.login.LoginActivity; import org.mercury_im.messenger.ui.login.LoginViewModel; import org.mercury_im.messenger.ui.roster.RosterViewModel; +import org.mercury_im.messenger.xmpp_database_connector.RosterConnector; import javax.inject.Singleton; @@ -48,5 +49,10 @@ public interface AppComponent { // Services - void inject(XmppService service); + void inject(XmppStartedService service); + + + // Connectors + + void inject(RosterConnector connector); } diff --git a/app/src/main/java/org/mercury_im/messenger/di/module/RepositoryModule.java b/app/src/main/java/org/mercury_im/messenger/di/module/RepositoryModule.java index cc05b52..da2f8d0 100644 --- a/app/src/main/java/org/mercury_im/messenger/di/module/RepositoryModule.java +++ b/app/src/main/java/org/mercury_im/messenger/di/module/RepositoryModule.java @@ -1,11 +1,11 @@ package org.mercury_im.messenger.di.module; import org.mercury_im.messenger.persistence.repository.AccountRepository; -import org.mercury_im.messenger.persistence.repository.RosterEntryRepository; +import org.mercury_im.messenger.persistence.repository.ContactRepository; import org.mercury_im.messenger.persistence.room.dao.AccountDao; -import org.mercury_im.messenger.persistence.room.dao.RosterEntryDao; +import org.mercury_im.messenger.persistence.room.dao.ContactDao; import org.mercury_im.messenger.persistence.room.repository.IAccountRepository; -import org.mercury_im.messenger.persistence.room.repository.IRosterEntryRepository; +import org.mercury_im.messenger.persistence.room.repository.IContactRepository; import javax.inject.Singleton; @@ -23,7 +23,7 @@ public class RepositoryModule { @Singleton @Provides - RosterEntryRepository provideRosterEntryRepository(RosterEntryDao dao) { - return new IRosterEntryRepository(dao); + ContactRepository provideRosterEntryRepository(ContactDao dao) { + return new IContactRepository(dao); } } diff --git a/app/src/main/java/org/mercury_im/messenger/di/module/RoomModule.java b/app/src/main/java/org/mercury_im/messenger/di/module/RoomModule.java index f3e40d8..a274f0e 100644 --- a/app/src/main/java/org/mercury_im/messenger/di/module/RoomModule.java +++ b/app/src/main/java/org/mercury_im/messenger/di/module/RoomModule.java @@ -4,7 +4,7 @@ import org.mercury_im.messenger.MercuryImApplication; import org.mercury_im.messenger.persistence.room.AppDatabase; import org.mercury_im.messenger.persistence.room.dao.AccountDao; import org.mercury_im.messenger.persistence.room.dao.MessageDao; -import org.mercury_im.messenger.persistence.room.dao.RosterEntryDao; +import org.mercury_im.messenger.persistence.room.dao.ContactDao; import javax.inject.Inject; import javax.inject.Singleton; @@ -39,7 +39,7 @@ public class RoomModule { @Singleton @Provides - RosterEntryDao provideRosterEntryDao() { + ContactDao provideRosterEntryDao() { return mAppDatabase.rosterEntryDao(); } diff --git a/app/src/main/java/org/mercury_im/messenger/service/MessengerXmppConnection.java b/app/src/main/java/org/mercury_im/messenger/service/MessengerXmppConnection.java deleted file mode 100644 index 337933f..0000000 --- a/app/src/main/java/org/mercury_im/messenger/service/MessengerXmppConnection.java +++ /dev/null @@ -1,16 +0,0 @@ -package org.mercury_im.messenger.service; - -import org.jivesoftware.smack.XMPPConnection; -import org.mercury_im.messenger.persistence.room.model.RoomAccountModel; - -public class MessengerXmppConnection { - - private final XMPPConnection connection; - private final RoomAccountModel account; - - public MessengerXmppConnection(XMPPConnection connection, RoomAccountModel account) { - this.connection = connection; - this.account = account; - } - -} diff --git a/app/src/main/java/org/mercury_im/messenger/service/XmppBoundService.java b/app/src/main/java/org/mercury_im/messenger/service/XmppBoundService.java new file mode 100644 index 0000000..7f65413 --- /dev/null +++ b/app/src/main/java/org/mercury_im/messenger/service/XmppBoundService.java @@ -0,0 +1,34 @@ +package org.mercury_im.messenger.service; + +import android.app.Service; +import android.content.Intent; +import android.os.Binder; +import android.os.IBinder; + +public class XmppBoundService extends Service { + + private final Binder binder = new Binder(); + private XmppStartedService startedService; + + public class Binder extends android.os.Binder { + public XmppBoundService getService() { + return XmppBoundService.this; + } + } + + public XmppBoundService() { + } + + @Override + public IBinder onBind(Intent intent) { + return binder; + } + + public void setXmppStartedService(XmppStartedService service) { + this.startedService = service; + } + + public XmppStartedService getStartedService() { + return startedService; + } +} diff --git a/app/src/main/java/org/mercury_im/messenger/service/XmppConnectionHolder.java b/app/src/main/java/org/mercury_im/messenger/service/XmppConnectionHolder.java deleted file mode 100644 index 767003a..0000000 --- a/app/src/main/java/org/mercury_im/messenger/service/XmppConnectionHolder.java +++ /dev/null @@ -1,27 +0,0 @@ -package org.mercury_im.messenger.service; - -import android.util.LongSparseArray; - -import org.jivesoftware.smack.XMPPConnection; - -public class XmppConnectionHolder { - - private static XmppConnectionHolder INSTANCE; - - private final LongSparseArray connections = new LongSparseArray<>(); - - private XmppConnectionHolder() { - - } - - public static XmppConnectionHolder getInstance() { - if (INSTANCE == null) { - INSTANCE = new XmppConnectionHolder(); - } - return INSTANCE; - } - - public LongSparseArray getConnections() { - return connections; - } -} diff --git a/app/src/main/java/org/mercury_im/messenger/service/XmppService.java b/app/src/main/java/org/mercury_im/messenger/service/XmppService.java deleted file mode 100644 index 844e928..0000000 --- a/app/src/main/java/org/mercury_im/messenger/service/XmppService.java +++ /dev/null @@ -1,229 +0,0 @@ -package org.mercury_im.messenger.service; - -import android.app.Notification; -import android.app.PendingIntent; -import android.app.Service; -import android.content.Context; -import android.content.Intent; -import android.os.IBinder; -import android.util.Log; -import android.util.LongSparseArray; -import android.widget.Toast; - -import androidx.annotation.Nullable; -import androidx.core.app.NotificationCompat; -import androidx.core.app.NotificationManagerCompat; - -import org.jivesoftware.smack.SmackException; -import org.jivesoftware.smack.XMPPConnection; -import org.jivesoftware.smack.XMPPException; -import org.jivesoftware.smack.roster.Roster; -import org.jivesoftware.smack.roster.RosterEntry; -import org.jivesoftware.smack.roster.RosterLoadedListener; -import org.jivesoftware.smack.tcp.XMPPTCPConnection; -import org.jivesoftware.smack.tcp.XMPPTCPConnectionConfiguration; -import org.jxmpp.jid.EntityBareJid; -import org.jxmpp.jid.impl.JidCreate; -import org.mercury_im.messenger.MercuryImApplication; -import org.mercury_im.messenger.Notifications; -import org.mercury_im.messenger.R; -import org.mercury_im.messenger.persistence.model.RosterEntryModel; -import org.mercury_im.messenger.persistence.repository.RosterEntryRepository; -import org.mercury_im.messenger.persistence.room.AppDatabase; -import org.mercury_im.messenger.persistence.room.model.RoomRosterEntryModel; -import org.mercury_im.messenger.ui.MainActivity; - -import java.io.IOException; -import java.net.InetAddress; -import java.util.Set; - -import javax.inject.Inject; - -/** - * Started Service, which is responsible for managing {@link XMPPConnection XMPPConnections} - * affiliated with registered accounts. - */ -public class XmppService extends Service { - - private static final String TAG = MercuryImApplication.TAG; - - private static final String APP = "org.olomono.mercury"; - private static final String SERVICE = APP + ".XmppService"; - - private static final String ACTION = SERVICE + ".ACTION"; - private static final String EVENT = SERVICE + ".EVENT"; - private static final String EXTRA = SERVICE + ".EXTRA"; - private static final String STATUS = SERVICE + ".STATUS"; - - public static final String ACTION_START = ACTION + ".START"; - public static final String ACTION_STOP = ACTION + ".STOP"; - public static final String ACTION_CONNECT = ACTION + ".CONNECT"; - public static final String ACTION_DISCONNECT = ACTION + ".DISCONNECT"; - public static final String ACTION_PING = ACTION + ".PING"; - - public static final String EVENT_INCOMING_MESSAGE = EVENT + ".INCOMING_MESSAGE"; - public static final String EVENT_OUTGOING_MESSAGE = EVENT + ".OUTGOING_MESSAGE"; - - public static final String EXTRA_JID = EXTRA + ".JID"; - public static final String EXTRA_PASSWORD = EXTRA + ".PASSWORD"; - public static final String EXTRA_ACCOUNT_ID = EXTRA + ".ACCOUNT_ID"; - - public static final String STATUS_SUCCESS = STATUS + ".SUCCESS"; - public static final String STATUS_FAILURE = STATUS + ".FAILURE"; - - @Inject - AppDatabase database; - - @Inject - RosterEntryRepository rosterRepository; - - private final LongSparseArray connections = new LongSparseArray<>(); - - @Nullable - @Override - public final IBinder onBind(Intent intent) { - // We are a started service, so we don't provide a binding and always return null. - return null; - } - - @Override - public void onCreate() { - super.onCreate(); - Log.d(TAG, "onCreate()"); - MercuryImApplication.getApplication().getAppComponent().inject(this); - } - - @Override - public int onStartCommand(Intent intent, int flags, int startId) { - Log.d(TAG, "onStartCommand(" + intent + ")"); - if (intent == null) { - startAndDisplayForegroundNotification(); - } else { - String action = intent.getAction(); - action = action == null ? "" : action; - - switch (action) { - case ACTION_START: - startAndDisplayForegroundNotification(); - break; - case ACTION_STOP: - stopForeground(true); - break; - case ACTION_CONNECT: - String jid = intent.getStringExtra(EXTRA_JID); - EntityBareJid bareJid = JidCreate.entityBareFromOrNull(jid); - if (jid == null) { - Toast.makeText(this, "No JID provided.", Toast.LENGTH_SHORT).show(); - return START_STICKY_COMPATIBILITY; - } - String password = intent.getStringExtra(EXTRA_PASSWORD); - if (password == null) { - Toast.makeText(this, "No Password provided.", Toast.LENGTH_SHORT).show(); - return START_STICKY_COMPATIBILITY; - } - long accountId = intent.getLongExtra(EXTRA_ACCOUNT_ID, -1); - if (accountId == -1) { - Toast.makeText(this, "No account ID provided.", Toast.LENGTH_SHORT).show(); - return START_STICKY_COMPATIBILITY; - } - - new Thread() { - - public void run() { - - XMPPTCPConnection con = null; - try { - InetAddress address = InetAddress.getByName(bareJid.getDomain().toString()); - XMPPTCPConnectionConfiguration conf = XMPPTCPConnectionConfiguration.builder() - .setXmppDomain(bareJid.asDomainBareJid()) - .setUsernameAndPassword(bareJid.getLocalpart().toString(), password) - .setHostAddress(address) - .setConnectTimeout(2 * 60 * 1000) - .build(); - con = new XMPPTCPConnection(conf); - con.connect().login(); - } catch ( - XMPPException e) { - e.printStackTrace(); - } catch ( - SmackException e) { - e.printStackTrace(); - } catch ( - IOException e) { - e.printStackTrace(); - } catch ( - InterruptedException e) { - e.printStackTrace(); - } - - connections.put(intent.getLongExtra(EXTRA_ACCOUNT_ID, -1), con); - NotificationManagerCompat.from(getApplicationContext()).notify(Notifications.FOREGROUND_SERVICE_ID, - getForegroundNotification(getApplicationContext(), connections.size())); - - Roster roster = Roster.getInstanceFor(con); - roster.addRosterLoadedListener(new RosterLoadedListener() { - @Override - public void onRosterLoaded(Roster roster) { - Set entries = roster.getEntries(); - for (RosterEntry e : entries) { - Log.d(TAG, "Inserting Roster entry " + e.getJid().toString()); - RoomRosterEntryModel m = new RoomRosterEntryModel(e.getJid().asEntityBareJidIfPossible(), e.getName(), e.getName()); - m.setAccountId(accountId); - rosterRepository.updateOrInsertRosterEntry(m); - } - } - - @Override - public void onRosterLoadingFailed(Exception exception) { - Log.d(TAG, "Roster Loading failed", exception); - } - }); - - try { - roster.reload(); - } catch (SmackException.NotLoggedInException e) { - e.printStackTrace(); - } catch (SmackException.NotConnectedException e) { - e.printStackTrace(); - } catch (InterruptedException e) { - e.printStackTrace(); - } - - } - }.start(); - break; - default: - break; - } - } - - return START_STICKY_COMPATIBILITY; - } - - public void startAndDisplayForegroundNotification() { - Log.d(TAG, "startAndDisplayForegroundNotification()"); - Notification notification = getForegroundNotification(getApplicationContext(), connections.size()); - - startForeground(Notifications.FOREGROUND_SERVICE_ID, notification); - } - - static Notification getForegroundNotification(Context context, int numConnections) { - Intent startMainActivityIntent = new Intent(context, MainActivity.class); - PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, - startMainActivityIntent, 0); - return new NotificationCompat.Builder(context, Notifications.NOTIFICATION_CHANNEL__FOREGROUND_SERVICE) - .setContentTitle("Mercury") - .setContentText(numConnections + " connections.") - .setSmallIcon(R.drawable.ic_send_black_24dp) - .setContentIntent(pendingIntent) - .build(); - } - - public XMPPConnection getConnection(long accountId) { - return connections.get(accountId); - } - - public void putConnection(int accountId, XMPPConnection connection) { - connections.put(accountId, connection); - } -} diff --git a/app/src/main/java/org/mercury_im/messenger/service/XmppStartedService.java b/app/src/main/java/org/mercury_im/messenger/service/XmppStartedService.java new file mode 100644 index 0000000..2cfbe53 --- /dev/null +++ b/app/src/main/java/org/mercury_im/messenger/service/XmppStartedService.java @@ -0,0 +1,298 @@ +package org.mercury_im.messenger.service; + +import android.app.Notification; +import android.app.PendingIntent; +import android.app.Service; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.os.Handler; +import android.os.IBinder; +import android.os.Looper; +import android.util.Log; +import android.util.LongSparseArray; +import android.widget.Toast; + +import androidx.annotation.Nullable; +import androidx.core.app.NotificationCompat; +import androidx.core.app.NotificationManagerCompat; + +import org.jivesoftware.smack.SmackException; +import org.jivesoftware.smack.XMPPConnection; +import org.jivesoftware.smack.XMPPException; +import org.jivesoftware.smack.chat2.Chat; +import org.jivesoftware.smack.chat2.ChatManager; +import org.jivesoftware.smack.chat2.IncomingChatMessageListener; +import org.jivesoftware.smack.packet.Message; +import org.jivesoftware.smack.roster.Roster; +import org.jivesoftware.smack.roster.RosterEntry; +import org.jivesoftware.smack.roster.RosterLoadedListener; +import org.jivesoftware.smack.tcp.XMPPTCPConnection; +import org.jivesoftware.smack.tcp.XMPPTCPConnectionConfiguration; +import org.jxmpp.jid.EntityBareJid; +import org.mercury_im.messenger.MercuryImApplication; +import org.mercury_im.messenger.Notifications; +import org.mercury_im.messenger.R; +import org.mercury_im.messenger.persistence.model.AccountModel; +import org.mercury_im.messenger.persistence.repository.AccountRepository; +import org.mercury_im.messenger.persistence.repository.ContactRepository; +import org.mercury_im.messenger.persistence.room.AppDatabase; +import org.mercury_im.messenger.persistence.room.model.RoomAccountModel; +import org.mercury_im.messenger.persistence.room.model.RoomContactModel; +import org.mercury_im.messenger.ui.MainActivity; +import org.mercury_im.messenger.xmpp_android.ParcelableXMPPTCPConnectionConfiguration; + +import java.io.IOException; +import java.util.List; +import java.util.Set; + +import javax.inject.Inject; + +/** + * Started Service, which is responsible for managing {@link XMPPConnection XMPPConnections} + * affiliated with registered accounts. + */ +public class XmppStartedService extends Service { + + private static final String TAG = MercuryImApplication.TAG; + + private static final String APP = "org.olomono.mercury"; + private static final String SERVICE = APP + ".XmppStartedService"; + + private static final String ACTION = SERVICE + ".ACTION"; + private static final String EVENT = SERVICE + ".EVENT"; + private static final String EXTRA = SERVICE + ".EXTRA"; + private static final String STATUS = SERVICE + ".STATUS"; + + public static final String ACTION_START = ACTION + ".START"; + public static final String ACTION_STOP = ACTION + ".STOP"; + public static final String ACTION_CONNECT = ACTION + ".CONNECT"; + public static final String ACTION_DISCONNECT = ACTION + ".DISCONNECT"; + public static final String ACTION_PING = ACTION + ".PING"; + + public static final String EVENT_INCOMING_MESSAGE = EVENT + ".INCOMING_MESSAGE"; + public static final String EVENT_OUTGOING_MESSAGE = EVENT + ".OUTGOING_MESSAGE"; + + public static final String EXTRA_CONFIGURATION = EXTRA + ".CONFIGURATION"; + public static final String EXTRA_ACCOUNT_ID = EXTRA + ".ACCOUNT_ID"; + + public static final String STATUS_SUCCESS = STATUS + ".SUCCESS"; + public static final String STATUS_FAILURE = STATUS + ".FAILURE"; + + @Inject + AppDatabase database; + + @Inject + ContactRepository rosterRepository; + + @Inject + AccountRepository accountRepository; + + private final LongSparseArray connections = new LongSparseArray<>(); + + private Handler uiHandler; + + @Nullable + @Override + public final IBinder onBind(Intent intent) { + // We are a started service, so we don't provide a binding and always return null. + return null; + } + + @Override + public void onCreate() { + super.onCreate(); + Log.d(TAG, "onCreate()"); + MercuryImApplication.getApplication().getAppComponent().inject(this); + + Intent intent = new Intent(this, XmppBoundService.class); + bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE); + } + + private ServiceConnection serviceConnection = new ServiceConnection() { + @Override + public void onServiceConnected(ComponentName componentName, IBinder iBinder) { + XmppBoundService.Binder binder = (XmppBoundService.Binder) iBinder; + XmppBoundService boundService = binder.getService(); + boundService.setXmppStartedService(XmppStartedService.this); + } + + @Override + public void onServiceDisconnected(ComponentName componentName) { + + } + }; + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + + if (uiHandler == null) { + uiHandler = new Handler(Looper.getMainLooper()) { + @Override + public void handleMessage(android.os.Message msg) { + switch (msg.what) { + case 1: + Message m = (Message) msg.obj; + Toast.makeText(XmppStartedService.this, (m.getFrom() != null ? m.getFrom().toString() : "null") + ": " + + m.getBody(), Toast.LENGTH_LONG).show(); + } + } + }; + } + + Log.d(TAG, "onStartCommand(" + intent + ")"); + if (intent == null) { + startAndDisplayForegroundNotification(); + } else { + String action = intent.getAction(); + action = action == null ? "" : action; + + switch (action) { + case ACTION_START: + startAndDisplayForegroundNotification(); + startConnections(); + break; + case ACTION_STOP: + stopForeground(true); + break; + case ACTION_CONNECT: + ParcelableXMPPTCPConnectionConfiguration configuration = intent.getParcelableExtra(EXTRA_CONFIGURATION); + if (configuration == null) { + Log.e(TAG, "Configuration is null."); + return START_STICKY_COMPATIBILITY; + } + + long accountId = intent.getLongExtra(EXTRA_ACCOUNT_ID, -1); + if (accountId == -1) { + Log.d(TAG, "No AccountID provided."); + return START_STICKY_COMPATIBILITY; + } + + new Thread() { + public void run() { + XMPPConnection connection = startConnection(configuration, accountId); + connections.put(accountId, connection); + } + }.start(); + break; + default: + break; + } + } + + return START_STICKY_COMPATIBILITY; + } + + public void startAndDisplayForegroundNotification() { + Log.d(TAG, "startAndDisplayForegroundNotification()"); + Notification notification = getForegroundNotification(getApplicationContext(), connections.size()); + + startForeground(Notifications.FOREGROUND_SERVICE_ID, notification); + } + + static Notification getForegroundNotification(Context context, int numConnections) { + Intent startMainActivityIntent = new Intent(context, MainActivity.class); + PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, + startMainActivityIntent, 0); + return new NotificationCompat.Builder(context, Notifications.NOTIFICATION_CHANNEL__FOREGROUND_SERVICE) + .setContentTitle("Mercury") + .setContentText(numConnections + " connections.") + .setSmallIcon(R.drawable.ic_send_black_24dp) + .setContentIntent(pendingIntent) + .build(); + } + + public void startConnections() { + new Thread() { + @Override + public void run() { + synchronized (connections) { + List accounts = accountRepository.getAllAccounts(); + if (accounts == null) return; + + for (AccountModel a : accounts) { + if (connections.get(a.getId()) != null) { + continue; + } + + // XMPPConnection connection = startConnection(a.getJid(), a.getPassword(), a.getId()); + // connections.put(a.getId(), connection); + } + } + } + }.start(); + } + + private XMPPConnection startConnection(ParcelableXMPPTCPConnectionConfiguration connectionConfiguration, long accountId) { + XMPPTCPConnection con = null; + try { + XMPPTCPConnectionConfiguration conf = connectionConfiguration.getConfiguration(); + con = new XMPPTCPConnection(conf); + con.connect().login(); + } catch ( + XMPPException e) { + e.printStackTrace(); + } catch ( + SmackException e) { + e.printStackTrace(); + } catch ( + IOException e) { + e.printStackTrace(); + } catch ( + InterruptedException e) { + e.printStackTrace(); + } + + NotificationManagerCompat.from(getApplicationContext()).notify(Notifications.FOREGROUND_SERVICE_ID, + getForegroundNotification(getApplicationContext(), connections.size())); + + Roster roster = Roster.getInstanceFor(con); + roster.addRosterLoadedListener(new RosterLoadedListener() { + @Override + public void onRosterLoaded(Roster roster) { + Set entries = roster.getEntries(); + for (RosterEntry e : entries) { + Log.d(TAG, "Inserting Roster entry " + e.getJid().toString()); + RoomContactModel m = new RoomContactModel(e.getJid().asEntityBareJidIfPossible(), e.getName(), e.getName()); + m.setAccountId(accountId); + rosterRepository.updateOrInsertRosterEntry(m); + } + } + + @Override + public void onRosterLoadingFailed(Exception exception) { + Log.d(TAG, "Roster Loading failed", exception); + } + }); + + try { + roster.reload(); + } catch (SmackException.NotLoggedInException e) { + e.printStackTrace(); + } catch (SmackException.NotConnectedException e) { + e.printStackTrace(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + ChatManager chatManager = ChatManager.getInstanceFor(con); + chatManager.addIncomingListener(new IncomingChatMessageListener() { + @Override + public void newIncomingMessage(EntityBareJid from, Message message, Chat chat) { + android.os.Message msg = uiHandler.obtainMessage(1, message); + msg.sendToTarget(); + } + }); + + return con; + } + + public XMPPConnection getConnection(long accountId) { + return connections.get(accountId); + } + + public void putConnection(int accountId, XMPPConnection connection) { + connections.put(accountId, connection); + } +} diff --git a/app/src/main/java/org/mercury_im/messenger/ui/MainActivity.java b/app/src/main/java/org/mercury_im/messenger/ui/MainActivity.java index 5ee21d8..ff8a994 100644 --- a/app/src/main/java/org/mercury_im/messenger/ui/MainActivity.java +++ b/app/src/main/java/org/mercury_im/messenger/ui/MainActivity.java @@ -10,16 +10,14 @@ import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.widget.Toolbar; import android.view.Menu; import android.view.MenuItem; -import android.view.View; -import org.jxmpp.jid.impl.JidCreate; import org.mercury_im.messenger.MercuryImApplication; import org.mercury_im.messenger.R; +import org.mercury_im.messenger.persistence.model.AccountModel; import org.mercury_im.messenger.persistence.room.AppDatabase; -import org.mercury_im.messenger.persistence.room.model.RoomAccountModel; -import org.mercury_im.messenger.persistence.room.model.RoomRosterEntryModel; +import org.mercury_im.messenger.persistence.room.model.RoomContactModel; import org.mercury_im.messenger.persistence.repository.AccountRepository; -import org.mercury_im.messenger.persistence.repository.RosterEntryRepository; +import org.mercury_im.messenger.persistence.repository.ContactRepository; import org.mercury_im.messenger.ui.chat.ChatActivity; import org.mercury_im.messenger.ui.login.LoginActivity; import org.mercury_im.messenger.ui.settings.SettingsActivity; @@ -35,7 +33,7 @@ public class MainActivity extends AppCompatActivity { public AccountRepository accountRepository; @Inject - public RosterEntryRepository rosterEntryRepository; + public ContactRepository contactRepository; @Override protected void onCreate(Bundle savedInstanceState) { @@ -47,20 +45,10 @@ public class MainActivity extends AppCompatActivity { MercuryImApplication.getApplication().getAppComponent().inject(this); FloatingActionButton fab = findViewById(R.id.fab); - fab.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - RoomAccountModel account = new RoomAccountModel(); - account.setJid(JidCreate.entityBareFromOrThrowUnchecked("alice@wonderland.lit")); - account.setPassword("swordfish"); - accountRepository.insertAccount(account); - } - }); - - accountRepository.getAllAccounts().observe(this, new Observer>() { + accountRepository.getAllAccountsLive().observe(this, new Observer>() { @Override - public void onChanged(@Nullable List accountModels) { + public void onChanged(@Nullable List accountModels) { if (accountModels == null || accountModels.isEmpty()) { startActivity(new Intent(getApplicationContext(), LoginActivity.class)); } @@ -96,11 +84,11 @@ public class MainActivity extends AppCompatActivity { return super.onOptionsItemSelected(item); } - private void addRosterEntry(AppDatabase database, RoomRosterEntryModel rosterEntry) { + private void addRosterEntry(AppDatabase database, RoomContactModel rosterEntry) { new addRosterEntry(database).execute(rosterEntry); } - private static class addRosterEntry extends AsyncTask { + private static class addRosterEntry extends AsyncTask { private AppDatabase database; @@ -109,7 +97,7 @@ public class MainActivity extends AppCompatActivity { } @Override - protected Void doInBackground(RoomRosterEntryModel... rosterEntryModels) { + protected Void doInBackground(RoomContactModel... rosterEntryModels) { database.rosterEntryDao().insert(rosterEntryModels[0]); return null; } diff --git a/app/src/main/java/org/mercury_im/messenger/ui/chat/ChatInputFragment.java b/app/src/main/java/org/mercury_im/messenger/ui/chat/ChatInputFragment.java index 9418944..ce8aa84 100644 --- a/app/src/main/java/org/mercury_im/messenger/ui/chat/ChatInputFragment.java +++ b/app/src/main/java/org/mercury_im/messenger/ui/chat/ChatInputFragment.java @@ -19,7 +19,7 @@ import org.mercury_im.messenger.R; public class ChatInputFragment extends Fragment implements View.OnClickListener { private EditText textInput; - private FloatingActionButton addAttachement; + private ImageButton addAttachement; private ImageButton buttonSend; private ChatInputViewModel mViewModel; @@ -34,7 +34,7 @@ public class ChatInputFragment extends Fragment implements View.OnClickListener @Nullable Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_chat, container, false); textInput = view.findViewById(R.id.chat_field__text_input); - addAttachement = view.findViewById(R.id.chat_field__fab_add); + addAttachement = view.findViewById(R.id.chat_field__button_attachment); buttonSend = view.findViewById(R.id.chat_field__button_send); addAttachement.setOnClickListener(this); @@ -62,7 +62,7 @@ public class ChatInputFragment extends Fragment implements View.OnClickListener public void onClick(View view) { switch (view.getId()) { // Add media - case R.id.chat_field__fab_add: + case R.id.chat_field__button_attachment: Toast.makeText(getContext(), R.string.not_yet_implemented, Toast.LENGTH_SHORT).show(); break; diff --git a/app/src/main/java/org/mercury_im/messenger/ui/chatlist/ChatListViewModel.java b/app/src/main/java/org/mercury_im/messenger/ui/chatlist/ChatListViewModel.java new file mode 100644 index 0000000..4a03982 --- /dev/null +++ b/app/src/main/java/org/mercury_im/messenger/ui/chatlist/ChatListViewModel.java @@ -0,0 +1,7 @@ +package org.mercury_im.messenger.ui.chatlist; + +import androidx.lifecycle.ViewModel; + +public class ChatListViewModel extends ViewModel { + +} diff --git a/app/src/main/java/org/mercury_im/messenger/ui/login/LoginActivity.java b/app/src/main/java/org/mercury_im/messenger/ui/login/LoginActivity.java index 8901776..8113821 100644 --- a/app/src/main/java/org/mercury_im/messenger/ui/login/LoginActivity.java +++ b/app/src/main/java/org/mercury_im/messenger/ui/login/LoginActivity.java @@ -1,5 +1,6 @@ package org.mercury_im.messenger.ui.login; +import androidx.lifecycle.LiveData; import androidx.lifecycle.ViewModelProviders; import android.content.Intent; import android.os.Bundle; @@ -17,9 +18,10 @@ import org.jxmpp.jid.EntityBareJid; import org.jxmpp.jid.impl.JidCreate; import org.mercury_im.messenger.MercuryImApplication; import org.mercury_im.messenger.R; +import org.mercury_im.messenger.persistence.model.AccountModel; import org.mercury_im.messenger.persistence.room.model.RoomAccountModel; import org.mercury_im.messenger.persistence.repository.AccountRepository; -import org.mercury_im.messenger.service.XmppService; +import org.mercury_im.messenger.service.XmppStartedService; import javax.inject.Inject; @@ -51,19 +53,7 @@ public class LoginActivity extends AppCompatActivity implements TextView.OnEdito mPasswordView = findViewById(R.id.password); viewModel = ViewModelProviders.of(this).get(LoginViewModel.class); - viewModel.getAccount().observe(this, accountModel -> { - if (accountModel == null) { - return; - } - - if (accountModel.getJid() != null) { - mJidView.setText(accountModel.getJid().toString()); - } - - if (accountModel.getPassword() != null) { - mPasswordView.setText(accountModel.getPassword()); - } - }); + displayCredentials(viewModel.getAccount()); mJidView.setOnEditorActionListener(this); mPasswordView.setOnEditorActionListener(this); @@ -80,6 +70,22 @@ public class LoginActivity extends AppCompatActivity implements TextView.OnEdito mProgressView = findViewById(R.id.login_progress); } + private void displayCredentials(LiveData account) { + account.observe(this, accountModel -> { + if (accountModel == null) { + return; + } + + if (accountModel.getJid() != null) { + mJidView.setText(accountModel.getJid().toString()); + } + + if (accountModel.getPassword() != null) { + mPasswordView.setText(accountModel.getPassword()); + } + }); + } + private void loginDetailsEntered() { boolean loginIntact = true; String jidInput = mJidView.getText().toString(); @@ -112,11 +118,9 @@ public class LoginActivity extends AppCompatActivity implements TextView.OnEdito } private void attemptLogin(EntityBareJid jid, String password, long accountId) { - Intent connectIntent = new Intent(getApplicationContext(), XmppService.class); - connectIntent.setAction(XmppService.ACTION_CONNECT); - connectIntent.putExtra(XmppService.EXTRA_JID, jid.toString()); - connectIntent.putExtra(XmppService.EXTRA_PASSWORD, password); - connectIntent.putExtra(XmppService.EXTRA_ACCOUNT_ID, accountId); + Intent connectIntent = new Intent(getApplicationContext(), XmppStartedService.class); + connectIntent.setAction(XmppStartedService.ACTION_CONNECT); + connectIntent.putExtra(XmppStartedService.EXTRA_ACCOUNT_ID, accountId); startService(connectIntent); } diff --git a/app/src/main/java/org/mercury_im/messenger/ui/roster/RosterFragment.java b/app/src/main/java/org/mercury_im/messenger/ui/roster/RosterFragment.java index f948edb..0636883 100644 --- a/app/src/main/java/org/mercury_im/messenger/ui/roster/RosterFragment.java +++ b/app/src/main/java/org/mercury_im/messenger/ui/roster/RosterFragment.java @@ -11,7 +11,7 @@ import android.view.View; import android.view.ViewGroup; import org.mercury_im.messenger.R; -import org.mercury_im.messenger.persistence.room.model.RoomRosterEntryModel; +import org.mercury_im.messenger.persistence.room.model.RoomContactModel; import java.util.ArrayList; import java.util.List; @@ -45,9 +45,9 @@ public class RosterFragment extends Fragment { } private void observeViewModel(RosterViewModel viewModel) { - viewModel.getRosterEntryList().observe(this, new Observer>() { + viewModel.getRosterEntryList().observe(this, new Observer>() { @Override - public void onChanged(@Nullable List rosterEntries) { + public void onChanged(@Nullable List rosterEntries) { if (rosterEntries == null) { return; } diff --git a/app/src/main/java/org/mercury_im/messenger/ui/roster/RosterRecyclerViewAdapter.java b/app/src/main/java/org/mercury_im/messenger/ui/roster/RosterRecyclerViewAdapter.java index 8ee6e7d..8220d34 100644 --- a/app/src/main/java/org/mercury_im/messenger/ui/roster/RosterRecyclerViewAdapter.java +++ b/app/src/main/java/org/mercury_im/messenger/ui/roster/RosterRecyclerViewAdapter.java @@ -8,16 +8,16 @@ import android.view.ViewGroup; import android.widget.TextView; import org.mercury_im.messenger.R; -import org.mercury_im.messenger.persistence.room.model.RoomRosterEntryModel; +import org.mercury_im.messenger.persistence.room.model.RoomContactModel; import java.util.List; public class RosterRecyclerViewAdapter extends RecyclerView.Adapter { - private List entryModelList; + private List entryModelList; - public RosterRecyclerViewAdapter(List entryModelList) { + public RosterRecyclerViewAdapter(List entryModelList) { this.entryModelList = entryModelList; } @@ -30,7 +30,7 @@ public class RosterRecyclerViewAdapter @Override public void onBindViewHolder(@NonNull RecyclerViewHolder holder, int position) { - RoomRosterEntryModel model = entryModelList.get(position); + RoomContactModel model = entryModelList.get(position); holder.jidView.setText(model.getJid().toString()); holder.nicknameView.setText(model.getNickname()); holder.itemView.setTag(model); @@ -41,7 +41,7 @@ public class RosterRecyclerViewAdapter return entryModelList.size(); } - public void setItems(List rosterEntryModels) { + public void setItems(List rosterEntryModels) { this.entryModelList = rosterEntryModels; notifyDataSetChanged(); } diff --git a/app/src/main/java/org/mercury_im/messenger/ui/roster/RosterViewModel.java b/app/src/main/java/org/mercury_im/messenger/ui/roster/RosterViewModel.java index 8ab880c..d743860 100644 --- a/app/src/main/java/org/mercury_im/messenger/ui/roster/RosterViewModel.java +++ b/app/src/main/java/org/mercury_im/messenger/ui/roster/RosterViewModel.java @@ -6,8 +6,8 @@ import androidx.lifecycle.LiveData; import androidx.annotation.NonNull; import org.mercury_im.messenger.MercuryImApplication; -import org.mercury_im.messenger.persistence.room.model.RoomRosterEntryModel; -import org.mercury_im.messenger.persistence.repository.RosterEntryRepository; +import org.mercury_im.messenger.persistence.repository.ContactRepository; +import org.mercury_im.messenger.persistence.room.model.RoomContactModel; import java.util.List; @@ -16,18 +16,18 @@ import javax.inject.Inject; public class RosterViewModel extends AndroidViewModel { @Inject - RosterEntryRepository rosterEntryRepository; + ContactRepository contactRepository; - private final LiveData> rosterEntryList; + private final LiveData> rosterEntryList; @Inject public RosterViewModel(@NonNull Application application) { super(application); MercuryImApplication.getApplication().getAppComponent().inject(this); - this.rosterEntryList = rosterEntryRepository.getAllRosterEntries(); + this.rosterEntryList = contactRepository.getAllRosterEntries(); } - public LiveData> getRosterEntryList() { + public LiveData> getRosterEntryList() { return rosterEntryList; } } diff --git a/app/src/main/java/org/mercury_im/messenger/xmpp_database_connector/RosterConnector.java b/app/src/main/java/org/mercury_im/messenger/xmpp_database_connector/RosterConnector.java new file mode 100644 index 0000000..61b1c6a --- /dev/null +++ b/app/src/main/java/org/mercury_im/messenger/xmpp_database_connector/RosterConnector.java @@ -0,0 +1,78 @@ +package org.mercury_im.messenger.xmpp_database_connector; + +import android.util.Log; + +import org.jivesoftware.smack.packet.Presence; +import org.jivesoftware.smack.roster.Roster; +import org.jivesoftware.smack.roster.RosterEntry; +import org.jxmpp.jid.Jid; +import org.mercury_im.messenger.MercuryImApplication; +import org.mercury_im.messenger.persistence.model.AccountModel; +import org.mercury_im.messenger.persistence.repository.AccountRepository; +import org.mercury_im.messenger.persistence.repository.ContactRepository; +import org.mercury_im.messenger.xmpp_core.MercuryConnection; +import org.mercury_im.messenger.xmpp_core.RosterHandler; + +import java.util.Collection; + +import javax.inject.Inject; + +import static androidx.constraintlayout.widget.Constraints.TAG; + +public class RosterConnector implements RosterHandler { + + @Inject + ContactRepository contactRepository; + + @Inject + AccountRepository accountRepository; + + private AccountModel account; + + private final MercuryConnection connection; + private final Roster roster; + + public RosterConnector(MercuryConnection connection) { + this.connection = connection; + this.roster = connection.getRoster(); + + MercuryImApplication.getApplication().getAppComponent().inject(this); + + account = (AccountModel) accountRepository.getAccount(connection.getAccountId()).getValue(); + } + + @Override + public void entriesAdded(Collection addresses) { + for (Jid j : addresses) { + RosterEntry entry = roster.getEntry(j.asBareJid()); + // ContactModel + } + } + + @Override + public void entriesUpdated(Collection addresses) { + + } + + @Override + public void entriesDeleted(Collection addresses) { + + } + + @Override + public void presenceChanged(Presence presence) { + + } + + @Override + public void onRosterLoaded(Roster roster) { + if (roster == connection.getRoster()) { + + } + } + + @Override + public void onRosterLoadingFailed(Exception exception) { + Log.e(TAG, "Loading roster for " + account.getJid().toString() + " failed.", exception); + } +} diff --git a/app/src/main/res/layout/fragment_chat.xml b/app/src/main/res/layout/fragment_chat.xml index 2c2ab75..30a6526 100644 --- a/app/src/main/res/layout/fragment_chat.xml +++ b/app/src/main/res/layout/fragment_chat.xml @@ -1,5 +1,6 @@ - - - - + card_view:layout_constraintStart_toStartOf="parent"> + + @@ -63,7 +57,7 @@ android:tint="?attr/colorAccent" app:layout_constraintEnd_toEndOf="parent" app:srcCompat="@drawable/ic_send_black_24dp" - card_view:layout_constraintBottom_toBottomOf="parent" /> + app:layout_constraintBottom_toBottomOf="parent" /> diff --git a/persistence-room/build.gradle b/persistence-room/build.gradle index abfe8e4..a1fb13b 100644 --- a/persistence-room/build.gradle +++ b/persistence-room/build.gradle @@ -12,6 +12,12 @@ android { testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + javaCompileOptions { + annotationProcessorOptions { + arguments = ["room.schemaLocation": "$projectDir/schemas".toString()] + } + } + } buildTypes { @@ -36,6 +42,8 @@ dependencies { testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test:runner:1.1.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' + androidTestImplementation "androidx.test:core:1.2.0-beta01" + androidTestImplementation 'androidx.test.ext:junit:1.1.1-beta01' // Room api "androidx.room:room-runtime:$roomVersion" diff --git a/persistence-room/schemas/org.mercury_im.messenger.persistence.room.AppDatabase/1.json b/persistence-room/schemas/org.mercury_im.messenger.persistence.room.AppDatabase/1.json new file mode 100644 index 0000000..42f97cf --- /dev/null +++ b/persistence-room/schemas/org.mercury_im.messenger.persistence.room.AppDatabase/1.json @@ -0,0 +1,175 @@ +{ + "formatVersion": 1, + "database": { + "version": 1, + "identityHash": "378204e8bb2f9f4c8bf432291835718c", + "entities": [ + { + "tableName": "RoomContactModel", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`accountId` INTEGER NOT NULL, `jid` TEXT NOT NULL, `rosterName` TEXT, `nickname` TEXT, PRIMARY KEY(`accountId`, `jid`), FOREIGN KEY(`accountId`) REFERENCES `accounts`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "accountId", + "columnName": "accountId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "jid", + "columnName": "jid", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "rosterName", + "columnName": "rosterName", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "nickname", + "columnName": "nickname", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "accountId", + "jid" + ], + "autoGenerate": false + }, + "indices": [ + { + "name": "index_RoomContactModel_accountId_jid", + "unique": true, + "columnNames": [ + "accountId", + "jid" + ], + "createSql": "CREATE UNIQUE INDEX `index_RoomContactModel_accountId_jid` ON `${TABLE_NAME}` (`accountId`, `jid`)" + } + ], + "foreignKeys": [ + { + "table": "accounts", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "accountId" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "accounts", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `jid` TEXT, `password` TEXT, `enabled` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "jid", + "columnName": "jid", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "password", + "columnName": "password", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "enabled", + "columnName": "enabled", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "messages", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `accountId` INTEGER NOT NULL, `body` TEXT, `sendDate` INTEGER, `from` TEXT, `to` TEXT, FOREIGN KEY(`accountId`) REFERENCES `accounts`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "accountId", + "columnName": "accountId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "body", + "columnName": "body", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "sendDate", + "columnName": "sendDate", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "from", + "columnName": "from", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "to", + "columnName": "to", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [ + { + "table": "accounts", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "accountId" + ], + "referencedColumns": [ + "id" + ] + } + ] + } + ], + "views": [], + "setupQueries": [ + "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, \"378204e8bb2f9f4c8bf432291835718c\")" + ] + } +} \ No newline at end of file diff --git a/persistence-room/src/androidTest/java/org/mercury_im/messenger/persistence/room/ExampleInstrumentedTest.java b/persistence-room/src/androidTest/java/org/mercury_im/messenger/persistence/room/ExampleInstrumentedTest.java index 5277bb2..7fdfbb4 100644 --- a/persistence-room/src/androidTest/java/org/mercury_im/messenger/persistence/room/ExampleInstrumentedTest.java +++ b/persistence-room/src/androidTest/java/org/mercury_im/messenger/persistence/room/ExampleInstrumentedTest.java @@ -2,13 +2,21 @@ package org.mercury_im.messenger.persistence.room; import android.content.Context; -import androidx.test.InstrumentationRegistry; -import androidx.test.runner.AndroidJUnit4; +import androidx.lifecycle.LiveData; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; +import org.jxmpp.jid.impl.JidCreate; +import org.mercury_im.messenger.persistence.room.model.RoomAccountModel; +import org.mercury_im.messenger.persistence.room.repository.IAccountRepository; +import org.mercury_im.messenger.persistence.room.repository.IContactRepository; +import org.mercury_im.messenger.persistence.room.repository.IMessageRepository; -import static org.junit.Assert.*; +import java.util.List; + +import static org.junit.Assert.assertNull; /** * Instrumented test, which will execute on an Android device. @@ -17,11 +25,25 @@ import static org.junit.Assert.*; */ @RunWith(AndroidJUnit4.class) public class ExampleInstrumentedTest { + @Test public void useAppContext() { - // Context of the app under test. - Context appContext = InstrumentationRegistry.getTargetContext(); + // Context of the app under test - assertEquals("org.mercury_im.messenger.persistence.room", appContext.getPackageName()); + Context context = ApplicationProvider.getApplicationContext(); + + AppDatabase appDatabase = AppDatabase.getDatabase(context); + IAccountRepository accountRepository = new IAccountRepository(appDatabase.accountDao()); + IContactRepository rosterRepository = new IContactRepository(appDatabase.rosterEntryDao()); + IMessageRepository messageRepository = new IMessageRepository(appDatabase.messageDao()); + + LiveData> accounts = accountRepository.getAllAccountsLive(); + assertNull(accounts.getValue()); + + RoomAccountModel a1 = new RoomAccountModel(); + a1.setJid(JidCreate.entityBareFromOrThrowUnchecked("alice@wonderland.lit")); + a1.setPassword("5w0rdf1sh"); + a1.setEnabled(false); + accountRepository.insertAccount(a1); } } diff --git a/persistence-room/src/main/java/org/mercury_im/messenger/persistence/room/AppDatabase.java b/persistence-room/src/main/java/org/mercury_im/messenger/persistence/room/AppDatabase.java index fb997fa..0cc08e3 100644 --- a/persistence-room/src/main/java/org/mercury_im/messenger/persistence/room/AppDatabase.java +++ b/persistence-room/src/main/java/org/mercury_im/messenger/persistence/room/AppDatabase.java @@ -8,15 +8,15 @@ import androidx.room.RoomDatabase; import org.mercury_im.messenger.persistence.room.dao.AccountDao; import org.mercury_im.messenger.persistence.room.dao.MessageDao; -import org.mercury_im.messenger.persistence.room.dao.RosterEntryDao; +import org.mercury_im.messenger.persistence.room.dao.ContactDao; import org.mercury_im.messenger.persistence.room.model.RoomAccountModel; +import org.mercury_im.messenger.persistence.room.model.RoomContactModel; import org.mercury_im.messenger.persistence.room.model.RoomMessageModel; -import org.mercury_im.messenger.persistence.room.model.RoomRosterEntryModel; -@Database(entities = {RoomRosterEntryModel.class, RoomAccountModel.class, RoomMessageModel.class}, version = 1) +@Database(entities = {RoomContactModel.class, RoomAccountModel.class, RoomMessageModel.class}, version = 1) public abstract class AppDatabase extends RoomDatabase { - public static final String DB_NAME = "app_db"; + private static final String DB_NAME = "mercury_db"; private static AppDatabase INSTANCE; public static AppDatabase getDatabase(Context context) { @@ -27,7 +27,7 @@ public abstract class AppDatabase extends RoomDatabase { return INSTANCE; } - public abstract RosterEntryDao rosterEntryDao(); + public abstract ContactDao rosterEntryDao(); public abstract MessageDao messageDao(); diff --git a/persistence-room/src/main/java/org/mercury_im/messenger/persistence/room/dao/AccountDao.java b/persistence-room/src/main/java/org/mercury_im/messenger/persistence/room/dao/AccountDao.java index 3d5c6ce..41dea43 100644 --- a/persistence-room/src/main/java/org/mercury_im/messenger/persistence/room/dao/AccountDao.java +++ b/persistence-room/src/main/java/org/mercury_im/messenger/persistence/room/dao/AccountDao.java @@ -28,7 +28,12 @@ public interface AccountDao extends BaseDao { * @return live updating account list */ @Query("select * from accounts") - LiveData> getAllAccounts(); + LiveData> getAllAccountsLive(); + + @Query("select * from accounts") + List getAllAccounts(); + + /** * Return the {@link RoomAccountModel Account} which is identified by the given id. diff --git a/persistence-room/src/main/java/org/mercury_im/messenger/persistence/room/dao/BaseDao.java b/persistence-room/src/main/java/org/mercury_im/messenger/persistence/room/dao/BaseDao.java index 72e3fdf..4cb877a 100644 --- a/persistence-room/src/main/java/org/mercury_im/messenger/persistence/room/dao/BaseDao.java +++ b/persistence-room/src/main/java/org/mercury_im/messenger/persistence/room/dao/BaseDao.java @@ -10,8 +10,8 @@ public interface BaseDao { long insert(T entity); @Update - void update(T entity); + void upddate(T... entity); @Delete - void delete(T entity); + void delete(T... entity); } diff --git a/persistence-room/src/main/java/org/mercury_im/messenger/persistence/room/dao/ChatDao.java b/persistence-room/src/main/java/org/mercury_im/messenger/persistence/room/dao/ChatDao.java new file mode 100644 index 0000000..b67bb0a --- /dev/null +++ b/persistence-room/src/main/java/org/mercury_im/messenger/persistence/room/dao/ChatDao.java @@ -0,0 +1,20 @@ +package org.mercury_im.messenger.persistence.room.dao; + +import androidx.lifecycle.LiveData; +import androidx.room.Query; + +import org.jxmpp.jid.EntityBareJid; +import org.mercury_im.messenger.persistence.room.model.RoomChatModel; + +import java.util.List; + +public interface ChatDao extends BaseDao { + + @Query("SELECT * FROM RoomChatModel") + LiveData> getAllChats(); + + @Query("SELECT * FROM RoomChatModel WHERE ") + LiveData getChatWith(EntityBareJid contact); + + +} diff --git a/persistence-room/src/main/java/org/mercury_im/messenger/persistence/room/dao/ContactDao.java b/persistence-room/src/main/java/org/mercury_im/messenger/persistence/room/dao/ContactDao.java new file mode 100644 index 0000000..5dc909b --- /dev/null +++ b/persistence-room/src/main/java/org/mercury_im/messenger/persistence/room/dao/ContactDao.java @@ -0,0 +1,31 @@ +package org.mercury_im.messenger.persistence.room.dao; + +import androidx.lifecycle.LiveData; +import androidx.room.Dao; +import androidx.room.Query; +import androidx.room.TypeConverters; + +import org.jxmpp.jid.EntityBareJid; +import org.mercury_im.messenger.persistence.room.model.RoomContactModel; +import org.mercury_im.messenger.persistence.room.type_converter.EntityBareJidConverter; + +import java.util.List; + +@Dao +@TypeConverters(EntityBareJidConverter.class) +public interface ContactDao extends BaseDao { + + /** + * Return a {@link LiveData} wrapping a {@link List} of all {@link RoomContactModel RosterEntries} + * which are currently found in the database. + * @return + */ + @Query("select * from RoomContactModel") + LiveData> getAllRosterEntries(); + + @Query("select * from RoomContactModel where jid = :jid") + RoomContactModel getRosterEntryByJid(EntityBareJid jid); + + @Query("select * from RoomContactModel where accountId = :accountId") + LiveData> getRosterEntriesForAccount(long accountId); +} diff --git a/persistence-room/src/main/java/org/mercury_im/messenger/persistence/room/dao/RosterEntryDao.java b/persistence-room/src/main/java/org/mercury_im/messenger/persistence/room/dao/RosterEntryDao.java deleted file mode 100644 index d6f88d9..0000000 --- a/persistence-room/src/main/java/org/mercury_im/messenger/persistence/room/dao/RosterEntryDao.java +++ /dev/null @@ -1,35 +0,0 @@ -package org.mercury_im.messenger.persistence.room.dao; - -import androidx.lifecycle.LiveData; -import androidx.room.Dao; -import androidx.room.Delete; -import androidx.room.Insert; -import androidx.room.Query; -import androidx.room.TypeConverters; - -import org.mercury_im.messenger.persistence.model.RosterEntryModel; -import org.mercury_im.messenger.persistence.room.type_converter.EntityBareJidConverter; -import org.mercury_im.messenger.persistence.room.model.RoomRosterEntryModel; - -import java.util.List; - -import static androidx.room.OnConflictStrategy.REPLACE; - -@Dao -@TypeConverters(EntityBareJidConverter.class) -public interface RosterEntryDao extends BaseDao { - - /** - * Return a {@link LiveData} wrapping a {@link List} of all {@link RoomRosterEntryModel RosterEntries} - * which are currently found in the database. - * @return - */ - @Query("select * from roster") - LiveData> getAllRosterEntries(); - - @Query("select * from roster where id = :id") - RoomRosterEntryModel getRosterEntryById(long id); - - @Query("select * from roster where accountId = :accountId") - LiveData> getRosterEntriesForAccount(long accountId); -} diff --git a/persistence-room/src/main/java/org/mercury_im/messenger/persistence/room/model/RoomChatModel.java b/persistence-room/src/main/java/org/mercury_im/messenger/persistence/room/model/RoomChatModel.java new file mode 100644 index 0000000..e0a0d24 --- /dev/null +++ b/persistence-room/src/main/java/org/mercury_im/messenger/persistence/room/model/RoomChatModel.java @@ -0,0 +1,23 @@ +package org.mercury_im.messenger.persistence.room.model; + +import androidx.lifecycle.LiveData; +import androidx.paging.PagedList; +import androidx.room.Entity; + +import org.mercury_im.messenger.persistence.model.ChatModel; +import org.mercury_im.messenger.persistence.model.ContactModel; +import org.mercury_im.messenger.persistence.model.MessageModel; + +@Entity +public class RoomChatModel implements ChatModel { + + @Override + public LiveData getContact() { + return null; + } + + @Override + public LiveData> getMessages() { + return null; + } +} diff --git a/persistence-room/src/main/java/org/mercury_im/messenger/persistence/room/model/RoomRosterEntryModel.java b/persistence-room/src/main/java/org/mercury_im/messenger/persistence/room/model/RoomContactModel.java similarity index 50% rename from persistence-room/src/main/java/org/mercury_im/messenger/persistence/room/model/RoomRosterEntryModel.java rename to persistence-room/src/main/java/org/mercury_im/messenger/persistence/room/model/RoomContactModel.java index f4d4713..5011f7f 100644 --- a/persistence-room/src/main/java/org/mercury_im/messenger/persistence/room/model/RoomRosterEntryModel.java +++ b/persistence-room/src/main/java/org/mercury_im/messenger/persistence/room/model/RoomContactModel.java @@ -1,28 +1,37 @@ package org.mercury_im.messenger.persistence.room.model; +import androidx.annotation.NonNull; import androidx.room.Entity; import androidx.room.ForeignKey; -import androidx.room.PrimaryKey; +import androidx.room.Index; import androidx.room.TypeConverters; import org.jxmpp.jid.EntityBareJid; -import org.mercury_im.messenger.persistence.model.RosterEntryModel; +import org.mercury_im.messenger.persistence.model.ContactModel; import org.mercury_im.messenger.persistence.room.type_converter.EntityBareJidConverter; +import java.io.File; + import static androidx.room.ForeignKey.CASCADE; +import static androidx.room.ForeignKey.RESTRICT; -@Entity(tableName = "roster", foreignKeys = @ForeignKey(entity = RoomAccountModel.class, - parentColumns = "id", - childColumns = "accountId", - onDelete = CASCADE)) -public class RoomRosterEntryModel implements RosterEntryModel { - - @PrimaryKey(autoGenerate = true) - public long id; +@Entity(primaryKeys = {"accountId", "jid"}, + indices = {@Index(value = {"accountId", "jid"}, unique = true)}, + foreignKeys = { + @ForeignKey(entity = RoomAccountModel.class, + parentColumns = "id", + childColumns = "accountId", + onDelete = CASCADE), + @ForeignKey(entity = RoomXmppIdentityModel.class, + parentColumns = {"accountId", "jid"}, + childColumns = {"accountId", "jid"}, + onDelete = RESTRICT)}) +public class RoomContactModel implements ContactModel { private long accountId; + @NonNull @TypeConverters(EntityBareJidConverter.class) private EntityBareJid jid; @@ -30,27 +39,27 @@ public class RoomRosterEntryModel implements RosterEntryModel { private String nickname; - public RoomRosterEntryModel(EntityBareJid jid, String rosterName, String nickname) { + private File avatarFile; + + public RoomContactModel(@NonNull EntityBareJid jid, + String rosterName, + String nickname) { this.jid = jid; this.nickname = nickname; this.rosterName = rosterName; } - @Override - public long getId() { - return id; - } - - @Override - public void setId(long id) { - this.id = id; - } - + @NonNull @Override public EntityBareJid getJid() { return jid; } + @Override + public void setJid(EntityBareJid jid) { + + } + @Override public String getRosterName() { return rosterName; @@ -80,4 +89,15 @@ public class RoomRosterEntryModel implements RosterEntryModel { public void setAccountId(long accountId) { this.accountId = accountId; } + + @Override + public File getAvatarFile() { + return avatarFile; + } + + @Override + public void setAvatarFile(File file) { + this.avatarFile = file; + } + } diff --git a/persistence-room/src/main/java/org/mercury_im/messenger/persistence/room/model/RoomXmppIdentityModel.java b/persistence-room/src/main/java/org/mercury_im/messenger/persistence/room/model/RoomXmppIdentityModel.java new file mode 100644 index 0000000..c79bc08 --- /dev/null +++ b/persistence-room/src/main/java/org/mercury_im/messenger/persistence/room/model/RoomXmppIdentityModel.java @@ -0,0 +1,62 @@ +package org.mercury_im.messenger.persistence.room.model; + +import android.graphics.Bitmap; + +import androidx.annotation.NonNull; +import androidx.room.Entity; +import androidx.room.ForeignKey; +import androidx.room.Index; + +import org.jxmpp.jid.EntityBareJid; +import org.mercury_im.messenger.persistence.model.XmppIdentityModel; + +import java.io.File; + +import static androidx.room.ForeignKey.CASCADE; + +@Entity(tableName = "entities", primaryKeys = {"accountId", "jid"}, + indices = {@Index(value = {"accountId", "jid"}, unique = true)}, + foreignKeys = @ForeignKey(entity = RoomAccountModel.class, + parentColumns = "id", + childColumns = "accountId", + onDelete = CASCADE)) +public class RoomXmppIdentityModel implements XmppIdentityModel { + + protected long accountId; + + protected EntityBareJid jid; + + protected File avatarFile; + + @NonNull + @Override + public EntityBareJid getJid() { + return jid; + } + + @Override + public void setJid(EntityBareJid jid) { + this.jid = jid; + } + + @Override + public long getAccountId() { + return accountId; + } + + @Override + public void setAccountId(long accountId) { + this.accountId = accountId; + } + + @Override + public File getAvatarFile() { + return avatarFile; + } + + @Override + public void setAvatarFile(File file) { + this.avatarFile = file; + } + +} diff --git a/persistence-room/src/main/java/org/mercury_im/messenger/persistence/room/repository/IAccountRepository.java b/persistence-room/src/main/java/org/mercury_im/messenger/persistence/room/repository/IAccountRepository.java index a752ddb..e390d89 100644 --- a/persistence-room/src/main/java/org/mercury_im/messenger/persistence/room/repository/IAccountRepository.java +++ b/persistence-room/src/main/java/org/mercury_im/messenger/persistence/room/repository/IAccountRepository.java @@ -28,10 +28,16 @@ public class IAccountRepository implements AccountRepository { } @Override - public LiveData> getAllAccounts() { + public LiveData> getAllAccountsLive() { + return accountDao.getAllAccountsLive(); + } + + @Override + public List getAllAccounts() { return accountDao.getAllAccounts(); } + @Override public long insertAccount(RoomAccountModel accountModel) { InsertAsyncTask task = new InsertAsyncTask(accountDao); diff --git a/persistence-room/src/main/java/org/mercury_im/messenger/persistence/room/repository/IChatRepository.java b/persistence-room/src/main/java/org/mercury_im/messenger/persistence/room/repository/IChatRepository.java new file mode 100644 index 0000000..49cac45 --- /dev/null +++ b/persistence-room/src/main/java/org/mercury_im/messenger/persistence/room/repository/IChatRepository.java @@ -0,0 +1,7 @@ +package org.mercury_im.messenger.persistence.room.repository; + +import org.mercury_im.messenger.persistence.repository.ChatRepository; + +public class IChatRepository implements ChatRepository { + +} diff --git a/persistence-room/src/main/java/org/mercury_im/messenger/persistence/room/repository/IContactRepository.java b/persistence-room/src/main/java/org/mercury_im/messenger/persistence/room/repository/IContactRepository.java new file mode 100644 index 0000000..3b6cfe0 --- /dev/null +++ b/persistence-room/src/main/java/org/mercury_im/messenger/persistence/room/repository/IContactRepository.java @@ -0,0 +1,30 @@ +package org.mercury_im.messenger.persistence.room.repository; + +import androidx.lifecycle.LiveData; + +import org.mercury_im.messenger.persistence.repository.ContactRepository; +import org.mercury_im.messenger.persistence.room.dao.ContactDao; +import org.mercury_im.messenger.persistence.room.model.RoomContactModel; + +import java.util.List; + +public class IContactRepository implements ContactRepository { + + private final ContactDao contactDao; + + public IContactRepository(ContactDao dao) { + this.contactDao = dao; + } + + @Override + public LiveData> getAllRosterEntries() { + return contactDao.getAllRosterEntries(); + } + + @Override + public void updateOrInsertRosterEntry(RoomContactModel rosterEntryModel) { + contactDao.insert(rosterEntryModel); + } + + +} diff --git a/persistence-room/src/main/java/org/mercury_im/messenger/persistence/room/repository/IMessageRepository.java b/persistence-room/src/main/java/org/mercury_im/messenger/persistence/room/repository/IMessageRepository.java index 1ae2906..d2edf64 100644 --- a/persistence-room/src/main/java/org/mercury_im/messenger/persistence/room/repository/IMessageRepository.java +++ b/persistence-room/src/main/java/org/mercury_im/messenger/persistence/room/repository/IMessageRepository.java @@ -1,7 +1,35 @@ package org.mercury_im.messenger.persistence.room.repository; +import androidx.lifecycle.LiveData; + +import org.jxmpp.jid.EntityBareJid; +import org.jxmpp.jid.EntityFullJid; import org.mercury_im.messenger.persistence.repository.MessageRepository; +import org.mercury_im.messenger.persistence.room.dao.MessageDao; import org.mercury_im.messenger.persistence.room.model.RoomMessageModel; +import java.util.List; + public class IMessageRepository implements MessageRepository { + + private final MessageDao messageDao; + + public IMessageRepository(MessageDao messageDao) { + this.messageDao = messageDao; + } + + @Override + public long insertMessage(RoomMessageModel message) { + return messageDao.insert(message); + } + + @Override + public LiveData> getAllMessagesOf(long accountId) { + return messageDao.getAllMessagesOf(accountId); + } + + @Override + public LiveData> getAllMessagesFrom(long accountId, EntityFullJid contact) { + return messageDao.getAllMessagesFrom(accountId, contact); + } } diff --git a/persistence-room/src/main/java/org/mercury_im/messenger/persistence/room/repository/IRosterEntryRepository.java b/persistence-room/src/main/java/org/mercury_im/messenger/persistence/room/repository/IRosterEntryRepository.java deleted file mode 100644 index aedc2c2..0000000 --- a/persistence-room/src/main/java/org/mercury_im/messenger/persistence/room/repository/IRosterEntryRepository.java +++ /dev/null @@ -1,31 +0,0 @@ -package org.mercury_im.messenger.persistence.room.repository; - -import androidx.lifecycle.LiveData; - -import org.mercury_im.messenger.persistence.model.RosterEntryModel; -import org.mercury_im.messenger.persistence.repository.RosterEntryRepository; -import org.mercury_im.messenger.persistence.room.dao.RosterEntryDao; -import org.mercury_im.messenger.persistence.room.model.RoomRosterEntryModel; - -import java.util.List; - -public class IRosterEntryRepository implements RosterEntryRepository { - - private final RosterEntryDao rosterEntryDao; - - public IRosterEntryRepository(RosterEntryDao dao) { - this.rosterEntryDao = dao; - } - - @Override - public LiveData> getAllRosterEntries() { - return rosterEntryDao.getAllRosterEntries(); - } - - @Override - public void updateOrInsertRosterEntry(RoomRosterEntryModel rosterEntryModel) { - rosterEntryDao.insert(rosterEntryModel); - } - - -} diff --git a/persistence/build.gradle b/persistence/build.gradle index 88db8a2..cc645e7 100644 --- a/persistence/build.gradle +++ b/persistence/build.gradle @@ -37,4 +37,5 @@ dependencies { testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test:runner:1.1.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' + api "androidx.paging:paging-runtime:$pagingVersion" } diff --git a/persistence/src/main/java/org/mercury_im/messenger/persistence/model/ChatModel.java b/persistence/src/main/java/org/mercury_im/messenger/persistence/model/ChatModel.java new file mode 100644 index 0000000..b802f9a --- /dev/null +++ b/persistence/src/main/java/org/mercury_im/messenger/persistence/model/ChatModel.java @@ -0,0 +1,14 @@ +package org.mercury_im.messenger.persistence.model; + +import org.jxmpp.jid.EntityBareJid; + +public interface ChatModel { + + EntityBareJid getJid(); + + void setJid(EntityBareJid jid); + + long getAccountId(); + + void setAccountId(); +} diff --git a/persistence/src/main/java/org/mercury_im/messenger/persistence/model/RosterEntryModel.java b/persistence/src/main/java/org/mercury_im/messenger/persistence/model/ContactModel.java similarity index 70% rename from persistence/src/main/java/org/mercury_im/messenger/persistence/model/RosterEntryModel.java rename to persistence/src/main/java/org/mercury_im/messenger/persistence/model/ContactModel.java index a539305..1d8382d 100644 --- a/persistence/src/main/java/org/mercury_im/messenger/persistence/model/RosterEntryModel.java +++ b/persistence/src/main/java/org/mercury_im/messenger/persistence/model/ContactModel.java @@ -2,14 +2,16 @@ package org.mercury_im.messenger.persistence.model; import org.jxmpp.jid.EntityBareJid; -public interface RosterEntryModel { +public interface ContactModel { - long getId(); + long getAccountId(); - void setId(long id); + void setAccountId(long id); EntityBareJid getJid(); + void setJid(EntityBareJid jid); + String getRosterName(); void setRosterName(String rosterName); @@ -17,8 +19,4 @@ public interface RosterEntryModel { String getNickname(); void setNickname(String nickname); - - long getAccountId(); - - void setAccountId(long accountId); } diff --git a/persistence/src/main/java/org/mercury_im/messenger/persistence/model/MessageModel.java b/persistence/src/main/java/org/mercury_im/messenger/persistence/model/MessageModel.java index f1914b7..7795238 100644 --- a/persistence/src/main/java/org/mercury_im/messenger/persistence/model/MessageModel.java +++ b/persistence/src/main/java/org/mercury_im/messenger/persistence/model/MessageModel.java @@ -1,6 +1,6 @@ package org.mercury_im.messenger.persistence.model; -import org.jxmpp.jid.EntityFullJid; +import org.jxmpp.jid.EntityBareJid; import java.util.Date; @@ -22,11 +22,11 @@ public interface MessageModel { void setSendDate(Date date); - EntityFullJid getFrom(); + EntityBareJid getFrom(); - void setFrom(EntityFullJid sender); + void setFrom(EntityBareJid sender); - EntityFullJid getTo(); + EntityBareJid getTo(); - void setTo(EntityFullJid recipient); + void setTo(EntityBareJid recipient); } diff --git a/persistence/src/main/java/org/mercury_im/messenger/persistence/model/XmppIdentityModel.java b/persistence/src/main/java/org/mercury_im/messenger/persistence/model/XmppIdentityModel.java new file mode 100644 index 0000000..38ac1e8 --- /dev/null +++ b/persistence/src/main/java/org/mercury_im/messenger/persistence/model/XmppIdentityModel.java @@ -0,0 +1,40 @@ +package org.mercury_im.messenger.persistence.model; + +import androidx.annotation.NonNull; + +import org.jxmpp.jid.EntityBareJid; + +import java.io.File; + +/** + * An {@link XmppIdentityModel} represents an XMPP user as seen by an account. + * Its primary key should be composited of its {@link EntityBareJid} and the primary key of the + * {@link AccountModel} which is communicating with the user. + */ +public interface XmppIdentityModel { + + /** + * Return the JID of this identity. + * Should be part of the composited primary key. + * + * @return jid + */ + @NonNull + EntityBareJid getJid(); + + void setJid(EntityBareJid jid); + + /** + * Return the primary key of the account which is communicating with the + * {@link XmppIdentityModel}. + * + * @return accountId + */ + long getAccountId(); + + void setAccountId(long accountId); + + File getAvatarFile(); + + void setAvatarFile(File file); +} diff --git a/persistence/src/main/java/org/mercury_im/messenger/persistence/repository/AccountRepository.java b/persistence/src/main/java/org/mercury_im/messenger/persistence/repository/AccountRepository.java index 8edf448..62419f3 100644 --- a/persistence/src/main/java/org/mercury_im/messenger/persistence/repository/AccountRepository.java +++ b/persistence/src/main/java/org/mercury_im/messenger/persistence/repository/AccountRepository.java @@ -10,7 +10,9 @@ public interface AccountRepository { LiveData getAccount(long accountId); - LiveData> getAllAccounts(); + LiveData> getAllAccountsLive(); + + List getAllAccounts(); long insertAccount(E accountModel); } diff --git a/persistence/src/main/java/org/mercury_im/messenger/persistence/repository/ChatRepository.java b/persistence/src/main/java/org/mercury_im/messenger/persistence/repository/ChatRepository.java new file mode 100644 index 0000000..9e1dbe9 --- /dev/null +++ b/persistence/src/main/java/org/mercury_im/messenger/persistence/repository/ChatRepository.java @@ -0,0 +1,18 @@ +package org.mercury_im.messenger.persistence.repository; + +import androidx.lifecycle.LiveData; + +import org.mercury_im.messenger.persistence.model.ChatModel; +import org.mercury_im.messenger.persistence.model.ContactModel; +import org.mercury_im.messenger.persistence.model.XmppIdentityModel; + +import java.util.List; + +public interface ChatRepository { + + LiveData> getAllChats(); + + void getChatWith(XmppIdentityModel identity); + + void closeChat(ChatModel chat); +} diff --git a/persistence/src/main/java/org/mercury_im/messenger/persistence/repository/RosterEntryRepository.java b/persistence/src/main/java/org/mercury_im/messenger/persistence/repository/ContactRepository.java similarity index 62% rename from persistence/src/main/java/org/mercury_im/messenger/persistence/repository/RosterEntryRepository.java rename to persistence/src/main/java/org/mercury_im/messenger/persistence/repository/ContactRepository.java index c91f510..dff6450 100644 --- a/persistence/src/main/java/org/mercury_im/messenger/persistence/repository/RosterEntryRepository.java +++ b/persistence/src/main/java/org/mercury_im/messenger/persistence/repository/ContactRepository.java @@ -2,11 +2,11 @@ package org.mercury_im.messenger.persistence.repository; import androidx.lifecycle.LiveData; -import org.mercury_im.messenger.persistence.model.RosterEntryModel; +import org.mercury_im.messenger.persistence.model.ContactModel; import java.util.List; -public interface RosterEntryRepository { +public interface ContactRepository { LiveData> getAllRosterEntries(); diff --git a/persistence/src/main/java/org/mercury_im/messenger/persistence/repository/MessageRepository.java b/persistence/src/main/java/org/mercury_im/messenger/persistence/repository/MessageRepository.java index 6c1dbbf..35c605c 100644 --- a/persistence/src/main/java/org/mercury_im/messenger/persistence/repository/MessageRepository.java +++ b/persistence/src/main/java/org/mercury_im/messenger/persistence/repository/MessageRepository.java @@ -1,7 +1,20 @@ package org.mercury_im.messenger.persistence.repository; +import androidx.lifecycle.LiveData; + +import org.jxmpp.jid.EntityBareJid; +import org.jxmpp.jid.EntityFullJid; import org.mercury_im.messenger.persistence.model.MessageModel; +import java.util.List; + public interface MessageRepository { + long insertMessage(E message); + + LiveData> getAllMessagesOf(long accountId); + + LiveData> getAllMessagesFrom(long accountId, EntityBareJid contact); + + LiveData> findMessageByQuery(String query); } diff --git a/persistence/src/main/java/org/mercury_im/messenger/persistence/repository/XmppIdentityRepository.java b/persistence/src/main/java/org/mercury_im/messenger/persistence/repository/XmppIdentityRepository.java new file mode 100644 index 0000000..e663a26 --- /dev/null +++ b/persistence/src/main/java/org/mercury_im/messenger/persistence/repository/XmppIdentityRepository.java @@ -0,0 +1,12 @@ +package org.mercury_im.messenger.persistence.repository; + +import androidx.lifecycle.LiveData; + +import org.mercury_im.messenger.persistence.model.ContactModel; +import org.mercury_im.messenger.persistence.model.XmppIdentityModel; + +public interface XmppIdentityRepository { + + LiveData getIdentityOf(C contact); + +} diff --git a/settings.gradle b/settings.gradle index c9fd981..b17374e 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1 +1 @@ -include ':app', ':xmpp_core', ':persistence-room', ':persistence' +include ':app', ':xmpp_core', ':persistence-room', ':persistence', ':xmpp_android' diff --git a/version.gradle b/version.gradle index 14482b4..cbf10cf 100644 --- a/version.gradle +++ b/version.gradle @@ -38,6 +38,7 @@ ext { // Architecture Components lifecycleVersion = "2.0.0" roomVersion = "2.1.0-beta01" + pagingVersion = "2.1.0" // Dagger 2 daggerVersion = "2.17" diff --git a/xmpp_android/.gitignore b/xmpp_android/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/xmpp_android/.gitignore @@ -0,0 +1 @@ +/build diff --git a/xmpp_android/build.gradle b/xmpp_android/build.gradle new file mode 100644 index 0000000..032be9b --- /dev/null +++ b/xmpp_android/build.gradle @@ -0,0 +1,39 @@ +apply plugin: 'com.android.library' + +android { + compileSdkVersion 28 + + + defaultConfig { + minSdkVersion 19 + targetSdkVersion 28 + versionCode 1 + versionName "1.0" + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + +} + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + + api project(":xmpp_core") + + // Android related Smack libraries + api "org.igniterealtime.smack:smack-android:$smackAndroidVersion" + api "org.igniterealtime.smack:smack-android-extensions:$smackAndroidExtensionsVersion" + + implementation 'androidx.appcompat:appcompat:1.0.2' + testImplementation 'junit:junit:4.12' + androidTestImplementation 'androidx.test:runner:1.1.1' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' +} diff --git a/xmpp_android/proguard-rules.pro b/xmpp_android/proguard-rules.pro new file mode 100644 index 0000000..f1b4245 --- /dev/null +++ b/xmpp_android/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/xmpp_android/src/androidTest/java/org/mercury_im/messenger/xmpp_android/ExampleInstrumentedTest.java b/xmpp_android/src/androidTest/java/org/mercury_im/messenger/xmpp_android/ExampleInstrumentedTest.java new file mode 100644 index 0000000..ae33fbb --- /dev/null +++ b/xmpp_android/src/androidTest/java/org/mercury_im/messenger/xmpp_android/ExampleInstrumentedTest.java @@ -0,0 +1,27 @@ +package org.mercury_im.messenger.xmpp_android; + +import android.content.Context; + +import androidx.test.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.junit.Assert.*; + +/** + * Instrumented test, which will execute on an Android device. + * + * @see Testing documentation + */ +@RunWith(AndroidJUnit4.class) +public class ExampleInstrumentedTest { + @Test + public void useAppContext() { + // Context of the app under test. + Context appContext = InstrumentationRegistry.getTargetContext(); + + assertEquals("org.mercury_im.messenger.xmpp_android.test", appContext.getPackageName()); + } +} diff --git a/xmpp_android/src/main/AndroidManifest.xml b/xmpp_android/src/main/AndroidManifest.xml new file mode 100644 index 0000000..75e04bc --- /dev/null +++ b/xmpp_android/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + diff --git a/xmpp_android/src/main/java/org/mercury_im/messenger/xmpp_android/AndroidMercuryConnection.java b/xmpp_android/src/main/java/org/mercury_im/messenger/xmpp_android/AndroidMercuryConnection.java new file mode 100644 index 0000000..08a6a50 --- /dev/null +++ b/xmpp_android/src/main/java/org/mercury_im/messenger/xmpp_android/AndroidMercuryConnection.java @@ -0,0 +1,11 @@ +package org.mercury_im.messenger.xmpp_android; + +import org.jivesoftware.smack.XMPPConnection; +import org.mercury_im.messenger.xmpp_core.MercuryConnection; + +public class AndroidMercuryConnection extends MercuryConnection { + + public AndroidMercuryConnection(XMPPConnection connection, long accountId) { + super(connection, accountId); + } +} diff --git a/xmpp_android/src/main/java/org/mercury_im/messenger/xmpp_android/ParcelableXMPPTCPConnectionConfiguration.java b/xmpp_android/src/main/java/org/mercury_im/messenger/xmpp_android/ParcelableXMPPTCPConnectionConfiguration.java new file mode 100644 index 0000000..4178aeb --- /dev/null +++ b/xmpp_android/src/main/java/org/mercury_im/messenger/xmpp_android/ParcelableXMPPTCPConnectionConfiguration.java @@ -0,0 +1,86 @@ +package org.mercury_im.messenger.xmpp_android; + +import android.os.Parcel; +import android.os.Parcelable; + +import org.jivesoftware.smack.tcp.XMPPTCPConnectionConfiguration; +import org.jxmpp.stringprep.XmppStringprepException; + +public class ParcelableXMPPTCPConnectionConfiguration implements Parcelable { + + private final String username; + private final String password; + private final String xmppDomain; + private final String resourcePart; + private final String host; + private final int port; + + private XMPPTCPConnectionConfiguration configuration; + + public static final Creator CREATOR = new Creator() { + @Override + public ParcelableXMPPTCPConnectionConfiguration createFromParcel(Parcel in) { + return new ParcelableXMPPTCPConnectionConfiguration(in); + } + + @Override + public ParcelableXMPPTCPConnectionConfiguration[] newArray(int size) { + return new ParcelableXMPPTCPConnectionConfiguration[size]; + } + }; + + public ParcelableXMPPTCPConnectionConfiguration(String username, + String password, + String xmppDomain, + String resourcePart, + String host, + int port) { + this.username = username; + this.password = password; + this.xmppDomain = xmppDomain; + this.resourcePart = resourcePart; + this.host = host; + this.port = port; + } + + private ParcelableXMPPTCPConnectionConfiguration(Parcel in) { + this(in.readString(), // username + in.readString(), // password + in.readString(), // xmppDomain + in.readString(), // resourcePart + in.readString(), // host + in.readInt()); // port + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel parcel, int i) { + parcel.writeString(username); + parcel.writeString(password); + parcel.writeString(xmppDomain); + parcel.writeString(resourcePart); + parcel.writeString(host); + parcel.writeInt(port); + } + + public XMPPTCPConnectionConfiguration getConfiguration() throws XmppStringprepException { + if (configuration != null) { + return configuration; + } + + XMPPTCPConnectionConfiguration.Builder builder = XMPPTCPConnectionConfiguration.builder(); + + builder.setUsernameAndPassword(username, password); + if (xmppDomain != null) builder.setXmppDomain(xmppDomain); + if (resourcePart != null) builder.setResource(resourcePart); + if (host != null) builder.setHost(host); + if (port != -1) builder.setPort(port); + + configuration = builder.build(); + return configuration; + } +} diff --git a/xmpp_android/src/main/res/values/strings.xml b/xmpp_android/src/main/res/values/strings.xml new file mode 100644 index 0000000..15ade09 --- /dev/null +++ b/xmpp_android/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + XmppAndroid + diff --git a/xmpp_android/src/test/java/org/mercury_im/messenger/xmpp_android/ExampleUnitTest.java b/xmpp_android/src/test/java/org/mercury_im/messenger/xmpp_android/ExampleUnitTest.java new file mode 100644 index 0000000..c352d5a --- /dev/null +++ b/xmpp_android/src/test/java/org/mercury_im/messenger/xmpp_android/ExampleUnitTest.java @@ -0,0 +1,17 @@ +package org.mercury_im.messenger.xmpp_android; + +import org.junit.Test; + +import static org.junit.Assert.*; + +/** + * Example local unit test, which will execute on the development machine (host). + * + * @see Testing documentation + */ +public class ExampleUnitTest { + @Test + public void addition_isCorrect() { + assertEquals(4, 2 + 2); + } +} \ No newline at end of file diff --git a/xmpp_core/build.gradle b/xmpp_core/build.gradle index f423b31..1b50911 100644 --- a/xmpp_core/build.gradle +++ b/xmpp_core/build.gradle @@ -1,10 +1,9 @@ apply plugin: 'java-library' dependencies { + // Smack // Not all of those are needed, but it may be a good idea to define those versions explicitly - api "org.igniterealtime.smack:smack-android:$smackAndroidVersion" - api "org.igniterealtime.smack:smack-android-extensions:$smackAndroidExtensionsVersion" api "org.igniterealtime.smack:smack-core:$smackCoreVersion" api "org.igniterealtime.smack:smack-experimental:$smackExperimentalVersion" api "org.igniterealtime.smack:smack-extensions:$smackExtensionsVersion" diff --git a/xmpp_core/src/main/java/org/mercury_im/messenger/xmpp_core/ConnectionState.java b/xmpp_core/src/main/java/org/mercury_im/messenger/xmpp_core/ConnectionState.java new file mode 100644 index 0000000..536123e --- /dev/null +++ b/xmpp_core/src/main/java/org/mercury_im/messenger/xmpp_core/ConnectionState.java @@ -0,0 +1,43 @@ +package org.mercury_im.messenger.xmpp_core; + +/** + * {@link MercuryConnection} modeled as a finite state machine. + * Below enums represent the states of the machine. + */ +public enum ConnectionState { + + /** + * Connection is disconnected. + * This is the initial state of the machine. + */ + DISCONNECTED, + + /** + * The connection is in the process of connecting to the server. + * This state can be reached by issuing a connect() call from within the {@link #DISCONNECTED} + * state. + */ + CONNECTING, + + /** + * The connection is successfully connected to the server and the stream has been initiated. + * In this state the connection is ready to send and receive stanzas. + */ + CONNECTED, + + /** + * The connection is in the process of shutting down. + */ + DISCONNECTING, + + /** + * The device doesn't have usable network connectivity. + */ + WAITING_FOR_NETWORK, + + /** + * The connection already (unsuccessfully) tried to connect, but failed due to lack of network + * connectivity and is now waiting to retry connecting. + */ + WAIRING_FOR_RETRY +} diff --git a/xmpp_core/src/main/java/org/mercury_im/messenger/xmpp_core/MercuryConnection.java b/xmpp_core/src/main/java/org/mercury_im/messenger/xmpp_core/MercuryConnection.java new file mode 100644 index 0000000..5dd380b --- /dev/null +++ b/xmpp_core/src/main/java/org/mercury_im/messenger/xmpp_core/MercuryConnection.java @@ -0,0 +1,36 @@ +package org.mercury_im.messenger.xmpp_core; + +import org.jivesoftware.smack.XMPPConnection; +import org.jivesoftware.smack.roster.Roster; + +public class MercuryConnection { + + private final XMPPConnection connection; + private final long accountId; + private final Roster roster; + + public MercuryConnection(XMPPConnection connection, long accountId) { + this.connection = connection; + this.accountId = accountId; + + this.roster = Roster.getInstanceFor(connection); + roster.setRosterLoadedAtLogin(true); + } + + public XMPPConnection getConnection() { + return connection; + } + + public void setRosterHandler(RosterHandler handler) { + roster.addRosterListener(handler); + roster.addRosterLoadedListener(handler); + } + + public long getAccountId() { + return accountId; + } + + public Roster getRoster() { + return roster; + } +} diff --git a/xmpp_core/src/main/java/org/mercury_im/messenger/xmpp_core/RosterHandler.java b/xmpp_core/src/main/java/org/mercury_im/messenger/xmpp_core/RosterHandler.java new file mode 100644 index 0000000..1b54bd2 --- /dev/null +++ b/xmpp_core/src/main/java/org/mercury_im/messenger/xmpp_core/RosterHandler.java @@ -0,0 +1,8 @@ +package org.mercury_im.messenger.xmpp_core; + +import org.jivesoftware.smack.roster.RosterListener; +import org.jivesoftware.smack.roster.RosterLoadedListener; + +public interface RosterHandler extends RosterListener, RosterLoadedListener { + +} diff --git a/xmpp_core/src/main/java/org/mercury_im/xmpp_core/MercuryConnection.java b/xmpp_core/src/main/java/org/mercury_im/xmpp_core/MercuryConnection.java deleted file mode 100644 index 23b2ec5..0000000 --- a/xmpp_core/src/main/java/org/mercury_im/xmpp_core/MercuryConnection.java +++ /dev/null @@ -1,16 +0,0 @@ -package org.mercury_im.xmpp_core; - -import org.jivesoftware.smack.XMPPConnection; - -public class MercuryConnection { - - private final XMPPConnection connection; - - public MercuryConnection(XMPPConnection connection) { - this.connection = connection; - } - - public XMPPConnection getConnection() { - return connection; - } -}