diff --git a/Mercury-IM.ipr b/Mercury-IM.ipr
new file mode 100644
index 0000000..ef57a1e
--- /dev/null
+++ b/Mercury-IM.ipr
@@ -0,0 +1,2399 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ xmlns:android
+
+ ^$
+
+
+
+
+
+
+
+
+ xmlns:.*
+
+ ^$
+
+
+ BY_NAME
+
+
+
+
+
+
+ .*:id
+
+ http://schemas.android.com/apk/res/android
+
+
+
+
+
+
+
+
+ .*:name
+
+ http://schemas.android.com/apk/res/android
+
+
+
+
+
+
+
+
+ name
+
+ ^$
+
+
+
+
+
+
+
+
+ style
+
+ ^$
+
+
+
+
+
+
+
+
+ .*
+
+ ^$
+
+
+ BY_NAME
+
+
+
+
+
+
+ .*
+
+ http://schemas.android.com/apk/res/android
+
+
+ ANDROID_ATTRIBUTE_ORDER
+
+
+
+
+
+
+ .*
+
+ .*
+
+
+ BY_NAME
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1.6
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Mercury-IM.iws b/Mercury-IM.iws
new file mode 100644
index 0000000..f93b633
--- /dev/null
+++ b/Mercury-IM.iws
@@ -0,0 +1,493 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ localhost
+ 5050
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1587569163841
+
+
+ 1587569163841
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
index e5189a2..f77f9e4 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -35,6 +35,7 @@ android {
dataBinding {
enabled true
}
+ buildToolsVersion = '29.0.2'
}
checkstyle {
@@ -78,29 +79,29 @@ dependencies {
implementation project(":data")
implementation "io.requery:requery-android:$requeryVersion"
- implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.61'
+ implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.71'
// Dagger 2 for dependency injection
implementation "com.google.dagger:dagger:$daggerVersion"
annotationProcessor "com.google.dagger:dagger-compiler:$daggerVersion"
- compileOnly 'org.projectlombok:lombok:1.18.10'
- annotationProcessor 'org.projectlombok:lombok:1.18.10'
+ compileOnly "org.projectlombok:lombok:$lombokVersion"
+ annotationProcessor "org.projectlombok:lombok:$lombokVersion"
// ViewModel and LiveData
- implementation "androidx.lifecycle:lifecycle-extensions:$lifecycleVersion"
+ implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"
annotationProcessor "androidx.lifecycle:lifecycle-common-java8:$lifecycleVersion"
// Android extension for rxJava
api "io.reactivex.rxjava2:rxandroid:$rxAndroidVersion"
// ButterKnife for View Binding
- implementation "com.jakewharton:butterknife:$butterKnifeVersion"
- annotationProcessor "com.jakewharton:butterknife-compiler:$butterKnifeVersion"
+ implementation "com.jakewharton:butterknife:${butterKnifeVersion}"
+ annotationProcessor "com.jakewharton:butterknife-compiler:${butterKnifeVersion}"
// support libraries
- implementation "androidx.appcompat:appcompat:$appCompatVersion"
- implementation 'com.google.android.material:material:1.2.0-alpha03'
+ implementation "androidx.appcompat:appcompat:${appCompatVersion}"
+ implementation 'com.google.android.material:material:1.2.0-alpha06'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'androidx.vectordrawable:vectordrawable:1.1.0'
implementation 'androidx.cardview:cardview:1.0.0'
@@ -108,7 +109,7 @@ dependencies {
implementation 'androidx.recyclerview:recyclerview:1.1.0'
// circular image viewer for avatars
- implementation 'de.hdodenhof:circleimageview:3.0.1'
+ implementation 'de.hdodenhof:circleimageview:3.1.0'
// Android specific classes of Smacks API
implementation "org.igniterealtime.smack:smack-android-extensions:$smackAndroidExtensionsVersion"
diff --git a/app/src/main/java/org/mercury_im/messenger/MercuryImApplication.java b/app/src/main/java/org/mercury_im/messenger/MercuryImApplication.java
index 480082c..86cf7ad 100644
--- a/app/src/main/java/org/mercury_im/messenger/MercuryImApplication.java
+++ b/app/src/main/java/org/mercury_im/messenger/MercuryImApplication.java
@@ -56,7 +56,7 @@ public class MercuryImApplication extends Application {
}
private void setupClientStateIndication() {
- clientStateHandler.addClientStateListener(messenger);
+ clientStateHandler.addClientStateListener(messenger.getConnectionManager());
registerActivityLifecycleCallbacks(clientStateHandler);
}
diff --git a/app/src/main/java/org/mercury_im/messenger/ui/account/AccountsFragment.java b/app/src/main/java/org/mercury_im/messenger/ui/account/AccountsFragment.java
index 84da9b0..adb940d 100644
--- a/app/src/main/java/org/mercury_im/messenger/ui/account/AccountsFragment.java
+++ b/app/src/main/java/org/mercury_im/messenger/ui/account/AccountsFragment.java
@@ -49,11 +49,6 @@ public class AccountsFragment extends Fragment {
super.onCreate(savedInstanceState);
viewModel = new ViewModelProvider(this).get(AccountsViewModel.class);
this.adapter = new AccountsRecyclerViewAdapter(viewModel, accountClickListener);
- }
-
- @Override
- public void onResume() {
- super.onResume();
observeViewModel();
}
diff --git a/app/src/main/java/org/mercury_im/messenger/ui/account/AccountsRecyclerViewAdapter.java b/app/src/main/java/org/mercury_im/messenger/ui/account/AccountsRecyclerViewAdapter.java
index 97dc0e9..f614a9e 100644
--- a/app/src/main/java/org/mercury_im/messenger/ui/account/AccountsRecyclerViewAdapter.java
+++ b/app/src/main/java/org/mercury_im/messenger/ui/account/AccountsRecyclerViewAdapter.java
@@ -14,6 +14,7 @@ import androidx.recyclerview.widget.RecyclerView;
import org.jetbrains.annotations.NotNull;
import org.mercury_im.messenger.R;
import org.mercury_im.messenger.entity.Account;
+import org.mercury_im.messenger.logging.Tags;
import org.mercury_im.messenger.ui.avatar.AvatarDrawable;
import org.mercury_im.messenger.ui.account.AccountsFragment.OnAccountListItemClickListener;
import org.mercury_im.messenger.util.AbstractDiffCallback;
@@ -21,11 +22,15 @@ import org.mercury_im.messenger.xmpp.MercuryConnection;
import java.util.ArrayList;
import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
import io.reactivex.android.schedulers.AndroidSchedulers;
public class AccountsRecyclerViewAdapter extends RecyclerView.Adapter {
+ private static final Logger LOGGER = Logger.getLogger(Tags.TAG_ANDROID);
+
private final List connections = new ArrayList<>();
private final OnAccountListItemClickListener onAccountClickListener;
private final AccountsViewModel viewModel;
@@ -44,6 +49,7 @@ public class AccountsRecyclerViewAdapter extends RecyclerView.Adapter values) {
+ LOGGER.log(Level.INFO, "AccountsRecyclerViewAdapter.setValues(" + values.size() + ")");
DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(
new AccountsDiffCallback(values, connections), true);
connections.clear();
diff --git a/app/src/main/java/org/mercury_im/messenger/ui/account/AccountsViewModel.java b/app/src/main/java/org/mercury_im/messenger/ui/account/AccountsViewModel.java
index 09b0ffb..02c2c7b 100644
--- a/app/src/main/java/org/mercury_im/messenger/ui/account/AccountsViewModel.java
+++ b/app/src/main/java/org/mercury_im/messenger/ui/account/AccountsViewModel.java
@@ -10,19 +10,24 @@ import org.mercury_im.messenger.MercuryImApplication;
import org.mercury_im.messenger.Messenger;
import org.mercury_im.messenger.data.repository.AccountRepository;
import org.mercury_im.messenger.entity.Account;
+import org.mercury_im.messenger.logging.Tags;
+import org.mercury_im.messenger.util.DebugUtils;
import org.mercury_im.messenger.xmpp.MercuryConnection;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
import javax.inject.Inject;
import io.reactivex.disposables.CompositeDisposable;
-import lombok.Getter;
public class AccountsViewModel extends AndroidViewModel {
+ private static final Logger LOGGER = Logger.getLogger(Tags.TAG_ANDROID);
+
@Inject
AccountRepository repository;
@@ -36,15 +41,20 @@ public class AccountsViewModel extends AndroidViewModel {
public AccountsViewModel(Application application) {
super(application);
MercuryImApplication.getApplication().getAppComponent().inject(this);
- compositeDisposable.add(messenger.getConnectionManager()
- .observeConnections()
- .map(Map::values)
- .subscribe(conns -> connections.postValue(new ArrayList<>(conns))));
+ compositeDisposable.add(repository.observeAllAccounts()
+ .map(accounts -> {
+ List connections = new ArrayList<>(accounts.size());
+ for (Account account : accounts) {
+ connections.add(messenger.getConnectionManager().getOrCreateConnection(account));
+ }
+ return connections;
+ }).subscribe(connections::postValue));
}
@Override
protected void onCleared() {
super.onCleared();
+ LOGGER.log(Level.INFO, "AccountsViewModel.onCleared()");
compositeDisposable.clear();
}
@@ -58,7 +68,7 @@ public class AccountsViewModel extends AndroidViewModel {
public void setAccountEnabled(Account accountModel, boolean enabled) {
accountModel.setEnabled(enabled);
- repository.upsertAccount(accountModel)
- .subscribe();
+ compositeDisposable.add(repository.upsertAccount(accountModel)
+ .subscribe());
}
}
diff --git a/app/src/main/java/org/mercury_im/messenger/ui/account/LoginViewModel.java b/app/src/main/java/org/mercury_im/messenger/ui/account/LoginViewModel.java
index 29a8245..fbc8701 100644
--- a/app/src/main/java/org/mercury_im/messenger/ui/account/LoginViewModel.java
+++ b/app/src/main/java/org/mercury_im/messenger/ui/account/LoginViewModel.java
@@ -17,6 +17,7 @@ import org.mercury_im.messenger.Messenger;
import org.mercury_im.messenger.R;
import org.mercury_im.messenger.entity.Account;
import org.mercury_im.messenger.entity.IAccount;
+import org.mercury_im.messenger.logging.Tags;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -29,6 +30,8 @@ import io.reactivex.schedulers.Schedulers;
public class LoginViewModel extends AndroidViewModel {
+ private static final Logger LOGGER = Logger.getLogger(Tags.TAG_ANDROID);
+
private MutableLiveData usernameError = new MutableLiveData<>(new Error());
private MutableLiveData passwordError = new MutableLiveData<>(new Error());
private MutableLiveData loginButtonEnabled = new MutableLiveData<>(false);
@@ -86,6 +89,8 @@ public class LoginViewModel extends AndroidViewModel {
Account account = new IAccount();
account.setAddress(username.asUnescapedString());
account.setPassword(password);
+ signalLoginSuccessful();
+ /*
disposable.add(messenger.addAccount()
.execute(account)
.subscribeOn(Schedulers.newThread())
@@ -93,10 +98,11 @@ public class LoginViewModel extends AndroidViewModel {
.doOnComplete(this::signalLoginSuccessful)
.doOnError(this::signalLoginError)
.subscribe());
+ */
}
private void signalLoginSuccessful() {
- Logger.getAnonymousLogger().log(Level.INFO, "Signal Login Successful");
+ LOGGER.log(Level.INFO, "LoginViewModel.signalLoginSuccessful()");
loginCompleted.setValue(true);
}
diff --git a/app/src/test/java/org/mercury_im/messenger/ExampleUnitTest.java b/app/src/test/java/org/mercury_im/messenger/ExampleUnitTest.java
index 3977c6f..3bab749 100644
--- a/app/src/test/java/org/mercury_im/messenger/ExampleUnitTest.java
+++ b/app/src/test/java/org/mercury_im/messenger/ExampleUnitTest.java
@@ -1,8 +1,8 @@
package org.mercury_im.messenger;
import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mercury_im.messenger.core.connection.ConnectionState;
+import org.mercury_im.messenger.xmpp.MercuryConnection;
+import org.mercury_im.messenger.xmpp.MercuryConnection.ConnectionState;
import io.reactivex.observers.TestObserver;
import io.reactivex.schedulers.TestScheduler;
@@ -25,11 +25,11 @@ public class ExampleUnitTest {
@Test
public void test() {
TestScheduler testScheduler = new TestScheduler();
- BehaviorSubject state = BehaviorSubject.createDefault(ConnectionState.DISCONNECTED);
+ BehaviorSubject state = BehaviorSubject.createDefault(ConnectionState.closed);
TestObserver observable = state.test();
- assertEquals(ConnectionState.DISCONNECTED, state.getValue());
- state.onNext(ConnectionState.CONNECTING);
- assertEquals(ConnectionState.CONNECTING, state.getValue());
- observable.assertValues(ConnectionState.DISCONNECTED, ConnectionState.CONNECTING).dispose();
+ assertEquals(ConnectionState.closed, state.getValue());
+ state.onNext(ConnectionState.connected);
+ assertEquals(ConnectionState.connected, state.getValue());
+ observable.assertValues(ConnectionState.connected, ConnectionState.closed).dispose();
}
}
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index ba1be77..8d47d20 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,5 +1,7 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
+apply plugin: 'idea'
+
buildscript {
repositories {
@@ -7,7 +9,7 @@ buildscript {
jcenter()
}
dependencies {
- classpath 'com.android.tools.build:gradle:3.5.3'
+ classpath 'com.android.tools.build:gradle:3.6.3'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
diff --git a/data/build.gradle b/data/build.gradle
index af39365..3dc1279 100644
--- a/data/build.gradle
+++ b/data/build.gradle
@@ -12,14 +12,15 @@ dependencies {
implementation project(":entity")
implementation project(':domain')
- compileOnly 'org.projectlombok:lombok:1.18.10'
- annotationProcessor 'org.projectlombok:lombok:1.18.10'
+ compileOnly "org.projectlombok:lombok:$lombokVersion"
+ annotationProcessor "org.projectlombok:lombok:$lombokVersion"
// RxJava2
implementation "io.reactivex.rxjava2:rxjava:$rxJava2Version"
// Dagger 2 for dependency injection
- implementation "com.google.dagger:dagger:$daggerVersion"
+ compileOnly "com.google.dagger:dagger:$daggerVersion"
+ testCompileOnly "com.google.dagger:dagger:$daggerVersion"
annotationProcessor "com.google.dagger:dagger-compiler:$daggerVersion"
testAnnotationProcessor "com.google.dagger:dagger-compiler:$daggerVersion"
@@ -31,6 +32,8 @@ dependencies {
testImplementation "junit:junit:$junitVersion"
testImplementation 'org.xerial:sqlite-jdbc:3.30.1'
+
+ implementation 'javax.inject:javax.inject:1'
}
sourceCompatibility = "8"
diff --git a/data/src/main/java/org/mercury_im/messenger/data/repository/XmppAccountRepository.java b/data/src/main/java/org/mercury_im/messenger/data/repository/XmppAccountRepository.java
index f683023..7fad725 100644
--- a/data/src/main/java/org/mercury_im/messenger/data/repository/XmppAccountRepository.java
+++ b/data/src/main/java/org/mercury_im/messenger/data/repository/XmppAccountRepository.java
@@ -3,14 +3,16 @@ package org.mercury_im.messenger.data.repository;
import org.mercury_im.messenger.data.mapping.AccountMapping;
import org.mercury_im.messenger.data.model.AccountModel;
import org.mercury_im.messenger.data.repository.dao.AccountDao;
-import org.mercury_im.messenger.util.Optional;
import org.mercury_im.messenger.entity.Account;
+import org.mercury_im.messenger.util.Optional;
import org.mercury_im.messenger.util.ThreadUtils;
import java.util.ArrayList;
-import java.util.Collections;
+import java.util.Arrays;
import java.util.List;
import java.util.UUID;
+import java.util.logging.Level;
+import java.util.logging.Logger;
import javax.inject.Inject;
import javax.inject.Named;
@@ -29,6 +31,9 @@ public class XmppAccountRepository
extends RequeryRepository
implements AccountRepository {
+ private static final Logger LOGGER = Logger.getLogger(XmppAccountRepository.class.getName());
+ private static final Level LEVEL = Level.INFO;
+
private final AccountMapping accountMapping;
private final AccountDao dao;
@@ -48,6 +53,8 @@ public class XmppAccountRepository
.map(accountMapping::toModel)
.flatMap(dao::insert)
.map(model -> accountMapping.toEntity(model, account))
+ .doOnSuccess(a -> LOGGER.log(LEVEL, "insertAccount(" + account + "): onSuccess(): " + a))
+ .doOnError(e -> LOGGER.log(Level.SEVERE, "insertAccount(" + account + "): onError()", e))
.subscribeOn(subscriberScheduler())
.observeOn(observerScheduler());
}
@@ -57,6 +64,9 @@ public class XmppAccountRepository
return dao.get(accountId).observableResult()
.map(result -> new Optional<>(result.firstOrNull()))
.map(accountMapping::toEntity)
+ .doOnNext(a -> LOGGER.log(LEVEL, "observeAccount(" + accountId + "): onNext(): " + a))
+ .doOnError(e -> LOGGER.log(Level.SEVERE, "observeAccount(" + accountId + "): onError()", e))
+ .doOnComplete(() -> LOGGER.log(LEVEL, "observeAccount(" + accountId + "): onComplete()"))
.subscribeOn(subscriberScheduler())
.observeOn(observerScheduler());
}
@@ -65,6 +75,9 @@ public class XmppAccountRepository
public Maybe getAccount(UUID accountId) {
return dao.get(accountId).maybe()
.map(accountMapping::toEntity)
+ .doOnSuccess(a -> LOGGER.log(LEVEL, "getAccount(" + accountId + "): onSuccess(): " + a))
+ .doOnComplete(() -> LOGGER.log(LEVEL, "getAccount(" + accountId + "): onComplete()"))
+ .doOnError(e -> LOGGER.log(Level.SEVERE, "getAccount(" + accountId + "): onError()", e))
.subscribeOn(subscriberScheduler())
.observeOn(observerScheduler());
}
@@ -74,6 +87,9 @@ public class XmppAccountRepository
return dao.get(address).observableResult()
.map(result -> new Optional<>(result.firstOrNull()))
.map(accountMapping::toEntity)
+ .doOnNext(o -> LOGGER.log(LEVEL, "observeAccountByAddress(" + address + "): onNext(): " + o))
+ .doOnError(e -> LOGGER.log(Level.SEVERE, "observeAccountByAddress(" + address + "): onError()", e))
+ .doOnComplete(() -> LOGGER.log(Level.INFO, "observeAccountByAddress(" + address + "): onComplete()"))
.subscribeOn(subscriberScheduler())
.observeOn(observerScheduler());
}
@@ -82,6 +98,9 @@ public class XmppAccountRepository
public Maybe getAccountByAddress(String address) {
return dao.get(address).maybe()
.map(accountMapping::toEntity)
+ .doOnSuccess(a -> LOGGER.log(LEVEL, "getAccountByAddress(" + address + "): onSuccess(): " + a))
+ .doOnComplete(() -> LOGGER.log(LEVEL, "getAccountByAddress(" + address + "): onComplete()"))
+ .doOnError(e -> LOGGER.log(Level.SEVERE, "getAccountByAddress(" + address + "): onError()", e))
.subscribeOn(subscriberScheduler())
.observeOn(observerScheduler());
}
@@ -91,6 +110,9 @@ public class XmppAccountRepository
return dao.getAll().observableResult()
.map(ResultDelegate::toList)
.map(this::modelsToEntities)
+ .doOnNext(l -> LOGGER.log(LEVEL, "observeAllAccounts(): onNext(): " + Arrays.toString(l.toArray())))
+ .doOnError(e -> LOGGER.log(Level.SEVERE, "observeAllAccounts(): onError()", e))
+ .doOnComplete(() -> LOGGER.log(LEVEL, "observeAllAccounts(): onComplete()"))
.subscribeOn(subscriberScheduler())
.observeOn(observerScheduler());
}
@@ -100,6 +122,9 @@ public class XmppAccountRepository
return dao.getAll().observableResult()
.flatMap(ReactiveResult::observable)
.map(accountMapping::toEntity)
+ .doOnNext(a -> LOGGER.log(LEVEL, "observeAccounts(): onNext(): " + a))
+ .doOnError(e -> LOGGER.log(Level.SEVERE, "observeAccounts(): onError()", e))
+ .doOnComplete(() -> LOGGER.log(LEVEL, "observeAccounts(): onComplete()"))
.subscribeOn(subscriberScheduler())
.observeOn(observerScheduler());
}
@@ -113,6 +138,8 @@ public class XmppAccountRepository
.map(model -> accountMapping.toModel(account, model))
.flatMap(updatedModel -> data().update(updatedModel))
.map(model -> accountMapping.toEntity(model, account))
+ .doOnSuccess(a -> LOGGER.log(LEVEL, "updateAccount(" + account + "): onSuccess(): " + a))
+ .doOnError(e -> LOGGER.log(Level.SEVERE, "updateAccount(" + account + "): onError()", e))
.subscribeOn(subscriberScheduler())
.observeOn(observerScheduler());
}
@@ -125,6 +152,8 @@ public class XmppAccountRepository
.map(model -> accountMapping.toModel(account, model))
.flatMap(data()::update)
.map(model -> accountMapping.toEntity(model, account))
+ .doOnSuccess(a -> LOGGER.log(LEVEL, "upsertAccount(" + account + "): onSuccess(): " + a))
+ .doOnError(e -> LOGGER.log(Level.SEVERE, "upsertAccount(" + account + "): onError()", e))
.subscribeOn(subscriberScheduler())
.observeOn(observerScheduler());
}
@@ -132,6 +161,8 @@ public class XmppAccountRepository
@Override
public Completable deleteAccount(UUID accountId) {
return dao.delete(accountId).ignoreElement()
+ .doOnComplete(() -> LOGGER.log(LEVEL, "deleteAccount(" + accountId + "): onComplete()"))
+ .doOnError(e -> LOGGER.log(Level.SEVERE, "deleteAccount(" + accountId + "): onError()", e))
.subscribeOn(subscriberScheduler())
.observeOn(observerScheduler());
}
diff --git a/domain/build.gradle b/domain/build.gradle
index 187c55a..e75c31c 100644
--- a/domain/build.gradle
+++ b/domain/build.gradle
@@ -6,13 +6,13 @@ 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-core:$smackCoreVersion"
- api "org.igniterealtime.smack:smack-experimental:$smackExperimentalVersion"
- api "org.igniterealtime.smack:smack-extensions:$smackExtensionsVersion"
- api "org.igniterealtime.smack:smack-im:$smackImVersion"
- api "org.igniterealtime.smack:smack-tcp:$smackTcpVersion"
+ implementation 'org.igniterealtime.smack:smack-core:'
+ implementation 'org.igniterealtime.smack:smack-experimental:'
+ implementation 'org.igniterealtime.smack:smack-extensions:'
+ implementation 'org.igniterealtime.smack:smack-im:'
+ implementation 'org.igniterealtime.smack:smack-tcp:'
- testImplementation "org.igniterealtime.smack:smack-java7:$smackJava7Version"
+ testImplementation 'org.igniterealtime.smack:smack-java7:'
// RxJava2
implementation "io.reactivex.rxjava2:rxjava:$rxJava2Version"
@@ -21,8 +21,8 @@ dependencies {
implementation "com.google.dagger:dagger:$daggerVersion"
annotationProcessor "com.google.dagger:dagger-compiler:$daggerVersion"
- compileOnly 'org.projectlombok:lombok:1.18.10'
- annotationProcessor 'org.projectlombok:lombok:1.18.10'
+ compileOnly "org.projectlombok:lombok:$lombokVersion"
+ annotationProcessor "org.projectlombok:lombok:$lombokVersion"
// JUnit for testing
testImplementation "junit:junit:$junitVersion"
diff --git a/domain/src/main/java/org/mercury_im/messenger/Messenger.java b/domain/src/main/java/org/mercury_im/messenger/Messenger.java
index 1e53829..b499e31 100644
--- a/domain/src/main/java/org/mercury_im/messenger/Messenger.java
+++ b/domain/src/main/java/org/mercury_im/messenger/Messenger.java
@@ -1,86 +1,51 @@
package org.mercury_im.messenger;
-import org.jivesoftware.smack.SmackException;
-import org.jivesoftware.smackx.csi.ClientStateIndicationManager;
+import org.jivesoftware.smack.ReconnectionManager;
+import org.jivesoftware.smackx.caps.EntityCapsManager;
+import org.jivesoftware.smackx.iqversion.VersionManager;
+import org.jivesoftware.smackx.receipts.DeliveryReceiptManager;
+import org.jivesoftware.smackx.sid.StableUniqueStanzaIdManager;
import org.mercury_im.messenger.data.repository.Repositories;
-import org.mercury_im.messenger.usecase.AddAccount;
-import org.mercury_im.messenger.usecase.RosterStoreBinder;
-import org.mercury_im.messenger.xmpp.MercuryConnection;
+import org.mercury_im.messenger.store.MercuryEntityCapsStore;
import org.mercury_im.messenger.xmpp.MercuryConnectionManager;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
import javax.inject.Inject;
import javax.inject.Singleton;
-import io.reactivex.disposables.CompositeDisposable;
-import io.reactivex.schedulers.Schedulers;
-
@Singleton
-public class Messenger implements ClientStateListener {
+public class Messenger {
public static final String TAG = "MercuryIM";
- private static final Logger LOGGER = Logger.getLogger(Messenger.class.getName());
private final MercuryConnectionManager connectionManager;
private final Repositories repositories;
- private CompositeDisposable disposable = new CompositeDisposable();
+ static {
+ ReconnectionManager.setEnabledPerDefault(true);
+ ReconnectionManager.setDefaultReconnectionPolicy(ReconnectionManager.ReconnectionPolicy.RANDOM_INCREASING_DELAY);
+
+ VersionManager.setAutoAppendSmackVersion(false);
+ VersionManager.setDefaultVersion("Mercury-IM", "0.0.1-little-joe");
+
+ DeliveryReceiptManager.setDefaultAutoReceiptMode(DeliveryReceiptManager.AutoReceiptMode.ifIsSubscribed);
+
+ StableUniqueStanzaIdManager.setEnabledByDefault(true);
+ }
@Inject
- public Messenger(Repositories repositories, MercuryConnectionManager connectionManager) {
+ public Messenger(Repositories repositories,
+ MercuryConnectionManager connectionManager,
+ MercuryEntityCapsStore entityCapsStore) {
this.repositories = repositories;
this.connectionManager = connectionManager;
- performInitialLogin();
+ connectionManager.setRepositories(repositories);
+
+ EntityCapsManager.setPersistentCache(entityCapsStore);
+ getConnectionManager().connectActiveAccounts();
}
public MercuryConnectionManager getConnectionManager() {
return connectionManager;
}
- public void performInitialLogin() {
- LOGGER.log(Level.INFO, "Perform initial login.");
- disposable.add(repositories.getAccountRepository().observeAllAccounts().firstOrError()
- .subscribeOn(Schedulers.newThread())
- .subscribe(connectionManager::registerConnections));
- }
-
- public AddAccount addAccount() {
- return new AddAccount(repositories.getAccountRepository(), this.connectionManager);
- }
-
- // CSI
-
- @Override
- public void onClientInForeground() {
- LOGGER.log(Level.INFO, "CSI: active");
- for (MercuryConnection connection : connectionManager.getConnections()) {
- tryCsiActive(connection);
- }
- }
-
- @Override
- public void onClientInBackground() {
- LOGGER.log(Level.INFO, "CSI: inactive");
- for (MercuryConnection connection : connectionManager.getConnections()) {
- tryCsiInactive(connection);
- }
- }
-
- private void tryCsiActive(MercuryConnection connection) {
- try {
- ClientStateIndicationManager.active(connection.getConnection());
- } catch (SmackException.NotConnectedException | InterruptedException e) {
- LOGGER.log(Level.WARNING, "Sending CSI state 'active' failed.", e);
- }
- }
-
- private void tryCsiInactive(MercuryConnection connection) {
- try {
- ClientStateIndicationManager.inactive(connection.getConnection());
- } catch (SmackException.NotConnectedException | InterruptedException e) {
- LOGGER.log(Level.WARNING, "Sending CSI state 'inactive' failed.", e);
- }
- }
}
diff --git a/domain/src/main/java/org/mercury_im/messenger/usecase/RosterStoreBinder.java b/domain/src/main/java/org/mercury_im/messenger/store/RosterStoreBinder.java
similarity index 96%
rename from domain/src/main/java/org/mercury_im/messenger/usecase/RosterStoreBinder.java
rename to domain/src/main/java/org/mercury_im/messenger/store/RosterStoreBinder.java
index 795916f..7238104 100644
--- a/domain/src/main/java/org/mercury_im/messenger/usecase/RosterStoreBinder.java
+++ b/domain/src/main/java/org/mercury_im/messenger/store/RosterStoreBinder.java
@@ -1,4 +1,4 @@
-package org.mercury_im.messenger.usecase;
+package org.mercury_im.messenger.store;
import org.jivesoftware.smack.roster.Roster;
import org.mercury_im.messenger.data.repository.AccountRepository;
diff --git a/domain/src/main/java/org/mercury_im/messenger/usecase/AddAccount.java b/domain/src/main/java/org/mercury_im/messenger/usecase/AddAccount.java
deleted file mode 100644
index 87d0b46..0000000
--- a/domain/src/main/java/org/mercury_im/messenger/usecase/AddAccount.java
+++ /dev/null
@@ -1,82 +0,0 @@
-package org.mercury_im.messenger.usecase;
-
-import org.mercury_im.messenger.data.repository.AccountRepository;
-import org.mercury_im.messenger.entity.Account;
-import org.mercury_im.messenger.xmpp.MercuryConnection;
-import org.mercury_im.messenger.xmpp.MercuryConnectionManager;
-
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import io.reactivex.Completable;
-import io.reactivex.Single;
-import io.reactivex.disposables.CompositeDisposable;
-import io.reactivex.schedulers.Schedulers;
-
-public class AddAccount {
-
- private static final Logger LOGGER = Logger.getLogger(AddAccount.class.getName());
-
- private final AccountRepository accountRepository;
- private final MercuryConnectionManager connectionManager;
-
- private final CompositeDisposable disposable = new CompositeDisposable();
-
- public AddAccount(AccountRepository accountRepository, MercuryConnectionManager connectionManager) {
- this.accountRepository = accountRepository;
- this.connectionManager = connectionManager;
- }
-
- public Completable execute(Account account) {
- return loginAndStoreAccountIfSuccessful(account);
- }
-
- private Completable loginAndStoreAccountIfSuccessful(Account account) {
- LOGGER.log(Level.INFO, "loginAndStoreIfSuccessful");
- return logIntoAccount(account).flatMap(connection ->
- insertEnabledAccountIntoDatabase(account).flatMap(insertedAccount ->
- updateAccountIdInConnectionSingle(insertedAccount, connection)))
- .map(this::addConnectionToMessenger)
- .ignoreElement();
- }
-
- private Single logIntoAccount(Account account) {
- return getOrCreateConnectionSingle(account)
- .doAfterSuccess(con -> LogIntoAccount.with(con).executeAndPossiblyThrow())
- .subscribeOn(Schedulers.io());
- }
-
- private Single getOrCreateConnectionSingle(Account account) {
- return Single.fromCallable(() -> getOrCreateConnection(account));
- }
-
- private MercuryConnection getOrCreateConnection(Account account) {
- MercuryConnection connection = connectionManager.getConnection(account);
- if (connection == null) {
- connection = new MercuryConnection(accountRepository, account);
- }
- return connection;
- }
-
- private Single insertEnabledAccountIntoDatabase(Account account) {
- account.setEnabled(true);
- return accountRepository.upsertAccount(account);
- }
-
- private Completable addConnectionToMessenger(MercuryConnection connection) {
- return Completable.fromAction(() -> connectionManager.registerConnection(connection));
- }
-
- private Single updateAccountIdInConnectionSingle(Account account, MercuryConnection connection) {
- return Single.fromCallable(() -> {
- updateAccountIdInConnection(account, connection);
- return connection;
- });
- }
-
- private void updateAccountIdInConnection(Account account, MercuryConnection connection) {
- if (connection != null) {
- connection.getAccount().setId(account.getId());
- }
- }
-}
diff --git a/domain/src/main/java/org/mercury_im/messenger/usecase/AddAccountUseCase.java b/domain/src/main/java/org/mercury_im/messenger/usecase/AddAccountUseCase.java
deleted file mode 100644
index 6316d3d..0000000
--- a/domain/src/main/java/org/mercury_im/messenger/usecase/AddAccountUseCase.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package org.mercury_im.messenger.usecase;
-
-import io.reactivex.Completable;
-
-public interface AddAccountUseCase {
-
- AddAccountTask create();
-
- Completable execute(AddAccountTask task);
-
- interface AddAccountTask {
-
- void setAddress(String address);
-
- void setPassword(String password);
- }
-}
diff --git a/domain/src/main/java/org/mercury_im/messenger/usecase/LogIntoAccount.java b/domain/src/main/java/org/mercury_im/messenger/usecase/LogIntoAccount.java
deleted file mode 100644
index a3b74da..0000000
--- a/domain/src/main/java/org/mercury_im/messenger/usecase/LogIntoAccount.java
+++ /dev/null
@@ -1,74 +0,0 @@
-package org.mercury_im.messenger.usecase;
-
-import org.jivesoftware.smack.AbstractXMPPConnection;
-import org.jivesoftware.smack.SmackException;
-import org.jivesoftware.smack.XMPPException;
-import org.jivesoftware.smack.sasl.SASLErrorException;
-import org.mercury_im.messenger.xmpp.MercuryConnection;
-
-import java.io.IOException;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import io.reactivex.Completable;
-import io.reactivex.Single;
-
-public class LogIntoAccount {
-
- public enum ConnectionResult {
- success,
- credential_error,
- server_error,
- other_error
- }
-
- private static final Logger LOGGER = Logger.getLogger(LogIntoAccount.class.getName());
-
- private final MercuryConnection connection;
-
- private LogIntoAccount(MercuryConnection connection) {
- this.connection = connection;
- }
-
- public static LogIntoAccount with(MercuryConnection connection) {
- if (connection == null) {
- throw new NullPointerException("MercuryConnection cannot be null.");
- }
- return new LogIntoAccount(connection);
- }
-
- public Completable executeAndPossiblyThrow() {
- return Completable.fromAction(this::doAuthenticateIfNecessary);
- }
-
- public Single execute() {
- return Single.fromCallable(this::authenticateIfNecessary);
- }
-
- private ConnectionResult authenticateIfNecessary() {
- try {
- doAuthenticateIfNecessary();
- return ConnectionResult.success;
- } catch (SASLErrorException e) {
- LOGGER.log(Level.WARNING, "SASL Error while connecting to account " + connection.getAccount().getAddress(), e);
- return ConnectionResult.credential_error;
- } catch (SmackException.ConnectionException e) {
- LOGGER.log(Level.WARNING, "Connectivity error while connecting to account " + connection.getAccount().getAddress(), e);
- return ConnectionResult.server_error;
- }
- catch (IOException | XMPPException | SmackException | InterruptedException e) {
- LOGGER.log(Level.WARNING, "Error connecting to account " + connection.getAccount().getAddress(), e);
- return ConnectionResult.other_error;
- }
- }
-
- private void doAuthenticateIfNecessary()
- throws InterruptedException, XMPPException, SmackException, IOException {
- if (!connection.getConnection().isAuthenticated()) {
- LOGGER.log(Level.INFO, "Logging in");
- ((AbstractXMPPConnection) connection.getConnection()).connect().login();
- LOGGER.log(Level.INFO, "Login complete");
- }
- }
-
-}
diff --git a/domain/src/main/java/org/mercury_im/messenger/util/DebugUtils.java b/domain/src/main/java/org/mercury_im/messenger/util/DebugUtils.java
new file mode 100644
index 0000000..b837d88
--- /dev/null
+++ b/domain/src/main/java/org/mercury_im/messenger/util/DebugUtils.java
@@ -0,0 +1,25 @@
+package org.mercury_im.messenger.util;
+
+import java.util.Iterator;
+import java.util.Map;
+
+import io.reactivex.functions.Function;
+
+public class DebugUtils {
+
+ public static String mapToString(Map map) throws Exception {
+ return mapToString(map, K::toString, V::toString);
+ }
+
+ public static String mapToString(Map map, Function keyToString, Function valueToString) throws Exception {
+ StringBuilder sb = new StringBuilder("[");
+ for (Iterator> iterator = map.entrySet().iterator(); iterator.hasNext(); ) {
+ Map.Entry entry = iterator.next();
+ sb.append(keyToString.apply(entry.getKey())).append(": ").append(valueToString.apply(entry.getValue()));
+ if (iterator.hasNext()) {
+ sb.append(",\n");
+ }
+ }
+ return sb.append(']').toString();
+ }
+}
diff --git a/domain/src/main/java/org/mercury_im/messenger/util/Optional.java b/domain/src/main/java/org/mercury_im/messenger/util/Optional.java
index 4fae342..6db5b13 100644
--- a/domain/src/main/java/org/mercury_im/messenger/util/Optional.java
+++ b/domain/src/main/java/org/mercury_im/messenger/util/Optional.java
@@ -24,4 +24,9 @@ public class Optional {
public boolean isPresent() {
return item != null;
}
+
+ @Override
+ public String toString() {
+ return "Optional(" + (isPresent() ? getItem().toString() : "null") + ")";
+ }
}
diff --git a/domain/src/main/java/org/mercury_im/messenger/xmpp/MercuryConnection.java b/domain/src/main/java/org/mercury_im/messenger/xmpp/MercuryConnection.java
index 1cadeff..64d1f69 100644
--- a/domain/src/main/java/org/mercury_im/messenger/xmpp/MercuryConnection.java
+++ b/domain/src/main/java/org/mercury_im/messenger/xmpp/MercuryConnection.java
@@ -1,25 +1,26 @@
package org.mercury_im.messenger.xmpp;
+import org.jivesoftware.smack.AbstractXMPPConnection;
import org.jivesoftware.smack.ConnectionListener;
+import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.XMPPConnection;
+import org.jivesoftware.smack.XMPPException;
import org.mercury_im.messenger.data.repository.AccountRepository;
import org.mercury_im.messenger.entity.Account;
import org.mercury_im.messenger.util.Optional;
+import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import io.reactivex.Observable;
import io.reactivex.disposables.CompositeDisposable;
+import io.reactivex.disposables.Disposable;
import io.reactivex.subjects.BehaviorSubject;
public class MercuryConnection {
private static final Logger LOGGER = Logger.getLogger("MercuryConnection");
- private static final XmppConnectionFactory connectionFactory = new XmppConnectionFactory();
-
- private final CompositeDisposable disposable = new CompositeDisposable();
- private final AccountRepository accountRepository;
private Account account;
private XMPPConnection connection;
@@ -27,55 +28,30 @@ public class MercuryConnection {
private BehaviorSubject enabled = BehaviorSubject.create();
private BehaviorSubject state = BehaviorSubject.createDefault(ConnectionState.closed);
- public MercuryConnection(AccountRepository accountRepository, Account account) {
- this.accountRepository = accountRepository;
+ public MercuryConnection(Account account, XMPPConnection connection) {
this.account = account;
- this.connection = connectionFactory.createConnection(account);
- observeAccountAndConnection();
+ this.connection = connection;
}
public Observable getState() {
return state;
}
- private void observeAccountAndConnection() {
- observeAccount();
+ public void observeAccountAndConnection(AccountRepository accountRepository) {
+ observeAccount(accountRepository);
observeConnection();
}
- private void observeAccount() {
- disposable.add(accountRepository.observeAccount(account.getId())
+ private Disposable observeAccount(AccountRepository accountRepository) {
+ return accountRepository.observeAccount(account.getId())
.filter(Optional::isPresent)
.map(Optional::getItem)
- .subscribe(this::setAccount));
+ .subscribe(this::setAccount);
}
private void observeConnection() {
- connection.addConnectionListener(new ConnectionListener() {
- @Override
- public void connected(XMPPConnection connection) {
- LOGGER.log(Level.FINER, "connected");
- state.onNext(ConnectionState.connected);
- }
-
- @Override
- public void authenticated(XMPPConnection connection, boolean resumed) {
- LOGGER.log(Level.FINER, "authenticated. resumed? " + resumed);
- state.onNext(ConnectionState.authenticated);
- }
-
- @Override
- public void connectionClosed() {
- LOGGER.log(Level.FINER, "connectionClosed");
- state.onNext(ConnectionState.closed);
- }
-
- @Override
- public void connectionClosedOnError(Exception e) {
- LOGGER.log(Level.WARNING, "connectionClosedOnError");
- state.onNext(ConnectionState.closedOnError);
- }
- });
+ // TODO: Remove listener at some point
+ connection.addConnectionListener(connectionListener);
}
private void setAccount(Account account) {
@@ -91,8 +67,39 @@ public class MercuryConnection {
return connection;
}
- public void dispose() {
- disposable.dispose();
+ private final ConnectionListener connectionListener = new ConnectionListener() {
+ @Override
+ public void connected(XMPPConnection connection) {
+ LOGGER.log(Level.FINER, "connected");
+ state.onNext(ConnectionState.connected);
+ }
+
+ @Override
+ public void authenticated(XMPPConnection connection, boolean resumed) {
+ LOGGER.log(Level.FINER, "authenticated. resumed? " + resumed);
+ state.onNext(ConnectionState.authenticated);
+ }
+
+ @Override
+ public void connectionClosed() {
+ LOGGER.log(Level.FINER, "connectionClosed");
+ state.onNext(ConnectionState.closed);
+ }
+
+ @Override
+ public void connectionClosedOnError(Exception e) {
+ LOGGER.log(Level.WARNING, "connectionClosedOnError");
+ state.onNext(ConnectionState.closedOnError);
+ }
+ };
+
+ @Override
+ public String toString() {
+ return "MercuryConnection(" + getAccount() + ")";
+ }
+
+ public void login() throws InterruptedException, XMPPException, SmackException, IOException {
+ ((AbstractXMPPConnection) connection).connect().login();
}
public enum ConnectionState {
diff --git a/domain/src/main/java/org/mercury_im/messenger/xmpp/MercuryConnectionManager.java b/domain/src/main/java/org/mercury_im/messenger/xmpp/MercuryConnectionManager.java
index f4df1da..6024199 100644
--- a/domain/src/main/java/org/mercury_im/messenger/xmpp/MercuryConnectionManager.java
+++ b/domain/src/main/java/org/mercury_im/messenger/xmpp/MercuryConnectionManager.java
@@ -3,19 +3,17 @@ package org.mercury_im.messenger.xmpp;
import org.jivesoftware.smack.AbstractXMPPConnection;
import org.jivesoftware.smack.ReconnectionListener;
import org.jivesoftware.smack.ReconnectionManager;
-import org.jivesoftware.smack.sm.packet.StreamManagement;
-import org.jivesoftware.smackx.caps.EntityCapsManager;
-import org.jivesoftware.smackx.iqversion.VersionManager;
-import org.jivesoftware.smackx.receipts.DeliveryReceiptManager;
-import org.jivesoftware.smackx.sid.StableUniqueStanzaIdManager;
-import org.mercury_im.messenger.data.repository.AccountRepository;
+import org.jivesoftware.smack.SmackException;
+import org.jivesoftware.smack.XMPPException;
+import org.jivesoftware.smack.sasl.SASLErrorException;
+import org.jivesoftware.smack.util.Async;
+import org.jivesoftware.smackx.csi.ClientStateIndicationManager;
+import org.mercury_im.messenger.ClientStateListener;
import org.mercury_im.messenger.data.repository.Repositories;
import org.mercury_im.messenger.entity.Account;
-import org.mercury_im.messenger.store.MercuryEntityCapsStore;
-import org.mercury_im.messenger.usecase.LogIntoAccount;
-import org.mercury_im.messenger.usecase.RosterStoreBinder;
-import org.mercury_im.messenger.util.Optional;
+import org.mercury_im.messenger.store.RosterStoreBinder;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@@ -29,85 +27,38 @@ import javax.inject.Singleton;
import io.reactivex.Observable;
import io.reactivex.disposables.CompositeDisposable;
+import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
-import io.reactivex.subjects.BehaviorSubject;
@Singleton
-public class MercuryConnectionManager {
+public class MercuryConnectionManager implements ClientStateListener {
private static final Logger LOGGER = Logger.getLogger("ConnectionManager");
+ private static final XmppConnectionFactory connectionFactory = new XmppConnectionFactory();
private final Map connections = new ConcurrentHashMap<>();
- private final BehaviorSubject