mirror of
https://codeberg.org/Mercury-IM/Mercury-IM
synced 2025-04-28 02:44:48 +02:00
Temp
This commit is contained in:
parent
184c0777c1
commit
0b27a66dcd
27 changed files with 542 additions and 170 deletions
|
@ -72,7 +72,7 @@ check.configure {
|
|||
// Dependency versions are located in version.gradle
|
||||
dependencies {
|
||||
|
||||
implementation project(":xmpp_android")
|
||||
implementation(project(':xmpp_core'))
|
||||
implementation(project(':persistence-room')) {
|
||||
transitive = true
|
||||
}
|
||||
|
@ -104,4 +104,6 @@ dependencies {
|
|||
|
||||
// circular image viewer for avatars
|
||||
implementation 'de.hdodenhof:circleimageview:2.2.0'
|
||||
|
||||
implementation "org.igniterealtime.smack:smack-android-extensions:$smackAndroidExtensionsVersion"
|
||||
}
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
package org.mercury_im.messenger;
|
||||
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
|
||||
import org.jivesoftware.smack.XMPPConnection;
|
||||
import org.jivesoftware.smack.tcp.XMPPTCPConnection;
|
||||
import org.mercury_im.messenger.xmpp_core.ConnectionState;
|
||||
import org.mercury_im.messenger.xmpp_core.MercuryConnection;
|
||||
|
||||
public class AndroidMercuryConnection extends MercuryConnection {
|
||||
|
||||
private MutableLiveData<ConnectionState> connectionState = new MutableLiveData<>();
|
||||
|
||||
public AndroidMercuryConnection(XMPPTCPConnection connection, long accountId) {
|
||||
super(connection, accountId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connected(XMPPConnection connection) {
|
||||
super.connected(connection);
|
||||
connectionState.postValue(ConnectionState.CONNECTED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void authenticated(XMPPConnection connection, boolean resumed) {
|
||||
super.authenticated(connection, resumed);
|
||||
connectionState.postValue(ConnectionState.CONNECTED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connectionClosed() {
|
||||
super.connectionClosed();
|
||||
connectionState.postValue(ConnectionState.DISCONNECTED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connectionClosedOnError(Exception e) {
|
||||
super.connectionClosedOnError(e);
|
||||
connectionState.postValue(ConnectionState.WAIRING_FOR_RETRY);
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package org.mercury_im.messenger.xmpp_android;
|
||||
package org.mercury_im.messenger;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
|
@ -12,6 +12,8 @@ import android.util.LongSparseArray;
|
|||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.app.NotificationCompat;
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
|
||||
import org.jivesoftware.smack.SmackException;
|
||||
import org.jivesoftware.smack.XMPPConnection;
|
||||
|
@ -20,6 +22,7 @@ import org.jivesoftware.smack.tcp.XMPPTCPConnection;
|
|||
import org.jivesoftware.smack.tcp.XMPPTCPConnectionConfiguration;
|
||||
import org.jivesoftware.smackx.ping.android.ServerPingWithAlarmManager;
|
||||
import org.jxmpp.stringprep.XmppStringprepException;
|
||||
import org.mercury_im.messenger.AndroidMercuryConnection;
|
||||
import org.mercury_im.messenger.MercuryImApplication;
|
||||
import org.mercury_im.messenger.Notifications;
|
||||
import org.mercury_im.messenger.R;
|
||||
|
@ -32,8 +35,8 @@ import org.mercury_im.messenger.persistence.repository.EntityRepository;
|
|||
import org.mercury_im.messenger.persistence.room.dao.ContactDao;
|
||||
import org.mercury_im.messenger.persistence.room.dao.EntityDao;
|
||||
import org.mercury_im.messenger.ui.MainActivity;
|
||||
import org.mercury_im.messenger.xmpp_android.AndroidMercuryConnection;
|
||||
import org.mercury_im.messenger.xmpp_core.ConnectionHolder;
|
||||
import org.mercury_im.messenger.xmpp_core.ConnectionState;
|
||||
import org.mercury_im.messenger.xmpp_core.MercuryConnection;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -45,7 +48,7 @@ import javax.inject.Inject;
|
|||
* Started, Bound Service, which is responsible for managing {@link XMPPConnection XMPPConnections}
|
||||
* affiliated with registered accounts.
|
||||
*/
|
||||
public class XmppConnectionService extends Service implements ConnectionHolder {
|
||||
public class XmppConnectionService extends Service implements ConnectionHolder, MercuryConnection.ConnectionStateListener {
|
||||
|
||||
private static final String TAG = MercuryImApplication.TAG;
|
||||
|
||||
|
@ -142,6 +145,7 @@ public class XmppConnectionService extends Service implements ConnectionHolder {
|
|||
@Override
|
||||
public void putConnection(long accountId, MercuryConnection connection) {
|
||||
connections.put(accountId, connection);
|
||||
connection.setConnectionStateListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -230,6 +234,11 @@ public class XmppConnectionService extends Service implements ConnectionHolder {
|
|||
}.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stateChanged(MercuryConnection connection, ConnectionState state) {
|
||||
accountRepository.updateState(connection.getAccountId(), state.toString());
|
||||
}
|
||||
|
||||
public class Binder extends android.os.Binder {
|
||||
|
||||
private final XmppConnectionService service;
|
||||
|
|
|
@ -12,10 +12,12 @@ 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.repository.AccountRepository;
|
||||
import org.mercury_im.messenger.service.XmppConnectionService;
|
||||
import org.mercury_im.messenger.ui.BindingActivity;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
public class AccountsActivity extends FragmentActivity implements AccountsFragment.OnListFragmentInteractionListener {
|
||||
public class AccountsActivity extends BindingActivity implements AccountsFragment.OnListFragmentInteractionListener {
|
||||
|
||||
@Inject
|
||||
AccountRepository accountRepository;
|
||||
|
@ -42,4 +44,13 @@ public class AccountsActivity extends FragmentActivity implements AccountsFragme
|
|||
});
|
||||
builder.create().show();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onServiceBound() {
|
||||
super.onServiceBound();
|
||||
}
|
||||
|
||||
public XmppConnectionService getConnectionService() {
|
||||
return connectionService;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,11 +3,13 @@ package org.mercury_im.messenger.ui.login;
|
|||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.util.LongSparseArray;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.lifecycle.Observer;
|
||||
import androidx.lifecycle.ViewModelProviders;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
@ -15,6 +17,8 @@ import androidx.recyclerview.widget.RecyclerView;
|
|||
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.service.XmppConnectionService;
|
||||
import org.mercury_im.messenger.xmpp_core.ConnectionState;
|
||||
|
||||
/**
|
||||
* A fragment representing a list of Items.
|
||||
|
@ -30,6 +34,8 @@ public class AccountsFragment extends Fragment {
|
|||
|
||||
private AccountsRecyclerViewAdapter adapter;
|
||||
|
||||
private RecyclerView recyclerView;
|
||||
|
||||
/**
|
||||
* Mandatory empty constructor for the fragment manager to instantiate the
|
||||
* fragment (e.g. upon screen orientation changes).
|
||||
|
@ -58,8 +64,8 @@ public class AccountsFragment extends Fragment {
|
|||
|
||||
// Set the adapter
|
||||
if (view instanceof RecyclerView) {
|
||||
recyclerView = (RecyclerView) view;
|
||||
Context context = view.getContext();
|
||||
RecyclerView recyclerView = (RecyclerView) view;
|
||||
recyclerView.setLayoutManager(new LinearLayoutManager(context));
|
||||
this.adapter = new AccountsRecyclerViewAdapter(viewModel.getAccounts().getValue(), mListener);
|
||||
viewModel.getAccounts().observe(this, roomAccountModels -> adapter.setValues(roomAccountModels));
|
||||
|
|
|
@ -43,6 +43,7 @@ public class AccountsRecyclerViewAdapter extends RecyclerView.Adapter<AccountsRe
|
|||
holder.jid.setText(account.getJid());
|
||||
holder.enabled.setChecked(account.getEnabled());
|
||||
holder.accountModel = account;
|
||||
holder.status.setText(account.getState());
|
||||
holder.mView.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
|
@ -75,6 +76,7 @@ public class AccountsRecyclerViewAdapter extends RecyclerView.Adapter<AccountsRe
|
|||
public final CircleImageView avatar;
|
||||
public final TextView jid;
|
||||
public final Switch enabled;
|
||||
public final TextView status;
|
||||
|
||||
public ViewHolder(View view) {
|
||||
super(view);
|
||||
|
@ -82,6 +84,7 @@ public class AccountsRecyclerViewAdapter extends RecyclerView.Adapter<AccountsRe
|
|||
avatar = view.findViewById(R.id.avatar_account);
|
||||
jid = view.findViewById(R.id.text_account_jid);
|
||||
enabled = view.findViewById(R.id.switch_account_enabled);
|
||||
status = view.findViewById(R.id.text_account_status);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ import org.mercury_im.messenger.persistence.model.AccountModel;
|
|||
import org.mercury_im.messenger.persistence.repository.AccountRepository;
|
||||
import org.mercury_im.messenger.persistence.room.model.RoomAccountModel;
|
||||
import org.mercury_im.messenger.ui.BindingActivity;
|
||||
import org.mercury_im.messenger.xmpp_android.AndroidMercuryConnection;
|
||||
import org.mercury_im.messenger.AndroidMercuryConnection;
|
||||
import org.mercury_im.messenger.xmpp_core.MercuryConnection;
|
||||
|
||||
import java.io.IOException;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"formatVersion": 1,
|
||||
"database": {
|
||||
"version": 1,
|
||||
"identityHash": "c54702e8cd69b3410ca84bab6d4d3aa6",
|
||||
"identityHash": "1149b7d295726ec2043486e660dcf75d",
|
||||
"entities": [
|
||||
{
|
||||
"tableName": "contacts",
|
||||
|
@ -107,7 +107,7 @@
|
|||
},
|
||||
{
|
||||
"tableName": "accounts",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`pk_account_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `jid` TEXT, `password` TEXT, `enabled` INTEGER NOT NULL)",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`pk_account_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `jid` TEXT, `password` TEXT, `enabled` INTEGER NOT NULL, `state` TEXT)",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
|
@ -132,6 +132,12 @@
|
|||
"columnName": "enabled",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "state",
|
||||
"columnName": "state",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
|
@ -370,7 +376,7 @@
|
|||
"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, 'c54702e8cd69b3410ca84bab6d4d3aa6')"
|
||||
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '1149b7d295726ec2043486e660dcf75d')"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,382 @@
|
|||
{
|
||||
"formatVersion": 1,
|
||||
"database": {
|
||||
"version": 2,
|
||||
"identityHash": "1149b7d295726ec2043486e660dcf75d",
|
||||
"entities": [
|
||||
{
|
||||
"tableName": "contacts",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`pk_contact_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `fk_account_id` INTEGER NOT NULL, `fk_entity_id` INTEGER NOT NULL, `rostername` TEXT, `nickname` TEXT, FOREIGN KEY(`fk_account_id`) REFERENCES `accounts`(`pk_account_id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`fk_entity_id`) REFERENCES `entities`(`pk_entity_id`) ON UPDATE NO ACTION ON DELETE RESTRICT )",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "pk_contact_id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "accountId",
|
||||
"columnName": "fk_account_id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "entityId",
|
||||
"columnName": "fk_entity_id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "rosterName",
|
||||
"columnName": "rostername",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "nickname",
|
||||
"columnName": "nickname",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"columnNames": [
|
||||
"pk_contact_id"
|
||||
],
|
||||
"autoGenerate": true
|
||||
},
|
||||
"indices": [
|
||||
{
|
||||
"name": "index_contacts_pk_contact_id",
|
||||
"unique": false,
|
||||
"columnNames": [
|
||||
"pk_contact_id"
|
||||
],
|
||||
"createSql": "CREATE INDEX `index_contacts_pk_contact_id` ON `${TABLE_NAME}` (`pk_contact_id`)"
|
||||
},
|
||||
{
|
||||
"name": "index_contacts_fk_account_id",
|
||||
"unique": false,
|
||||
"columnNames": [
|
||||
"fk_account_id"
|
||||
],
|
||||
"createSql": "CREATE INDEX `index_contacts_fk_account_id` ON `${TABLE_NAME}` (`fk_account_id`)"
|
||||
},
|
||||
{
|
||||
"name": "index_contacts_fk_entity_id",
|
||||
"unique": false,
|
||||
"columnNames": [
|
||||
"fk_entity_id"
|
||||
],
|
||||
"createSql": "CREATE INDEX `index_contacts_fk_entity_id` ON `${TABLE_NAME}` (`fk_entity_id`)"
|
||||
},
|
||||
{
|
||||
"name": "index_contacts_pk_contact_id_fk_entity_id",
|
||||
"unique": true,
|
||||
"columnNames": [
|
||||
"pk_contact_id",
|
||||
"fk_entity_id"
|
||||
],
|
||||
"createSql": "CREATE UNIQUE INDEX `index_contacts_pk_contact_id_fk_entity_id` ON `${TABLE_NAME}` (`pk_contact_id`, `fk_entity_id`)"
|
||||
}
|
||||
],
|
||||
"foreignKeys": [
|
||||
{
|
||||
"table": "accounts",
|
||||
"onDelete": "CASCADE",
|
||||
"onUpdate": "NO ACTION",
|
||||
"columns": [
|
||||
"fk_account_id"
|
||||
],
|
||||
"referencedColumns": [
|
||||
"pk_account_id"
|
||||
]
|
||||
},
|
||||
{
|
||||
"table": "entities",
|
||||
"onDelete": "RESTRICT",
|
||||
"onUpdate": "NO ACTION",
|
||||
"columns": [
|
||||
"fk_entity_id"
|
||||
],
|
||||
"referencedColumns": [
|
||||
"pk_entity_id"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"tableName": "accounts",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`pk_account_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `jid` TEXT, `password` TEXT, `enabled` INTEGER NOT NULL, `state` TEXT)",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "pk_account_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
|
||||
},
|
||||
{
|
||||
"fieldPath": "state",
|
||||
"columnName": "state",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"columnNames": [
|
||||
"pk_account_id"
|
||||
],
|
||||
"autoGenerate": true
|
||||
},
|
||||
"indices": [
|
||||
{
|
||||
"name": "index_accounts_pk_account_id",
|
||||
"unique": false,
|
||||
"columnNames": [
|
||||
"pk_account_id"
|
||||
],
|
||||
"createSql": "CREATE INDEX `index_accounts_pk_account_id` ON `${TABLE_NAME}` (`pk_account_id`)"
|
||||
}
|
||||
],
|
||||
"foreignKeys": []
|
||||
},
|
||||
{
|
||||
"tableName": "chats",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`pk_chat_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `fk_entity_id` INTEGER NOT NULL, `active` INTEGER NOT NULL, FOREIGN KEY(`fk_entity_id`) REFERENCES `entities`(`pk_entity_id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "pk_chat_id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "peerEntityId",
|
||||
"columnName": "fk_entity_id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "isActive",
|
||||
"columnName": "active",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"columnNames": [
|
||||
"pk_chat_id"
|
||||
],
|
||||
"autoGenerate": true
|
||||
},
|
||||
"indices": [
|
||||
{
|
||||
"name": "index_chats_pk_chat_id",
|
||||
"unique": false,
|
||||
"columnNames": [
|
||||
"pk_chat_id"
|
||||
],
|
||||
"createSql": "CREATE INDEX `index_chats_pk_chat_id` ON `${TABLE_NAME}` (`pk_chat_id`)"
|
||||
},
|
||||
{
|
||||
"name": "index_chats_fk_entity_id",
|
||||
"unique": false,
|
||||
"columnNames": [
|
||||
"fk_entity_id"
|
||||
],
|
||||
"createSql": "CREATE INDEX `index_chats_fk_entity_id` ON `${TABLE_NAME}` (`fk_entity_id`)"
|
||||
}
|
||||
],
|
||||
"foreignKeys": [
|
||||
{
|
||||
"table": "entities",
|
||||
"onDelete": "CASCADE",
|
||||
"onUpdate": "NO ACTION",
|
||||
"columns": [
|
||||
"fk_entity_id"
|
||||
],
|
||||
"referencedColumns": [
|
||||
"pk_entity_id"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"tableName": "messages",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`pk_message_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `fk_account_id` INTEGER NOT NULL, `body` TEXT, `send_date` INTEGER, `from` TEXT, `to` TEXT, `incoming` INTEGER NOT NULL, FOREIGN KEY(`fk_account_id`) REFERENCES `accounts`(`pk_account_id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "pk_message_id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "accountId",
|
||||
"columnName": "fk_account_id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "body",
|
||||
"columnName": "body",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "sendDate",
|
||||
"columnName": "send_date",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "from",
|
||||
"columnName": "from",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "to",
|
||||
"columnName": "to",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "incoming",
|
||||
"columnName": "incoming",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"columnNames": [
|
||||
"pk_message_id"
|
||||
],
|
||||
"autoGenerate": true
|
||||
},
|
||||
"indices": [
|
||||
{
|
||||
"name": "index_messages_pk_message_id",
|
||||
"unique": false,
|
||||
"columnNames": [
|
||||
"pk_message_id"
|
||||
],
|
||||
"createSql": "CREATE INDEX `index_messages_pk_message_id` ON `${TABLE_NAME}` (`pk_message_id`)"
|
||||
},
|
||||
{
|
||||
"name": "index_messages_fk_account_id",
|
||||
"unique": false,
|
||||
"columnNames": [
|
||||
"fk_account_id"
|
||||
],
|
||||
"createSql": "CREATE INDEX `index_messages_fk_account_id` ON `${TABLE_NAME}` (`fk_account_id`)"
|
||||
}
|
||||
],
|
||||
"foreignKeys": [
|
||||
{
|
||||
"table": "accounts",
|
||||
"onDelete": "CASCADE",
|
||||
"onUpdate": "NO ACTION",
|
||||
"columns": [
|
||||
"fk_account_id"
|
||||
],
|
||||
"referencedColumns": [
|
||||
"pk_account_id"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"tableName": "entities",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`pk_entity_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `fk_account_id` INTEGER NOT NULL, `jid` TEXT NOT NULL, `avatar` TEXT, FOREIGN KEY(`fk_account_id`) REFERENCES `accounts`(`pk_account_id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "pk_entity_id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "accountId",
|
||||
"columnName": "fk_account_id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "jid",
|
||||
"columnName": "jid",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "avatarFile",
|
||||
"columnName": "avatar",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"columnNames": [
|
||||
"pk_entity_id"
|
||||
],
|
||||
"autoGenerate": true
|
||||
},
|
||||
"indices": [
|
||||
{
|
||||
"name": "index_entities_pk_entity_id",
|
||||
"unique": false,
|
||||
"columnNames": [
|
||||
"pk_entity_id"
|
||||
],
|
||||
"createSql": "CREATE INDEX `index_entities_pk_entity_id` ON `${TABLE_NAME}` (`pk_entity_id`)"
|
||||
},
|
||||
{
|
||||
"name": "index_entities_fk_account_id_jid",
|
||||
"unique": true,
|
||||
"columnNames": [
|
||||
"fk_account_id",
|
||||
"jid"
|
||||
],
|
||||
"createSql": "CREATE UNIQUE INDEX `index_entities_fk_account_id_jid` ON `${TABLE_NAME}` (`fk_account_id`, `jid`)"
|
||||
}
|
||||
],
|
||||
"foreignKeys": [
|
||||
{
|
||||
"table": "accounts",
|
||||
"onDelete": "CASCADE",
|
||||
"onUpdate": "NO ACTION",
|
||||
"columns": [
|
||||
"fk_account_id"
|
||||
],
|
||||
"referencedColumns": [
|
||||
"pk_account_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, '1149b7d295726ec2043486e660dcf75d')"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -2,9 +2,12 @@ package org.mercury_im.messenger.persistence.room;
|
|||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.room.Database;
|
||||
import androidx.room.Room;
|
||||
import androidx.room.RoomDatabase;
|
||||
import androidx.room.migration.Migration;
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase;
|
||||
|
||||
import org.mercury_im.messenger.persistence.room.dao.AccountDao;
|
||||
import org.mercury_im.messenger.persistence.room.dao.ChatDao;
|
||||
|
@ -18,7 +21,7 @@ import org.mercury_im.messenger.persistence.room.model.RoomContactModel;
|
|||
import org.mercury_im.messenger.persistence.room.model.RoomEntityModel;
|
||||
import org.mercury_im.messenger.persistence.room.model.RoomMessageModel;
|
||||
|
||||
@Database(version = 1,
|
||||
@Database(version = 2,
|
||||
entities = {
|
||||
RoomContactModel.class,
|
||||
RoomAccountModel.class,
|
||||
|
@ -31,10 +34,19 @@ public abstract class AppDatabase extends RoomDatabase {
|
|||
private static final String DB_NAME = "mercury_db";
|
||||
private static AppDatabase INSTANCE;
|
||||
|
||||
static Migration m1_2 = new Migration(1, 2) {
|
||||
@Override
|
||||
public void migrate(@NonNull SupportSQLiteDatabase database) {
|
||||
database.execSQL("ALTER TABLE accounts ADD COLUMN state TEXT");
|
||||
}
|
||||
};
|
||||
|
||||
public static AppDatabase getDatabase(final Context context) {
|
||||
if (INSTANCE == null) {
|
||||
INSTANCE = Room.databaseBuilder(context.getApplicationContext(),
|
||||
AppDatabase.class, DB_NAME).build();
|
||||
AppDatabase.class, DB_NAME)
|
||||
.addMigrations(m1_2)
|
||||
.build();
|
||||
}
|
||||
return INSTANCE;
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import androidx.room.Dao;
|
|||
import androidx.room.Delete;
|
||||
import androidx.room.Insert;
|
||||
import androidx.room.Query;
|
||||
import androidx.room.Transaction;
|
||||
import androidx.room.TypeConverters;
|
||||
import androidx.room.Update;
|
||||
|
||||
|
@ -46,4 +47,7 @@ public interface AccountDao extends BaseDao<RoomAccountModel> {
|
|||
|
||||
@Query("select * from accounts where jid = :jid")
|
||||
LiveData<RoomAccountModel> getAccountByJid(EntityBareJid jid);
|
||||
|
||||
@Query("update accounts set state = :state where pk_account_id = :accountId")
|
||||
void updateConnectionState(long accountId, String state);
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ public class RoomAccountModel implements AccountModel {
|
|||
public static final String KEY_JID = "jid";
|
||||
public static final String KEY_PASSWORD = "password";
|
||||
public static final String KEY_ENABLED = "enabled";
|
||||
public static final String KEY_STATE = "state";
|
||||
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
@ColumnInfo(name = KEY_ID)
|
||||
|
@ -37,6 +38,9 @@ public class RoomAccountModel implements AccountModel {
|
|||
@ColumnInfo(name = KEY_ENABLED)
|
||||
private boolean enabled;
|
||||
|
||||
@ColumnInfo(name = KEY_STATE)
|
||||
private String state;
|
||||
|
||||
@Override
|
||||
public long getId() {
|
||||
return id;
|
||||
|
@ -76,4 +80,14 @@ public class RoomAccountModel implements AccountModel {
|
|||
public void setEnabled(boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setState(String state) {
|
||||
this.state = state;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package org.mercury_im.messenger.persistence.room.repository;
|
|||
import android.os.AsyncTask;
|
||||
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.room.Transaction;
|
||||
|
||||
import org.mercury_im.messenger.persistence.repository.AccountRepository;
|
||||
import org.mercury_im.messenger.persistence.room.dao.AccountDao;
|
||||
|
@ -51,6 +52,11 @@ public class IAccountRepository implements AccountRepository<RoomAccountModel> {
|
|||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateState(long accountId, String state) {
|
||||
accountDao.updateConnectionState(accountId, state);
|
||||
}
|
||||
|
||||
private static class InsertAsyncTask extends AsyncTask<RoomAccountModel, Void, Long> {
|
||||
|
||||
private final AccountDao accountDao;
|
||||
|
|
|
@ -19,4 +19,8 @@ public interface AccountModel {
|
|||
boolean getEnabled();
|
||||
|
||||
void setEnabled(boolean enabled);
|
||||
|
||||
String getState();
|
||||
|
||||
void setState(String state);
|
||||
}
|
||||
|
|
|
@ -15,4 +15,6 @@ public interface AccountRepository<E extends AccountModel> {
|
|||
List<E> getAllAccounts();
|
||||
|
||||
long insertAccount(E accountModel);
|
||||
|
||||
void updateState(long accountId, String state);
|
||||
}
|
||||
|
|
|
@ -1 +1,4 @@
|
|||
include ':app', ':xmpp_core', ':persistence-room', ':persistence', ':xmpp_android'
|
||||
include ':app',
|
||||
':xmpp_core',
|
||||
':persistence-room',
|
||||
':persistence'
|
||||
|
|
1
xmpp_android/.gitignore
vendored
1
xmpp_android/.gitignore
vendored
|
@ -1 +0,0 @@
|
|||
/build
|
|
@ -1,39 +0,0 @@
|
|||
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'
|
||||
}
|
21
xmpp_android/proguard-rules.pro
vendored
21
xmpp_android/proguard-rules.pro
vendored
|
@ -1,21 +0,0 @@
|
|||
# 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
|
|
@ -1,27 +0,0 @@
|
|||
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());
|
||||
}
|
||||
}
|
|
@ -1,2 +0,0 @@
|
|||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.mercury_im.messenger.xmpp_android" />
|
|
@ -1,21 +0,0 @@
|
|||
package org.mercury_im.messenger.xmpp_android;
|
||||
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
|
||||
import org.mercury_im.messenger.xmpp_core.ConnectionState;
|
||||
import org.mercury_im.messenger.xmpp_core.ConnectionStateHolder;
|
||||
|
||||
public class AndroidConnectionStateHolder implements ConnectionStateHolder {
|
||||
|
||||
private MutableLiveData<ConnectionState> connectionState = new MutableLiveData<>();
|
||||
|
||||
@Override
|
||||
public void updateConnectionState(ConnectionState state) {
|
||||
this.connectionState.postValue(state);
|
||||
}
|
||||
|
||||
public LiveData<ConnectionState> getConnectionState() {
|
||||
return connectionState;
|
||||
}
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
package org.mercury_im.messenger.xmpp_android;
|
||||
|
||||
import org.jivesoftware.smack.tcp.XMPPTCPConnection;
|
||||
import org.mercury_im.messenger.xmpp_core.ConnectionStateHolder;
|
||||
import org.mercury_im.messenger.xmpp_core.MercuryConnection;
|
||||
|
||||
public class AndroidMercuryConnection extends MercuryConnection {
|
||||
|
||||
public AndroidMercuryConnection(XMPPTCPConnection connection, long accountId) {
|
||||
super(connection, accountId);
|
||||
this.stateHolder = new AndroidConnectionStateHolder();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConnectionStateHolder getState() {
|
||||
return stateHolder;
|
||||
}
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
<resources>
|
||||
<string name="app_name">XmppAndroid</string>
|
||||
</resources>
|
|
@ -1,17 +0,0 @@
|
|||
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);
|
||||
}
|
||||
}
|
|
@ -42,6 +42,8 @@ public abstract class MercuryConnection implements ConnectionListener {
|
|||
|
||||
protected ConnectionStateHolder stateHolder;
|
||||
|
||||
protected ConnectionStateListener stateListener = null;
|
||||
|
||||
public MercuryConnection(XMPPConnection connection, long accountId) {
|
||||
this.connection = connection;
|
||||
connection.addConnectionListener(this);
|
||||
|
@ -72,6 +74,10 @@ public abstract class MercuryConnection implements ConnectionListener {
|
|||
return connection;
|
||||
}
|
||||
|
||||
public void setConnectionStateListener(ConnectionStateListener stateListener) {
|
||||
this.stateListener = stateListener;
|
||||
}
|
||||
|
||||
public void setRosterHandler(RosterHandler handler) {
|
||||
roster.addRosterListener(handler);
|
||||
roster.addRosterLoadedListener(handler);
|
||||
|
@ -83,8 +89,6 @@ public abstract class MercuryConnection implements ConnectionListener {
|
|||
chatManager.addOutgoingListener(plainMessageHandler);
|
||||
}
|
||||
|
||||
public abstract ConnectionStateHolder getState();
|
||||
|
||||
public long getAccountId() {
|
||||
return accountId;
|
||||
}
|
||||
|
@ -95,11 +99,13 @@ public abstract class MercuryConnection implements ConnectionListener {
|
|||
|
||||
@Override
|
||||
public void connected(XMPPConnection connection) {
|
||||
getState().updateConnectionState(ConnectionState.CONNECTED);
|
||||
LOGGER.info("Connection " + getAccountId() + " connected.");
|
||||
notifyStateListener(ConnectionState.CONNECTING);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void authenticated(XMPPConnection connection, boolean resumed) {
|
||||
LOGGER.info("Connection " + getAccountId() + " authenticated (" + (resumed ? "resumed" : "first time") + ")");
|
||||
if (connection == this.connection && !resumed) {
|
||||
LOGGER.info("Enabling carbons!");
|
||||
carbonManager.enableCarbonsAsync(exception -> {
|
||||
|
@ -107,18 +113,28 @@ public abstract class MercuryConnection implements ConnectionListener {
|
|||
exception.printStackTrace();
|
||||
});
|
||||
}
|
||||
getState().updateConnectionState(ConnectionState.CONNECTED);
|
||||
notifyStateListener(ConnectionState.CONNECTED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connectionClosed() {
|
||||
LOGGER.fine("Connection closed.");
|
||||
getState().updateConnectionState(ConnectionState.DISCONNECTED);
|
||||
LOGGER.fine("Connection " + accountId + " closed.");
|
||||
notifyStateListener(ConnectionState.DISCONNECTED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connectionClosedOnError(Exception e) {
|
||||
LOGGER.severe("Connection closed on error: " + e.getMessage());
|
||||
getState().updateConnectionState(ConnectionState.DISCONNECTED);
|
||||
LOGGER.severe("Connection " + accountId + " closed on error: " + e.getMessage());
|
||||
notifyStateListener(ConnectionState.WAIRING_FOR_RETRY);
|
||||
}
|
||||
|
||||
private void notifyStateListener(ConnectionState newState) {
|
||||
if (stateListener != null) {
|
||||
stateListener.stateChanged(this, newState);
|
||||
}
|
||||
}
|
||||
|
||||
public interface ConnectionStateListener {
|
||||
void stateChanged(MercuryConnection connection, ConnectionState state);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue