Temp
This commit is contained in:
parent
b469f6de95
commit
35d7a7c473
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" project-jdk-name="JDK" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/classes" />
|
||||
</component>
|
||||
</project>
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.mercury_im.messenger">
|
||||
|
||||
<!-- To auto-complete the email text field in the login form with the user's emails -->
|
||||
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
|
||||
<uses-permission android:name="android.permission.READ_PROFILE" />
|
||||
|
@ -9,36 +10,37 @@
|
|||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
|
||||
<application
|
||||
android:name=".MercuryImApplication"
|
||||
android:allowBackup="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme"
|
||||
android:name="org.mercury_im.messenger.MercuryImApplication">
|
||||
<activity android:name="org.mercury_im.messenger.ui.chat.ChatActivity">
|
||||
android:theme="@style/AppTheme">
|
||||
<service
|
||||
android:name=".service.XmppBoundService"
|
||||
android:enabled="true"
|
||||
android:exported="false"></service>
|
||||
|
||||
</activity>
|
||||
<activity android:name=".ui.chat.ChatActivity"></activity>
|
||||
<activity
|
||||
android:name="org.mercury_im.messenger.ui.MainActivity"
|
||||
android:name=".ui.MainActivity"
|
||||
android:label="@string/title_activity_main"
|
||||
android:theme="@style/AppTheme.NoActionBar">
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
|
||||
</activity>
|
||||
<activity
|
||||
android:name="org.mercury_im.messenger.ui.settings.SettingsActivity"
|
||||
android:name=".ui.settings.SettingsActivity"
|
||||
android:label="@string/title_activity_settings" />
|
||||
<activity
|
||||
android:name="org.mercury_im.messenger.ui.login.LoginActivity"
|
||||
android:name=".ui.login.LoginActivity"
|
||||
android:label="@string/title_activity_login" />
|
||||
|
||||
<service android:name="org.mercury_im.messenger.service.XmppService" />
|
||||
<service android:name=".service.XmppStartedService" />
|
||||
</application>
|
||||
|
||||
</manifest>
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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<XMPPConnection> connections = new LongSparseArray<>();
|
||||
|
||||
private XmppConnectionHolder() {
|
||||
|
||||
}
|
||||
|
||||
public static XmppConnectionHolder getInstance() {
|
||||
if (INSTANCE == null) {
|
||||
INSTANCE = new XmppConnectionHolder();
|
||||
}
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
public LongSparseArray<XMPPConnection> getConnections() {
|
||||
return connections;
|
||||
}
|
||||
}
|
|
@ -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<XMPPConnection> 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<RosterEntry> 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);
|
||||
}
|
||||
}
|
|
@ -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<XMPPConnection> 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<RoomAccountModel> 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<RosterEntry> 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);
|
||||
}
|
||||
}
|
|
@ -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<List<RoomAccountModel>>() {
|
||||
accountRepository.getAllAccountsLive().observe(this, new Observer<List<AccountModel>>() {
|
||||
@Override
|
||||
public void onChanged(@Nullable List<RoomAccountModel> accountModels) {
|
||||
public void onChanged(@Nullable List<AccountModel> 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<RoomRosterEntryModel, Void, Void> {
|
||||
private static class addRosterEntry extends AsyncTask<RoomContactModel, Void, Void> {
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
package org.mercury_im.messenger.ui.chatlist;
|
||||
|
||||
import androidx.lifecycle.ViewModel;
|
||||
|
||||
public class ChatListViewModel extends ViewModel {
|
||||
|
||||
}
|
|
@ -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<? extends AccountModel> 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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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<List<RoomRosterEntryModel>>() {
|
||||
viewModel.getRosterEntryList().observe(this, new Observer<List<RoomContactModel>>() {
|
||||
@Override
|
||||
public void onChanged(@Nullable List<RoomRosterEntryModel> rosterEntries) {
|
||||
public void onChanged(@Nullable List<RoomContactModel> rosterEntries) {
|
||||
if (rosterEntries == null) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -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<RosterRecyclerViewAdapter.RecyclerViewHolder> {
|
||||
|
||||
private List<RoomRosterEntryModel> entryModelList;
|
||||
private List<RoomContactModel> entryModelList;
|
||||
|
||||
public RosterRecyclerViewAdapter(List<RoomRosterEntryModel> entryModelList) {
|
||||
public RosterRecyclerViewAdapter(List<RoomContactModel> 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<RoomRosterEntryModel> rosterEntryModels) {
|
||||
public void setItems(List<RoomContactModel> rosterEntryModels) {
|
||||
this.entryModelList = rosterEntryModels;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
|
|
@ -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<List<RoomRosterEntryModel>> rosterEntryList;
|
||||
private final LiveData<List<RoomContactModel>> rosterEntryList;
|
||||
|
||||
@Inject
|
||||
public RosterViewModel(@NonNull Application application) {
|
||||
super(application);
|
||||
MercuryImApplication.getApplication().getAppComponent().inject(this);
|
||||
this.rosterEntryList = rosterEntryRepository.getAllRosterEntries();
|
||||
this.rosterEntryList = contactRepository.getAllRosterEntries();
|
||||
}
|
||||
|
||||
public LiveData<List<RoomRosterEntryModel>> getRosterEntryList() {
|
||||
public LiveData<List<RoomContactModel>> getRosterEntryList() {
|
||||
return rosterEntryList;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<Jid> addresses) {
|
||||
for (Jid j : addresses) {
|
||||
RosterEntry entry = roster.getEntry(j.asBareJid());
|
||||
// ContactModel
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void entriesUpdated(Collection<Jid> addresses) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void entriesDeleted(Collection<Jid> 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);
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/chat"
|
||||
|
|
|
@ -7,43 +7,37 @@
|
|||
android:orientation="horizontal"
|
||||
android:background="@null">
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/chat_field__fab_add"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:scaleType="center"
|
||||
app:fabSize="normal"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintVertical_bias="1.0"
|
||||
app:srcCompat="@drawable/ic_add_white_24dp" />
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
xmlns:card_view="http://schemas.android.com/apk/res-auto"
|
||||
<androidx.cardview.widget.CardView xmlns:card_view="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
app:cardUseCompatPadding="true"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@+id/chat_field__fab_add"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
card_view:cardCornerRadius="28dp"
|
||||
card_view:cardElevation="6dp"
|
||||
app:cardUseCompatPadding="true">
|
||||
card_view:layout_constraintStart_toStartOf="parent">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:minHeight="56dp">
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageButton
|
||||
android:id="@+id/chat_field__button_attachment"
|
||||
android:layout_width="56dp"
|
||||
android:layout_height="56dp"
|
||||
android:background="@null"
|
||||
android:tint="?attr/colorAccent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:srcCompat="@drawable/ic_add_white_24dp" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/chat_field__text_input"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
|
@ -51,7 +45,7 @@
|
|||
android:maxLines="6"
|
||||
card_view:layout_constraintBottom_toBottomOf="parent"
|
||||
card_view:layout_constraintEnd_toStartOf="@+id/chat_field__button_send"
|
||||
card_view:layout_constraintStart_toStartOf="parent"
|
||||
card_view:layout_constraintStart_toEndOf="@+id/chat_field__button_attachment"
|
||||
card_view:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="Open Protocols!" />
|
||||
|
||||
|
@ -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" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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\")"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -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<List<RoomAccountModel>> 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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -28,7 +28,12 @@ public interface AccountDao extends BaseDao<RoomAccountModel> {
|
|||
* @return live updating account list
|
||||
*/
|
||||
@Query("select * from accounts")
|
||||
LiveData<List<RoomAccountModel>> getAllAccounts();
|
||||
LiveData<List<RoomAccountModel>> getAllAccountsLive();
|
||||
|
||||
@Query("select * from accounts")
|
||||
List<RoomAccountModel> getAllAccounts();
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Return the {@link RoomAccountModel Account} which is identified by the given id.
|
||||
|
|
|
@ -10,8 +10,8 @@ public interface BaseDao<T> {
|
|||
long insert(T entity);
|
||||
|
||||
@Update
|
||||
void update(T entity);
|
||||
void upddate(T... entity);
|
||||
|
||||
@Delete
|
||||
void delete(T entity);
|
||||
void delete(T... entity);
|
||||
}
|
||||
|
|
|
@ -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<RoomChatModel> {
|
||||
|
||||
@Query("SELECT * FROM RoomChatModel")
|
||||
LiveData<List<RoomChatModel>> getAllChats();
|
||||
|
||||
@Query("SELECT * FROM RoomChatModel WHERE ")
|
||||
LiveData<RoomChatModel> getChatWith(EntityBareJid contact);
|
||||
|
||||
|
||||
}
|
|
@ -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<RoomContactModel> {
|
||||
|
||||
/**
|
||||
* 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<List<RoomContactModel>> getAllRosterEntries();
|
||||
|
||||
@Query("select * from RoomContactModel where jid = :jid")
|
||||
RoomContactModel getRosterEntryByJid(EntityBareJid jid);
|
||||
|
||||
@Query("select * from RoomContactModel where accountId = :accountId")
|
||||
LiveData<List<RoomContactModel>> getRosterEntriesForAccount(long accountId);
|
||||
}
|
|
@ -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<RoomRosterEntryModel> {
|
||||
|
||||
/**
|
||||
* 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<List<RoomRosterEntryModel>> getAllRosterEntries();
|
||||
|
||||
@Query("select * from roster where id = :id")
|
||||
RoomRosterEntryModel getRosterEntryById(long id);
|
||||
|
||||
@Query("select * from roster where accountId = :accountId")
|
||||
LiveData<List<RoomRosterEntryModel>> getRosterEntriesForAccount(long accountId);
|
||||
}
|
|
@ -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<ContactModel> getContact() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LiveData<PagedList<MessageModel>> getMessages() {
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -28,10 +28,16 @@ public class IAccountRepository implements AccountRepository<RoomAccountModel> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public LiveData<List<RoomAccountModel>> getAllAccounts() {
|
||||
public LiveData<List<RoomAccountModel>> getAllAccountsLive() {
|
||||
return accountDao.getAllAccountsLive();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<RoomAccountModel> getAllAccounts() {
|
||||
return accountDao.getAllAccounts();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public long insertAccount(RoomAccountModel accountModel) {
|
||||
InsertAsyncTask task = new InsertAsyncTask(accountDao);
|
||||
|
|
|
@ -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 {
|
||||
|
||||
}
|
|
@ -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<RoomContactModel> {
|
||||
|
||||
private final ContactDao contactDao;
|
||||
|
||||
public IContactRepository(ContactDao dao) {
|
||||
this.contactDao = dao;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LiveData<List<RoomContactModel>> getAllRosterEntries() {
|
||||
return contactDao.getAllRosterEntries();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateOrInsertRosterEntry(RoomContactModel rosterEntryModel) {
|
||||
contactDao.insert(rosterEntryModel);
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -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<RoomMessageModel> {
|
||||
|
||||
private final MessageDao messageDao;
|
||||
|
||||
public IMessageRepository(MessageDao messageDao) {
|
||||
this.messageDao = messageDao;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long insertMessage(RoomMessageModel message) {
|
||||
return messageDao.insert(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LiveData<List<RoomMessageModel>> getAllMessagesOf(long accountId) {
|
||||
return messageDao.getAllMessagesOf(accountId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LiveData<List<RoomMessageModel>> getAllMessagesFrom(long accountId, EntityFullJid contact) {
|
||||
return messageDao.getAllMessagesFrom(accountId, contact);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<RoomRosterEntryModel> {
|
||||
|
||||
private final RosterEntryDao rosterEntryDao;
|
||||
|
||||
public IRosterEntryRepository(RosterEntryDao dao) {
|
||||
this.rosterEntryDao = dao;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LiveData<List<RoomRosterEntryModel>> getAllRosterEntries() {
|
||||
return rosterEntryDao.getAllRosterEntries();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateOrInsertRosterEntry(RoomRosterEntryModel rosterEntryModel) {
|
||||
rosterEntryDao.insert(rosterEntryModel);
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -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"
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -10,7 +10,9 @@ public interface AccountRepository<E extends AccountModel> {
|
|||
|
||||
LiveData<E> getAccount(long accountId);
|
||||
|
||||
LiveData<List<E>> getAllAccounts();
|
||||
LiveData<List<E>> getAllAccountsLive();
|
||||
|
||||
List<E> getAllAccounts();
|
||||
|
||||
long insertAccount(E accountModel);
|
||||
}
|
||||
|
|
|
@ -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<List<ChatModel>> getAllChats();
|
||||
|
||||
void getChatWith(XmppIdentityModel identity);
|
||||
|
||||
void closeChat(ChatModel chat);
|
||||
}
|
|
@ -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<E extends RosterEntryModel> {
|
||||
public interface ContactRepository<E extends ContactModel> {
|
||||
|
||||
LiveData<List<E>> getAllRosterEntries();
|
||||
|
|
@ -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<E extends MessageModel> {
|
||||
|
||||
long insertMessage(E message);
|
||||
|
||||
LiveData<List<E>> getAllMessagesOf(long accountId);
|
||||
|
||||
LiveData<List<E>> getAllMessagesFrom(long accountId, EntityBareJid contact);
|
||||
|
||||
LiveData<List<E>> findMessageByQuery(String query);
|
||||
}
|
||||
|
|
|
@ -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<E extends XmppIdentityModel> {
|
||||
|
||||
<C extends ContactModel> LiveData<E> getIdentityOf(C contact);
|
||||
|
||||
}
|
|
@ -1 +1 @@
|
|||
include ':app', ':xmpp_core', ':persistence-room', ':persistence'
|
||||
include ':app', ':xmpp_core', ':persistence-room', ':persistence', ':xmpp_android'
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
/build
|
|
@ -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'
|
||||
}
|
|
@ -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
|
|
@ -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 <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||
*/
|
||||
@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());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.mercury_im.messenger.xmpp_android" />
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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<ParcelableXMPPTCPConnectionConfiguration> CREATOR = new Creator<ParcelableXMPPTCPConnectionConfiguration>() {
|
||||
@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;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
<resources>
|
||||
<string name="app_name">XmppAndroid</string>
|
||||
</resources>
|
|
@ -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 <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||
*/
|
||||
public class ExampleUnitTest {
|
||||
@Test
|
||||
public void addition_isCorrect() {
|
||||
assertEquals(4, 2 + 2);
|
||||
}
|
||||
}
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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 {
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue