Prototype account details
This commit is contained in:
parent
669aa061ab
commit
b0ee219721
|
@ -5,7 +5,9 @@ import android.content.Intent;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
|
|
||||||
import org.jivesoftware.smack.android.AndroidSmackInitializer;
|
import org.jivesoftware.smack.android.AndroidSmackInitializer;
|
||||||
|
import org.jivesoftware.smackx.ping.android.ServerPingWithAlarmManager;
|
||||||
import org.mercury_im.messenger.android.di.component.DaggerAppComponent;
|
import org.mercury_im.messenger.android.di.component.DaggerAppComponent;
|
||||||
|
import org.mercury_im.messenger.android.util.AndroidLoggingHandler;
|
||||||
import org.mercury_im.messenger.core.Messenger;
|
import org.mercury_im.messenger.core.Messenger;
|
||||||
import org.mercury_im.messenger.core.data.repository.AccountRepository;
|
import org.mercury_im.messenger.core.data.repository.AccountRepository;
|
||||||
import org.mercury_im.messenger.android.di.component.AppComponent;
|
import org.mercury_im.messenger.android.di.component.AppComponent;
|
||||||
|
@ -43,11 +45,13 @@ public class MercuryImApplication extends Application {
|
||||||
public void onCreate() {
|
public void onCreate() {
|
||||||
super.onCreate();
|
super.onCreate();
|
||||||
AndroidSmackInitializer.initialize(getApplicationContext());
|
AndroidSmackInitializer.initialize(getApplicationContext());
|
||||||
|
AndroidLoggingHandler.reset(new AndroidLoggingHandler());
|
||||||
INSTANCE = this;
|
INSTANCE = this;
|
||||||
appComponent = createAppComponent();
|
appComponent = createAppComponent();
|
||||||
appComponent.inject(this);
|
appComponent.inject(this);
|
||||||
|
|
||||||
setupClientStateIndication();
|
setupClientStateIndication();
|
||||||
|
ServerPingWithAlarmManager.onCreate(this);
|
||||||
|
|
||||||
Notifications.initializeNotificationChannels(this);
|
Notifications.initializeNotificationChannels(this);
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@ package org.mercury_im.messenger.android.di.component;
|
||||||
import org.mercury_im.messenger.android.MercuryImApplication;
|
import org.mercury_im.messenger.android.MercuryImApplication;
|
||||||
import org.mercury_im.messenger.android.di.module.AndroidDatabaseModule;
|
import org.mercury_im.messenger.android.di.module.AndroidDatabaseModule;
|
||||||
import org.mercury_im.messenger.android.di.module.AndroidSchedulersModule;
|
import org.mercury_im.messenger.android.di.module.AndroidSchedulersModule;
|
||||||
|
import org.mercury_im.messenger.android.ui.ox.AndroidOxSecretKeyBackupRestoreViewModel;
|
||||||
import org.mercury_im.messenger.core.di.module.RxMercuryMessageStoreFactoryModule;
|
import org.mercury_im.messenger.core.di.module.RxMercuryMessageStoreFactoryModule;
|
||||||
import org.mercury_im.messenger.core.di.module.RxMercuryRosterStoreFactoryModule;
|
import org.mercury_im.messenger.core.di.module.RxMercuryRosterStoreFactoryModule;
|
||||||
import org.mercury_im.messenger.core.di.module.XmppTcpConnectionFactoryModule;
|
import org.mercury_im.messenger.core.di.module.XmppTcpConnectionFactoryModule;
|
||||||
|
@ -80,6 +81,8 @@ public interface AppComponent {
|
||||||
|
|
||||||
void inject(ContactDetailViewModel contactDetailViewModel);
|
void inject(ContactDetailViewModel contactDetailViewModel);
|
||||||
|
|
||||||
|
//void inject(AndroidOxSecretKeyBackupRestoreViewModel viewModel);
|
||||||
|
|
||||||
|
|
||||||
// Common VMs
|
// Common VMs
|
||||||
void inject(LoginViewModel loginViewModel);
|
void inject(LoginViewModel loginViewModel);
|
||||||
|
|
|
@ -30,7 +30,6 @@ public class AndroidSchedulersModule {
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Named(value = SchedulersFacade.SCHEDULER_NEW_THREAD)
|
@Named(value = SchedulersFacade.SCHEDULER_NEW_THREAD)
|
||||||
@Singleton
|
|
||||||
static Scheduler provideNewThread() {
|
static Scheduler provideNewThread() {
|
||||||
return Schedulers.newThread();
|
return Schedulers.newThread();
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@ package org.mercury_im.messenger.android.di.module;
|
||||||
|
|
||||||
import android.app.Application;
|
import android.app.Application;
|
||||||
|
|
||||||
import org.jivesoftware.smackx.ping.android.ServerPingWithAlarmManager;
|
|
||||||
import org.mercury_im.messenger.android.MercuryImApplication;
|
import org.mercury_im.messenger.android.MercuryImApplication;
|
||||||
|
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
|
@ -17,7 +16,6 @@ public class AppModule {
|
||||||
|
|
||||||
public AppModule(MercuryImApplication application) {
|
public AppModule(MercuryImApplication application) {
|
||||||
this.mApplication = application;
|
this.mApplication = application;
|
||||||
ServerPingWithAlarmManager.onCreate(application);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
|
|
|
@ -15,6 +15,7 @@ import com.google.android.material.navigation.NavigationView;
|
||||||
|
|
||||||
import org.mercury_im.messenger.android.MercuryImApplication;
|
import org.mercury_im.messenger.android.MercuryImApplication;
|
||||||
import org.mercury_im.messenger.R;
|
import org.mercury_im.messenger.R;
|
||||||
|
import org.mercury_im.messenger.android.ui.account.AccountDetailsFragment;
|
||||||
import org.mercury_im.messenger.android.ui.account.DeleteAccountDialogFragment;
|
import org.mercury_im.messenger.android.ui.account.DeleteAccountDialogFragment;
|
||||||
import org.mercury_im.messenger.android.ui.account.OnAccountListItemClickListener;
|
import org.mercury_im.messenger.android.ui.account.OnAccountListItemClickListener;
|
||||||
import org.mercury_im.messenger.core.data.repository.AccountRepository;
|
import org.mercury_im.messenger.core.data.repository.AccountRepository;
|
||||||
|
@ -101,7 +102,7 @@ public class MainActivity extends AppCompatActivity
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onAccountListItemClick(Account item) {
|
public void onAccountListItemClick(Account item) {
|
||||||
|
getSupportFragmentManager().beginTransaction().replace(R.id.fragment, new AccountDetailsFragment()).commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
package org.mercury_im.messenger.android.ui.account;
|
||||||
|
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.Button;
|
||||||
|
import android.widget.ListView;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.fragment.app.Fragment;
|
||||||
|
|
||||||
|
import org.mercury_im.messenger.R;
|
||||||
|
|
||||||
|
import butterknife.BindView;
|
||||||
|
import butterknife.ButterKnife;
|
||||||
|
import de.hdodenhof.circleimageview.CircleImageView;
|
||||||
|
|
||||||
|
public class AccountDetailsFragment extends Fragment {
|
||||||
|
|
||||||
|
@BindView(R.id.avatar)
|
||||||
|
CircleImageView avatar;
|
||||||
|
|
||||||
|
@BindView(R.id.jid)
|
||||||
|
TextView jid;
|
||||||
|
|
||||||
|
@BindView(R.id.btn_share)
|
||||||
|
Button localFingerprintShareButton;
|
||||||
|
|
||||||
|
@BindView(R.id.fingerprint)
|
||||||
|
TextView localFingerprint;
|
||||||
|
|
||||||
|
@BindView(R.id.fingerprint_list)
|
||||||
|
ListView externalFingerprintList;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||||
|
View view = inflater.inflate(R.layout.fragment_account_details, container, false);
|
||||||
|
ButterKnife.bind(this, view);
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
}
|
|
@ -98,7 +98,6 @@ public class AccountsFragment extends Fragment {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void displayAddAccountDialog() {
|
private void displayAddAccountDialog() {
|
||||||
Logger.getAnonymousLogger().log(Level.INFO, "DISPLAY FRAGMENT!!!");
|
|
||||||
AddAccountDialogFragment addAccountDialogFragment = new AddAccountDialogFragment();
|
AddAccountDialogFragment addAccountDialogFragment = new AddAccountDialogFragment();
|
||||||
addAccountDialogFragment.show(getParentFragmentManager(), "addAccount");
|
addAccountDialogFragment.show(getParentFragmentManager(), "addAccount");
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,9 +65,6 @@ public class AccountsRecyclerViewAdapter extends RecyclerView.Adapter<AccountsRe
|
||||||
holder.enabled.setOnCheckedChangeListener((compoundButton, checked) ->
|
holder.enabled.setOnCheckedChangeListener((compoundButton, checked) ->
|
||||||
viewModel.setAccountEnabled(account, checked));
|
viewModel.setAccountEnabled(account, checked));
|
||||||
holder.status.setText(viewItem.getConnectivityState().toString());
|
holder.status.setText(viewItem.getConnectivityState().toString());
|
||||||
if (viewItem.getFingerprint() != null) {
|
|
||||||
holder.fingerprint.setText(OpenPgpFingerprintColorizer.formatOpenPgpV4Fingerprint(viewItem.getFingerprint()));
|
|
||||||
}
|
|
||||||
|
|
||||||
holder.mView.setOnLongClickListener(v -> {
|
holder.mView.setOnLongClickListener(v -> {
|
||||||
onAccountClickListener.onAccountListItemLongClick(account);
|
onAccountClickListener.onAccountListItemLongClick(account);
|
||||||
|
@ -83,7 +80,6 @@ public class AccountsRecyclerViewAdapter extends RecyclerView.Adapter<AccountsRe
|
||||||
final TextView jid;
|
final TextView jid;
|
||||||
final Switch enabled;
|
final Switch enabled;
|
||||||
final TextView status;
|
final TextView status;
|
||||||
final TextView fingerprint;
|
|
||||||
|
|
||||||
public ViewHolder(View view) {
|
public ViewHolder(View view) {
|
||||||
super(view);
|
super(view);
|
||||||
|
@ -92,7 +88,6 @@ public class AccountsRecyclerViewAdapter extends RecyclerView.Adapter<AccountsRe
|
||||||
jid = view.findViewById(R.id.text_account_jid);
|
jid = view.findViewById(R.id.text_account_jid);
|
||||||
enabled = view.findViewById(R.id.switch_account_enabled);
|
enabled = view.findViewById(R.id.switch_account_enabled);
|
||||||
status = view.findViewById(R.id.text_account_status);
|
status = view.findViewById(R.id.text_account_status);
|
||||||
fingerprint = view.findViewById(R.id.fingerprint);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.EditText;
|
import android.widget.EditText;
|
||||||
import android.widget.ImageButton;
|
import android.widget.ImageButton;
|
||||||
|
import android.widget.ListView;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
|
@ -45,7 +45,6 @@ public class ChatListRecyclerViewAdapter
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBindViewHolder(@NonNull ChatHolder holder, int position) {
|
public void onBindViewHolder(@NonNull ChatHolder holder, int position) {
|
||||||
Logger.getAnonymousLogger().log(Level.INFO, "BIND");
|
|
||||||
DirectChat model = getItemAt(position);
|
DirectChat model = getItemAt(position);
|
||||||
String name = model.getPeer().getDisplayName();
|
String name = model.getPeer().getDisplayName();
|
||||||
String address = model.getPeer().getAddress();
|
String address = model.getPeer().getAddress();
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
package org.mercury_im.messenger.android.ui.ox;
|
||||||
|
|
||||||
|
import android.app.Application;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.lifecycle.AndroidViewModel;
|
||||||
|
import androidx.lifecycle.MutableLiveData;
|
||||||
|
|
||||||
|
import org.mercury_im.messenger.android.MercuryImApplication;
|
||||||
|
import org.mercury_im.messenger.android.ui.MercuryAndroidViewModel;
|
||||||
|
import org.mercury_im.messenger.core.util.Optional;
|
||||||
|
import org.mercury_im.messenger.core.viewmodel.ox.OxBackupRestoreError;
|
||||||
|
import org.mercury_im.messenger.core.viewmodel.ox.OxSecretKeyBackupRestoreViewModel;
|
||||||
|
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
public class AndroidOxSecretKeyBackupRestoreViewModel extends AndroidViewModel
|
||||||
|
implements MercuryAndroidViewModel<OxSecretKeyBackupRestoreViewModel> {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = Logger.getLogger(AndroidOxSecretKeyBackupRestoreViewModel.class.getName());
|
||||||
|
|
||||||
|
//@Inject
|
||||||
|
OxSecretKeyBackupRestoreViewModel commonViewModel;
|
||||||
|
|
||||||
|
private MutableLiveData<Optional<OxBackupRestoreError>> restoreError =
|
||||||
|
new MutableLiveData<>(new Optional<>());
|
||||||
|
|
||||||
|
public AndroidOxSecretKeyBackupRestoreViewModel(@NonNull Application application) {
|
||||||
|
super(application);
|
||||||
|
//MercuryImApplication.getApplication().getAppComponent().inject(this);
|
||||||
|
|
||||||
|
addDisposable(getCommonViewModel().observeBackupRestoreError()
|
||||||
|
.subscribe(opt -> restoreError.postValue(opt),
|
||||||
|
e -> LOGGER.log(Level.SEVERE, "Could not subscribe android view model to backup restore errors", e)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public OxSecretKeyBackupRestoreViewModel getCommonViewModel() {
|
||||||
|
return commonViewModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onRestoreCodeEntered(String code) {
|
||||||
|
getCommonViewModel().onRestoreCodeEntered(code);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
package org.mercury_im.messenger.android.ui.ox;
|
||||||
|
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.Button;
|
||||||
|
import android.widget.EditText;
|
||||||
|
import android.widget.ImageButton;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import androidx.appcompat.widget.Toolbar;
|
||||||
|
import androidx.fragment.app.Fragment;
|
||||||
|
|
||||||
|
import org.mercury_im.messenger.R;
|
||||||
|
|
||||||
|
import butterknife.BindView;
|
||||||
|
import butterknife.ButterKnife;
|
||||||
|
|
||||||
|
public class OxSecretKeyBackupRestoreFragment extends Fragment {
|
||||||
|
|
||||||
|
@BindView(R.id.toolbar)
|
||||||
|
Toolbar toolbar;
|
||||||
|
|
||||||
|
@BindView(R.id.backup_code)
|
||||||
|
EditText backupCode;
|
||||||
|
|
||||||
|
@BindView(R.id.btn_scan)
|
||||||
|
ImageButton scanButton;
|
||||||
|
|
||||||
|
@BindView(R.id.btn_cancel)
|
||||||
|
Button cancelButton;
|
||||||
|
|
||||||
|
@BindView(R.id.btn_continue)
|
||||||
|
Button continueButton;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||||
|
Bundle savedInstanceState) {
|
||||||
|
View view = inflater.inflate(R.layout.fragment_ox_restore_backup, container, false);
|
||||||
|
ButterKnife.bind(this, view);
|
||||||
|
|
||||||
|
scanButton.setOnClickListener(v -> Toast.makeText(getContext(), R.string.not_yet_implemented, Toast.LENGTH_SHORT).show());
|
||||||
|
|
||||||
|
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,67 @@
|
||||||
|
package org.mercury_im.messenger.android.util;
|
||||||
|
|
||||||
|
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import java.util.logging.Handler;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.LogManager;
|
||||||
|
import java.util.logging.LogRecord;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make JUL work on Android.
|
||||||
|
*/
|
||||||
|
public class AndroidLoggingHandler extends Handler {
|
||||||
|
|
||||||
|
public static void reset(Handler rootHandler) {
|
||||||
|
Logger rootLogger = LogManager.getLogManager().getLogger("");
|
||||||
|
Handler[] handlers = rootLogger.getHandlers();
|
||||||
|
for (Handler handler : handlers) {
|
||||||
|
rootLogger.removeHandler(handler);
|
||||||
|
}
|
||||||
|
rootLogger.addHandler(rootHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void flush() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void publish(LogRecord record) {
|
||||||
|
if (!super.isLoggable(record))
|
||||||
|
return;
|
||||||
|
|
||||||
|
String name = record.getLoggerName();
|
||||||
|
int maxLength = 30;
|
||||||
|
String tag = name.length() > maxLength ? name.substring(name.length() - maxLength) : name;
|
||||||
|
|
||||||
|
try {
|
||||||
|
int level = getAndroidLevel(record.getLevel());
|
||||||
|
Log.println(level, tag, record.getMessage());
|
||||||
|
if (record.getThrown() != null) {
|
||||||
|
Log.println(level, tag, Log.getStackTraceString(record.getThrown()));
|
||||||
|
}
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
Log.e("AndroidLoggingHandler", "Error logging message.", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int getAndroidLevel(Level level) {
|
||||||
|
int value = level.intValue();
|
||||||
|
|
||||||
|
if (value >= Level.SEVERE.intValue()) {
|
||||||
|
return Log.ERROR;
|
||||||
|
} else if (value >= Level.WARNING.intValue()) {
|
||||||
|
return Log.WARN;
|
||||||
|
} else if (value >= Level.INFO.intValue()) {
|
||||||
|
return Log.INFO;
|
||||||
|
} else {
|
||||||
|
return Log.DEBUG;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:pathData="M9.5,6.5v3h-3v-3H9.5M11,5H5v6h6V5L11,5zM9.5,14.5v3h-3v-3H9.5M11,13H5v6h6V13L11,13zM17.5,6.5v3h-3v-3H17.5M19,5h-6v6h6V5L19,5zM13,13h1.5v1.5H13V13zM14.5,14.5H16V16h-1.5V14.5zM16,13h1.5v1.5H16V13zM13,16h1.5v1.5H13V16zM14.5,17.5H16V19h-1.5V17.5zM16,16h1.5v1.5H16V16zM17.5,14.5H19V16h-1.5V14.5zM17.5,17.5H19V19h-1.5V17.5zM22,7h-2V4h-3V2h5V7zM22,22v-5h-2v3h-3v2H22zM2,22h5v-2H4v-3H2V22zM2,2v5h2V4h3V2H2z"
|
||||||
|
android:fillColor="#000000"/>
|
||||||
|
</vector>
|
|
@ -0,0 +1,9 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24.0"
|
||||||
|
android:viewportHeight="24.0">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FF000000"
|
||||||
|
android:pathData="M18,16.08c-0.76,0 -1.44,0.3 -1.96,0.77L8.91,12.7c0.05,-0.23 0.09,-0.46 0.09,-0.7s-0.04,-0.47 -0.09,-0.7l7.05,-4.11c0.54,0.5 1.25,0.81 2.04,0.81 1.66,0 3,-1.34 3,-3s-1.34,-3 -3,-3 -3,1.34 -3,3c0,0.24 0.04,0.47 0.09,0.7L8.04,9.81C7.5,9.31 6.79,9 6,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3c0.79,0 1.5,-0.31 2.04,-0.81l7.12,4.16c-0.05,0.21 -0.08,0.43 -0.08,0.65 0,1.61 1.31,2.92 2.92,2.92 1.61,0 2.92,-1.31 2.92,-2.92s-1.31,-2.92 -2.92,-2.92z"/>
|
||||||
|
</vector>
|
|
@ -1,32 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<LinearLayout
|
|
||||||
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:orientation="vertical"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent">
|
|
||||||
|
|
||||||
|
|
||||||
<com.google.android.material.textfield.TextInputLayout
|
|
||||||
android:id="@+id/input_layout_jid"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="8dp"
|
|
||||||
android:layout_marginTop="8dp"
|
|
||||||
android:layout_marginEnd="8dp"
|
|
||||||
android:layout_marginBottom="4dp">
|
|
||||||
|
|
||||||
<EditText
|
|
||||||
android:id="@+id/input_jid"
|
|
||||||
android:inputType="textEmailAddress"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:hint="@string/prompt_jid"
|
|
||||||
tools:text="alice@wonderland.lit" />
|
|
||||||
|
|
||||||
</com.google.android.material.textfield.TextInputLayout>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="12dp">
|
||||||
|
|
||||||
|
<de.hdodenhof.circleimageview.CircleImageView
|
||||||
|
android:id="@+id/avatar"
|
||||||
|
android:layout_width="196dp"
|
||||||
|
android:layout_height="196dp"
|
||||||
|
android:layout_marginTop="60dp"
|
||||||
|
android:src="@drawable/aldrin"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/jid"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Title"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintHorizontal_bias="0.497"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/avatar"
|
||||||
|
tools:text="aldrin@mercury.im" />
|
||||||
|
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="12dp"
|
||||||
|
android:orientation="vertical"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/jid">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.SearchResult.Title"
|
||||||
|
android:text="Encryption Keys" />
|
||||||
|
|
||||||
|
<include layout="@layout/fragment_fingerprint_card"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:layout_marginBottom="8dp"/>
|
||||||
|
|
||||||
|
<include layout="@layout/fragment_toggleable_fingerprints_card"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:layout_marginBottom="8dp"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -0,0 +1,48 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<com.google.android.material.card.MaterialCardView
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
app:cardCornerRadius="4dp"
|
||||||
|
app:cardElevation="4dp">
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:paddingStart="12dp"
|
||||||
|
android:paddingEnd="12dp"
|
||||||
|
android:paddingTop="12dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/title"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Local Fingerprint"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<include
|
||||||
|
android:id="@+id/fingerprint"
|
||||||
|
layout="@layout/view_fingerprint"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_centerHorizontal="true"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintHorizontal_bias="0.5"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/title" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/btn_share"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="share"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/fingerprint" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
</com.google.android.material.card.MaterialCardView>
|
|
@ -0,0 +1,86 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:orientation="vertical" android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.Toolbar
|
||||||
|
android:id="@+id/toolbar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="?attr/actionBarSize"
|
||||||
|
android:background="?attr/colorPrimary"
|
||||||
|
android:elevation="4dp"
|
||||||
|
android:theme="@style/Theme.Mercury" />
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/input"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="12dp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="A secret key backup was found on the server. Please enter your OX backup code to restore the key on this device." />
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/backup_code"
|
||||||
|
android:inputType="textNoSuggestions"
|
||||||
|
android:hint="TWNK-KD5Y-MT3T-E1GS-DRDB-KVTW"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:layout_toStartOf="@+id/btn_scan" />
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/btn_scan"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_alignParentEnd="true"
|
||||||
|
android:background="@drawable/ic_qr_code_scanner_black_24dp"
|
||||||
|
android:minWidth="48dp"
|
||||||
|
android:minHeight="48dp" />
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/buttons"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:gravity="end"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/input">
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/btn_cancel"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/button_cancel" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/btn_continue"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Continue" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
|
@ -0,0 +1,41 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<com.google.android.material.card.MaterialCardView
|
||||||
|
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:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
app:cardCornerRadius="4dp"
|
||||||
|
app:cardElevation="4dp">
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:paddingStart="12dp"
|
||||||
|
android:paddingEnd="12dp"
|
||||||
|
android:paddingTop="12dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/title"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Other Fingerprints"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<ListView
|
||||||
|
android:id="@+id/fingerprint_list"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
tools:listitem="@layout/view_toggleable_fingerprint"
|
||||||
|
android:layout_centerHorizontal="true"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintHorizontal_bias="0.5"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/title"/>
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
</com.google.android.material.card.MaterialCardView>
|
|
@ -62,20 +62,4 @@
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center"
|
|
||||||
android:textAppearance="@style/TextAppearance.MaterialComponents.Subtitle1"
|
|
||||||
android:text="Fingerprint" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/fingerprint"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center"
|
|
||||||
android:textSize="20dp"
|
|
||||||
android:typeface="monospace"
|
|
||||||
tools:text="1357 B018 65B2 503C 1845\n3D20 8CAC 2A96 7854 8E35" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
|
@ -0,0 +1,10 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:id="@+id/fingerprint"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:textSize="18sp"
|
||||||
|
android:typeface="monospace"
|
||||||
|
tools:text="1357 B018 65B2 503C 1845\n3D20 8CAC 2A96 7854 8E35" />
|
|
@ -0,0 +1,36 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<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:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<include
|
||||||
|
android:id="@+id/include"
|
||||||
|
layout="@layout/view_fingerprint"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_marginVertical="4dp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<Switch
|
||||||
|
android:id="@+id/toggle"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
android:layout_marginEnd="4dp"/>
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:id="@+id/divider"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="1dp"
|
||||||
|
android:background="?android:attr/listDivider"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent" />
|
||||||
|
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -3,7 +3,13 @@ package org.mercury_im.messenger.core;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Named;
|
import javax.inject.Named;
|
||||||
|
|
||||||
|
import io.reactivex.CompletableTransformer;
|
||||||
|
import io.reactivex.MaybeTransformer;
|
||||||
|
import io.reactivex.Observable;
|
||||||
|
import io.reactivex.ObservableSource;
|
||||||
|
import io.reactivex.ObservableTransformer;
|
||||||
import io.reactivex.Scheduler;
|
import io.reactivex.Scheduler;
|
||||||
|
import io.reactivex.SingleTransformer;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
public class SchedulersFacade {
|
public class SchedulersFacade {
|
||||||
|
@ -39,4 +45,20 @@ public class SchedulersFacade {
|
||||||
this.uiScheduler = uiScheduler;
|
this.uiScheduler = uiScheduler;
|
||||||
this.newThread = newThread;
|
this.newThread = newThread;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public <A> ObservableTransformer<A, A> executeUiSafeObservable() {
|
||||||
|
return upstream -> upstream.subscribeOn(ioScheduler).observeOn(uiScheduler);
|
||||||
|
}
|
||||||
|
|
||||||
|
public <A> SingleTransformer<A, A> executeUiSafeSingle() {
|
||||||
|
return upstream -> upstream.subscribeOn(ioScheduler).observeOn(uiScheduler);
|
||||||
|
}
|
||||||
|
|
||||||
|
public <A> MaybeTransformer<A, A> executeUiSafeMaybe() {
|
||||||
|
return upstream -> upstream.subscribeOn(ioScheduler).observeOn(uiScheduler);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompletableTransformer executeUiSafeCompletable() {
|
||||||
|
return upstream -> upstream.subscribeOn(ioScheduler).observeOn(uiScheduler);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
package org.mercury_im.messenger.core.crypto;
|
package org.mercury_im.messenger.core.crypto;
|
||||||
|
|
||||||
import org.bouncycastle.openpgp.PGPPublicKeyRing;
|
|
||||||
import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
|
|
||||||
import org.jivesoftware.smack.AbstractConnectionListener;
|
import org.jivesoftware.smack.AbstractConnectionListener;
|
||||||
import org.jivesoftware.smack.XMPPConnection;
|
import org.jivesoftware.smack.XMPPConnection;
|
||||||
import org.jivesoftware.smackx.ox.OpenPgpManager;
|
import org.jivesoftware.smackx.ox.OpenPgpManager;
|
||||||
|
@ -19,7 +17,6 @@ import org.mercury_im.messenger.core.data.repository.Repositories;
|
||||||
import org.mercury_im.messenger.core.store.crypto.MercuryOpenPgpStore;
|
import org.mercury_im.messenger.core.store.crypto.MercuryOpenPgpStore;
|
||||||
import org.mercury_im.messenger.core.store.message.MercuryMessageStore;
|
import org.mercury_im.messenger.core.store.message.MercuryMessageStore;
|
||||||
import org.mercury_im.messenger.core.xmpp.MercuryConnection;
|
import org.mercury_im.messenger.core.xmpp.MercuryConnection;
|
||||||
import org.pgpainless.key.OpenPgpV4Fingerprint;
|
|
||||||
|
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
package org.mercury_im.messenger.core.di.component;
|
||||||
|
|
||||||
|
import org.mercury_im.messenger.core.di.scope.AccountScope;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import dagger.BindsInstance;
|
||||||
|
import dagger.Component;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public interface ConnectionComponent {
|
||||||
|
|
||||||
|
ConnectionComponent getComponent();
|
||||||
|
|
||||||
|
@Component.Builder
|
||||||
|
interface Builder {
|
||||||
|
|
||||||
|
@BindsInstance Builder withAccount(@AccountScope UUID accountId);
|
||||||
|
|
||||||
|
ConnectionComponent build();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -3,18 +3,14 @@ package org.mercury_im.messenger.core.di.module;
|
||||||
import org.mercury_im.messenger.core.SchedulersFacade;
|
import org.mercury_im.messenger.core.SchedulersFacade;
|
||||||
import org.mercury_im.messenger.core.data.repository.AccountRepository;
|
import org.mercury_im.messenger.core.data.repository.AccountRepository;
|
||||||
import org.mercury_im.messenger.core.data.repository.OpenPgpRepository;
|
import org.mercury_im.messenger.core.data.repository.OpenPgpRepository;
|
||||||
import org.mercury_im.messenger.core.data.repository.Repositories;
|
|
||||||
import org.mercury_im.messenger.core.viewmodel.accounts.AccountsViewModel;
|
import org.mercury_im.messenger.core.viewmodel.accounts.AccountsViewModel;
|
||||||
import org.mercury_im.messenger.core.viewmodel.accounts.LoginViewModel;
|
import org.mercury_im.messenger.core.viewmodel.accounts.LoginViewModel;
|
||||||
import org.mercury_im.messenger.core.viewmodel.chat.ChatViewModel;
|
|
||||||
import org.mercury_im.messenger.core.xmpp.MercuryConnectionManager;
|
import org.mercury_im.messenger.core.xmpp.MercuryConnectionManager;
|
||||||
|
|
||||||
import javax.inject.Named;
|
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
import dagger.Module;
|
import dagger.Module;
|
||||||
import dagger.Provides;
|
import dagger.Provides;
|
||||||
import io.reactivex.Scheduler;
|
|
||||||
|
|
||||||
@Module
|
@Module
|
||||||
public class ViewModelModule {
|
public class ViewModelModule {
|
||||||
|
@ -36,12 +32,19 @@ public class ViewModelModule {
|
||||||
return new AccountsViewModel(connectionManager, accountRepository, openPgpRepository, schedulers);
|
return new AccountsViewModel(connectionManager, accountRepository, openPgpRepository, schedulers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
static OxSecretKeyBackupRestoreViewModel provideOxSecretKeyBackupRestoreViewModel(OpenPgpManager openPgpManager) {
|
||||||
|
return new OxSecretKeyBackupRestoreViewModel(openPgpManager);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
static ChatViewModel provideChatViewModel(Repositories repositories, SchedulersFacade schedulers) {
|
static ChatViewModel provideChatViewModel(Repositories repositories, SchedulersFacade schedulers) {
|
||||||
return new ChatViewModel(repositories, schedulers);
|
return new ChatViewModel(repositories, schedulers);
|
||||||
}
|
}
|
||||||
|
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
package org.mercury_im.messenger.core.di.scope;
|
||||||
|
|
||||||
|
import java.lang.annotation.Documented;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
|
||||||
|
import javax.inject.Scope;
|
||||||
|
|
||||||
|
@Scope
|
||||||
|
@Documented
|
||||||
|
@Retention(value = RetentionPolicy.RUNTIME)
|
||||||
|
public @interface AccountScope {
|
||||||
|
}
|
|
@ -48,7 +48,7 @@ public class AccountsViewModel implements MercuryViewModel {
|
||||||
|
|
||||||
public Observable<List<AccountViewItem>> observeAccounts() {
|
public Observable<List<AccountViewItem>> observeAccounts() {
|
||||||
return connectionManager.observeConnectionPool()
|
return connectionManager.observeConnectionPool()
|
||||||
.compose(transformer);
|
.compose(toAccountViewItems);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onToggleAccountEnabled(Account account, boolean enabled) {
|
public void onToggleAccountEnabled(Account account, boolean enabled) {
|
||||||
|
@ -64,14 +64,14 @@ public class AccountsViewModel implements MercuryViewModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void logAccountToggledSuccess(Account account, boolean enabled) {
|
private void logAccountToggledSuccess(Account account, boolean enabled) {
|
||||||
LOGGER.log(Level.FINER, "Account " + account.getAddress() + (enabled ? " enabled" : " disabled"));
|
LOGGER.log(Level.INFO, "Account " + account.getAddress() + (enabled ? " enabled" : " disabled"));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void logAccountToggleError(Account account, boolean enabled, Throwable error) {
|
private void logAccountToggleError(Account account, boolean enabled, Throwable error) {
|
||||||
LOGGER.log(Level.SEVERE, "Account " + account.getAddress() + " could not be " + (enabled ? "enabled" : "disabled"), error);
|
LOGGER.log(Level.SEVERE, "Account " + account.getAddress() + " could not be " + (enabled ? "enabled" : "disabled"), error);
|
||||||
}
|
}
|
||||||
|
|
||||||
private final ObservableTransformer<ConnectionPoolState, List<AccountViewItem>> transformer = new ObservableTransformer<ConnectionPoolState, List<AccountViewItem>>() {
|
private final ObservableTransformer<ConnectionPoolState, List<AccountViewItem>> toAccountViewItems = new ObservableTransformer<ConnectionPoolState, List<AccountViewItem>>() {
|
||||||
@Override
|
@Override
|
||||||
public ObservableSource<List<AccountViewItem>> apply(Observable<ConnectionPoolState> upstream) {
|
public ObservableSource<List<AccountViewItem>> apply(Observable<ConnectionPoolState> upstream) {
|
||||||
return upstream.map(state -> {
|
return upstream.map(state -> {
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
package org.mercury_im.messenger.core.viewmodel.ox;
|
||||||
|
|
||||||
|
public enum OxBackupRestoreError {
|
||||||
|
|
||||||
|
invalid_backup_code,
|
||||||
|
no_backup_found,
|
||||||
|
invalid_user_id_on_key,
|
||||||
|
pgp_error,
|
||||||
|
not_authenticated_error,
|
||||||
|
protocol_error,
|
||||||
|
other_error
|
||||||
|
}
|
|
@ -0,0 +1,70 @@
|
||||||
|
package org.mercury_im.messenger.core.viewmodel.ox;
|
||||||
|
|
||||||
|
import org.bouncycastle.openpgp.PGPException;
|
||||||
|
import org.jivesoftware.smack.SmackException;
|
||||||
|
import org.jivesoftware.smack.XMPPException;
|
||||||
|
import org.jivesoftware.smackx.ox.OpenPgpManager;
|
||||||
|
import org.jivesoftware.smackx.ox.exception.InvalidBackupCodeException;
|
||||||
|
import org.jivesoftware.smackx.ox.exception.MissingUserIdOnKeyException;
|
||||||
|
import org.jivesoftware.smackx.ox.exception.NoBackupFoundException;
|
||||||
|
import org.jivesoftware.smackx.pubsub.PubSubException;
|
||||||
|
import org.mercury_im.messenger.core.util.Optional;
|
||||||
|
import org.mercury_im.messenger.core.viewmodel.MercuryViewModel;
|
||||||
|
import org.pgpainless.key.OpenPgpV4Fingerprint;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import io.reactivex.Observable;
|
||||||
|
import io.reactivex.subjects.BehaviorSubject;
|
||||||
|
|
||||||
|
public class OxSecretKeyBackupRestoreViewModel implements MercuryViewModel {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = Logger.getLogger(OxSecretKeyBackupRestoreViewModel.class.getName());
|
||||||
|
|
||||||
|
private final OpenPgpManager openPgpManager;
|
||||||
|
|
||||||
|
private BehaviorSubject<Optional<OxBackupRestoreError>> backupRestoreError = BehaviorSubject.createDefault(new Optional<>());
|
||||||
|
private BehaviorSubject<Boolean> finished = BehaviorSubject.createDefault(false);
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public OxSecretKeyBackupRestoreViewModel(OpenPgpManager openPgpManager) {
|
||||||
|
this.openPgpManager = openPgpManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Observable<Optional<OxBackupRestoreError>> observeBackupRestoreError() {
|
||||||
|
return backupRestoreError;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onRestoreCodeEntered(String code) {
|
||||||
|
try {
|
||||||
|
OpenPgpV4Fingerprint fingerprint = openPgpManager.restoreSecretKeyServerBackup(() -> code);
|
||||||
|
LOGGER.log(Level.INFO, "Successfully restored OX secret key " + fingerprint + " for " + openPgpManager.getOpenPgpSelf().getJid());
|
||||||
|
finished.onNext(true);
|
||||||
|
} catch (InvalidBackupCodeException e) {
|
||||||
|
LOGGER.log(Level.FINE, "Invalid backup code entered.");
|
||||||
|
backupRestoreError.onNext(new Optional<>(OxBackupRestoreError.invalid_backup_code));
|
||||||
|
} catch (MissingUserIdOnKeyException e) {
|
||||||
|
LOGGER.log(Level.WARNING, "Invalid or missing user ID on key.", e);
|
||||||
|
backupRestoreError.onNext(new Optional<>(OxBackupRestoreError.invalid_user_id_on_key));
|
||||||
|
} catch (NoBackupFoundException e) {
|
||||||
|
LOGGER.log(Level.FINE, "No secret key backup found.", e);
|
||||||
|
backupRestoreError.onNext(new Optional<>(OxBackupRestoreError.no_backup_found));
|
||||||
|
} catch (PGPException e) {
|
||||||
|
LOGGER.log(Level.WARNING, "PGP error while restoring key from server backup.", e);
|
||||||
|
backupRestoreError.onNext(new Optional<>(OxBackupRestoreError.pgp_error));
|
||||||
|
} catch (InterruptedException | IOException e) {
|
||||||
|
LOGGER.log(Level.SEVERE, "Error occurred while restoring key.", e);
|
||||||
|
backupRestoreError.onNext(new Optional<>(OxBackupRestoreError.other_error));
|
||||||
|
} catch (PubSubException.NotALeafNodeException | XMPPException.XMPPErrorException | SmackException.NoResponseException e) {
|
||||||
|
LOGGER.log(Level.WARNING, "Network related error encountered while restoring OX secret key.", e);
|
||||||
|
backupRestoreError.onNext(new Optional<>(OxBackupRestoreError.protocol_error));
|
||||||
|
} catch (SmackException.NotConnectedException | SmackException.NotLoggedInException e) {
|
||||||
|
LOGGER.log(Level.FINE, "Cannot restore OX secret key while not logged in.", e);
|
||||||
|
backupRestoreError.onNext(new Optional<>(OxBackupRestoreError.not_authenticated_error));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -26,7 +26,7 @@ import lombok.Getter;
|
||||||
|
|
||||||
public class MercuryConnection {
|
public class MercuryConnection {
|
||||||
|
|
||||||
private static final Logger LOGGER = Logger.getLogger("MercuryConnection");
|
private static final Logger LOGGER = Logger.getLogger(MercuryConnection.class.getName());
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
private XMPPConnection connection;
|
private XMPPConnection connection;
|
||||||
|
@ -34,13 +34,13 @@ public class MercuryConnection {
|
||||||
@Getter
|
@Getter
|
||||||
private final Account account;
|
private final Account account;
|
||||||
|
|
||||||
private final BehaviorSubject<ConnectionState> state;
|
private final BehaviorSubject<ConnectionState> stateObservable;
|
||||||
|
|
||||||
public MercuryConnection(XMPPConnection connection, Account account) {
|
public MercuryConnection(XMPPConnection connection, Account account) {
|
||||||
this.connection = connection;
|
this.connection = connection;
|
||||||
this.account = account;
|
this.account = account;
|
||||||
|
|
||||||
this.state = BehaviorSubject.createDefault(new ConnectionState(account.getId(), this,
|
this.stateObservable = BehaviorSubject.createDefault(new ConnectionState(account.getId(), this,
|
||||||
ConnectivityState.disconnected, false, false));
|
ConnectivityState.disconnected, false, false));
|
||||||
connection.addConnectionListener(connectionListener);
|
connection.addConnectionListener(connectionListener);
|
||||||
}
|
}
|
||||||
|
@ -50,7 +50,7 @@ public class MercuryConnection {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Observable<ConnectionState> observeConnection() {
|
public Observable<ConnectionState> observeConnection() {
|
||||||
return state;
|
return stateObservable;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Completable connect() {
|
public Completable connect() {
|
||||||
|
@ -58,14 +58,12 @@ public class MercuryConnection {
|
||||||
.doOnError(error -> LOGGER.log(Level.WARNING, "Connection error for account " + account, error));
|
.doOnError(error -> LOGGER.log(Level.WARNING, "Connection error for account " + account, error));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void doConnect() throws ServerUnreachableException {
|
private synchronized void doConnect() throws ServerUnreachableException {
|
||||||
state.onNext(state.getValue().withConnectivity(ConnectivityState.connecting));
|
|
||||||
AbstractXMPPConnection connection = (AbstractXMPPConnection) getConnection();
|
AbstractXMPPConnection connection = (AbstractXMPPConnection) getConnection();
|
||||||
if (connection.isConnected()) {
|
if (connection.isConnected()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
LOGGER.log(Level.INFO, "Connected!");
|
|
||||||
connection.connect();
|
connection.connect();
|
||||||
} catch (SmackException.EndpointConnectionException e) {
|
} catch (SmackException.EndpointConnectionException e) {
|
||||||
connection.disconnect();
|
connection.disconnect();
|
||||||
|
@ -73,6 +71,8 @@ public class MercuryConnection {
|
||||||
} catch (IOException | InterruptedException | XMPPException | SmackException e) {
|
} catch (IOException | InterruptedException | XMPPException | SmackException e) {
|
||||||
throw new AssertionError("Unexpected exception.", e);
|
throw new AssertionError("Unexpected exception.", e);
|
||||||
}
|
}
|
||||||
|
stateObservable.onNext(stateObservable.getValue().withConnectivity(ConnectivityState.connecting));
|
||||||
|
LOGGER.log(Level.INFO, "Connected!");
|
||||||
}
|
}
|
||||||
|
|
||||||
public Completable login() {
|
public Completable login() {
|
||||||
|
@ -80,7 +80,7 @@ public class MercuryConnection {
|
||||||
.doOnError(error -> LOGGER.log(Level.WARNING, "Login error for account " + account, error));
|
.doOnError(error -> LOGGER.log(Level.WARNING, "Login error for account " + account, error));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void doLogin() throws InvalidCredentialsException {
|
private synchronized void doLogin() throws InvalidCredentialsException {
|
||||||
if (connection.isAuthenticated()) {
|
if (connection.isAuthenticated()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -98,7 +98,7 @@ public class MercuryConnection {
|
||||||
.doOnError(error -> LOGGER.log(Level.WARNING, "Shutdown error for account " + account, error));
|
.doOnError(error -> LOGGER.log(Level.WARNING, "Shutdown error for account " + account, error));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void doShutdown() {
|
public synchronized void doShutdown() {
|
||||||
if (connection.isConnected()) {
|
if (connection.isConnected()) {
|
||||||
((AbstractXMPPConnection) getConnection()).disconnect();
|
((AbstractXMPPConnection) getConnection()).disconnect();
|
||||||
} else {
|
} else {
|
||||||
|
@ -109,32 +109,32 @@ public class MercuryConnection {
|
||||||
private final ConnectionListener connectionListener = new ConnectionListener() {
|
private final ConnectionListener connectionListener = new ConnectionListener() {
|
||||||
@Override
|
@Override
|
||||||
public void connected(XMPPConnection connection) {
|
public void connected(XMPPConnection connection) {
|
||||||
state.onNext(state.getValue()
|
stateObservable.onNext(stateObservable.getValue()
|
||||||
.withConnectivity(ConnectivityState.connected)
|
.withConnectivity(ConnectivityState.connected)
|
||||||
.withAuthenticated(false));
|
.withAuthenticated(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void authenticated(XMPPConnection connection, boolean resumed) {
|
public void authenticated(XMPPConnection connection, boolean isResumed) {
|
||||||
state.onNext(state.getValue()
|
stateObservable.onNext(stateObservable.getValue()
|
||||||
.withConnectivity(ConnectivityState.connected)
|
.withConnectivity(ConnectivityState.connected)
|
||||||
.withAuthenticated(true)
|
.withAuthenticated(true)
|
||||||
.withResumed(resumed));
|
.withResumed(isResumed));
|
||||||
if (!resumed) {
|
if (!isResumed) {
|
||||||
initialConnectionSetup();
|
initialConnectionSetup();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void connectionClosed() {
|
public void connectionClosed() {
|
||||||
state.onNext(state.getValue()
|
stateObservable.onNext(stateObservable.getValue()
|
||||||
.withConnectivity(ConnectivityState.disconnected)
|
.withConnectivity(ConnectivityState.disconnected)
|
||||||
.withAuthenticated(false));
|
.withAuthenticated(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void connectionClosedOnError(Exception e) {
|
public void connectionClosedOnError(Exception e) {
|
||||||
state.onNext(state.getValue()
|
stateObservable.onNext(stateObservable.getValue()
|
||||||
.withConnectivity(ConnectivityState.disconnected)
|
.withConnectivity(ConnectivityState.disconnected)
|
||||||
.withAuthenticated(false));
|
.withAuthenticated(false));
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,13 +86,13 @@ public class MercuryConnectionManager {
|
||||||
start();
|
start();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void start() {
|
public synchronized void start() {
|
||||||
disposable.add(accountRepository.observeAllAccounts()
|
disposable.add(accountRepository.observeAllAccounts()
|
||||||
.subscribeOn(schedulers.getIoScheduler())
|
.subscribeOn(schedulers.getIoScheduler())
|
||||||
.subscribe(this::doRegisterConnections));
|
.subscribe(this::doRegisterConnections));
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<MercuryConnection> getConnections() {
|
public synchronized List<MercuryConnection> getConnections() {
|
||||||
return new ArrayList<>(connectionsMap.values());
|
return new ArrayList<>(connectionsMap.values());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,11 +101,11 @@ public class MercuryConnectionManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public MercuryConnection getConnection(Account account) {
|
public synchronized MercuryConnection getConnection(Account account) {
|
||||||
return getConnection(account.getId());
|
return getConnection(account.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
public MercuryConnection getConnection(UUID id) {
|
public synchronized MercuryConnection getConnection(UUID id) {
|
||||||
return connectionsMap.get(id);
|
return connectionsMap.get(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,7 +113,7 @@ public class MercuryConnectionManager {
|
||||||
return new MercuryConnection(connectionFactory.createConnection(account), account);
|
return new MercuryConnection(connectionFactory.createConnection(account), account);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void doRegisterConnections(List<Account> accounts) {
|
public synchronized void doRegisterConnections(List<Account> accounts) {
|
||||||
for (Account account : accounts) {
|
for (Account account : accounts) {
|
||||||
if (!connectionsMap.containsKey(account.getId())) {
|
if (!connectionsMap.containsKey(account.getId())) {
|
||||||
MercuryConnection connection = createConnection(account);
|
MercuryConnection connection = createConnection(account);
|
||||||
|
@ -126,7 +126,7 @@ public class MercuryConnectionManager {
|
||||||
return Completable.fromAction(() -> doRegisterConnection(connection));
|
return Completable.fromAction(() -> doRegisterConnection(connection));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void doRegisterConnection(MercuryConnection connection) {
|
public synchronized void doRegisterConnection(MercuryConnection connection) {
|
||||||
LOGGER.log(Level.INFO, "Register Connection " + connection.getAccountId());
|
LOGGER.log(Level.INFO, "Register Connection " + connection.getAccountId());
|
||||||
putConnection(connection);
|
putConnection(connection);
|
||||||
disposable.add(accountRepository
|
disposable.add(accountRepository
|
||||||
|
@ -137,20 +137,25 @@ public class MercuryConnectionManager {
|
||||||
handleOptionalAccountChangedEvent(connection, event)));
|
handleOptionalAccountChangedEvent(connection, event)));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void putConnection(MercuryConnection connection) {
|
private synchronized void putConnection(MercuryConnection connection) {
|
||||||
connectionsMap.put(connection.getAccountId(), connection);
|
connectionsMap.put(connection.getAccountId(), connection);
|
||||||
connectionDisposables.put(connection.getAccountId(), connection.observeConnection().subscribe(s ->
|
connectionDisposables.put(connection.getAccountId(), connection.observeConnection()
|
||||||
connectionPoolObservable.onNext(updatePoolState(connectionPoolObservable.getValue(), s))));
|
.subscribe(this::insertConnectionToPoolState));
|
||||||
bindConnection(connection);
|
bindConnection(connection);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ConnectionPoolState updatePoolState(ConnectionPoolState poolState, ConnectionState conState) {
|
private void insertConnectionToPoolState(ConnectionState s) {
|
||||||
|
LOGGER.log(Level.INFO, "Insert new connection to pool state: " + s);
|
||||||
|
connectionPoolObservable.onNext(updatePoolState(connectionPoolObservable.getValue(), s));
|
||||||
|
}
|
||||||
|
|
||||||
|
private synchronized ConnectionPoolState updatePoolState(ConnectionPoolState poolState, ConnectionState conState) {
|
||||||
Map<UUID, ConnectionState> states = poolState.getConnectionStates();
|
Map<UUID, ConnectionState> states = poolState.getConnectionStates();
|
||||||
states.put(conState.getId(), conState);
|
states.put(conState.getId(), conState);
|
||||||
return new ConnectionPoolState(states);
|
return new ConnectionPoolState(states);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void bindConnection(MercuryConnection connection) {
|
public synchronized void bindConnection(MercuryConnection connection) {
|
||||||
rosterStoreBinder.setRosterStoreOn(connection);
|
rosterStoreBinder.setRosterStoreOn(connection);
|
||||||
disposable.add(accountRepository.getAccount(connection.getAccountId())
|
disposable.add(accountRepository.getAccount(connection.getAccountId())
|
||||||
.subscribeOn(schedulers.getIoScheduler())
|
.subscribeOn(schedulers.getIoScheduler())
|
||||||
|
@ -164,14 +169,16 @@ public class MercuryConnectionManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleOptionalAccountChangedEvent(MercuryConnection connection, Optional<Account> event) {
|
private void handleOptionalAccountChangedEvent(MercuryConnection connection, Optional<Account> event) {
|
||||||
|
synchronized (connection) {
|
||||||
if (event.isPresent()) {
|
if (event.isPresent()) {
|
||||||
handleAccountChangedEvent(connection, event.getItem());
|
handleAccountChangedEvent(connection, event.getItem());
|
||||||
} else {
|
} else {
|
||||||
handleAccountRemoved(connection);
|
handleAccountRemoved(connection);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void handleAccountChangedEvent(MercuryConnection connection, Account account) {
|
private synchronized void handleAccountChangedEvent(MercuryConnection connection, Account account) {
|
||||||
if (account.isEnabled()) {
|
if (account.isEnabled()) {
|
||||||
handleAccountEnabled(connection);
|
handleAccountEnabled(connection);
|
||||||
} else {
|
} else {
|
||||||
|
@ -179,41 +186,46 @@ public class MercuryConnectionManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleAccountDisabled(MercuryConnection connection) {
|
private synchronized void handleAccountDisabled(MercuryConnection connection) {
|
||||||
LOGGER.log(Level.FINER, "HandleAccountDisabled: " + connection.getAccountId());
|
LOGGER.log(Level.FINER, "HandleAccountDisabled: " + connection.getAccountId());
|
||||||
disposable.add(connection.shutdown().subscribeOn(Schedulers.newThread()).subscribe());
|
disposable.add(connection.shutdown().subscribeOn(Schedulers.newThread()).subscribe());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleAccountEnabled(MercuryConnection connection) {
|
private synchronized void handleAccountEnabled(MercuryConnection connection) {
|
||||||
LOGGER.log(Level.FINER, "HandleAccountEnabled: " + connection.getAccountId());
|
LOGGER.log(Level.FINER, "HandleAccountEnabled: " + connection.getAccountId());
|
||||||
connectionLogin(connection);
|
connectionLogin(connection);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void connectionLogin(MercuryConnection connection) {
|
private synchronized void connectionLogin(MercuryConnection connection) {
|
||||||
disposable.add(connection.connect().andThen(connection.login())
|
disposable.add(connection.connect().andThen(connection.login())
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.subscribe(() -> LOGGER.log(Level.FINER, "Logged in."),
|
.subscribe(() -> LOGGER.log(Level.FINER, "Logged in."),
|
||||||
error -> LOGGER.log(Level.SEVERE, "Connection error!", error)));
|
error -> LOGGER.log(Level.SEVERE, "Connection error!", error)));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleAccountRemoved(MercuryConnection connection) {
|
private synchronized void handleAccountRemoved(MercuryConnection connection) {
|
||||||
LOGGER.log(Level.FINER, "HandleAccountRemove: " + connection.getAccountId());
|
LOGGER.log(Level.FINER, "HandleAccountRemove: " + connection.getAccountId());
|
||||||
disconnectAndRemoveConnection(connection);
|
disconnectAndRemoveConnection(connection);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void disconnectAndRemoveConnection(MercuryConnection connection) {
|
private synchronized void disconnectAndRemoveConnection(MercuryConnection connection) {
|
||||||
disposable.add(connection.shutdown().subscribeOn(Schedulers.newThread()).subscribe());
|
disposable.add(connection.shutdown().subscribeOn(Schedulers.newThread()).subscribe());
|
||||||
removeConnection(connection);
|
removeConnection(connection);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void removeConnection(MercuryConnection connection) {
|
private synchronized void removeConnection(MercuryConnection connection) {
|
||||||
LOGGER.log(Level.FINER, "Remove Connection: " + connection.getAccountId());
|
LOGGER.log(Level.FINER, "Remove Connection: " + connection.getAccountId());
|
||||||
connectionsMap.remove(connection.getAccountId());
|
connectionsMap.remove(connection.getAccountId());
|
||||||
connectionDisposables.remove(connection.getAccountId()).dispose();
|
connectionDisposables.remove(connection.getAccountId()).dispose();
|
||||||
|
removeConnectionFromPoolState();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removeConnectionFromPoolState() {
|
||||||
|
LOGGER.log(Level.INFO, "Remove connection from pool state");
|
||||||
connectionPoolObservable.onNext(updatePoolState(connectionPoolObservable.getValue()));
|
connectionPoolObservable.onNext(updatePoolState(connectionPoolObservable.getValue()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private ConnectionPoolState updatePoolState(ConnectionPoolState value) {
|
private synchronized ConnectionPoolState updatePoolState(ConnectionPoolState value) {
|
||||||
Map<UUID, ConnectionState> states = value.getConnectionStates();
|
Map<UUID, ConnectionState> states = value.getConnectionStates();
|
||||||
for (UUID id : connectionsMap.keySet()) {
|
for (UUID id : connectionsMap.keySet()) {
|
||||||
if (!states.containsKey(id)) {
|
if (!states.containsKey(id)) {
|
||||||
|
@ -223,7 +235,7 @@ public class MercuryConnectionManager {
|
||||||
return new ConnectionPoolState(states);
|
return new ConnectionPoolState(states);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void doShutdownAllConnections() {
|
public synchronized void doShutdownAllConnections() {
|
||||||
for (MercuryConnection connection : getConnections()) {
|
for (MercuryConnection connection : getConnections()) {
|
||||||
connection.doShutdown();
|
connection.doShutdown();
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ import org.jivesoftware.smackx.sid.StableUniqueStanzaIdManager;
|
||||||
public class SmackConfig {
|
public class SmackConfig {
|
||||||
|
|
||||||
static void staticConfiguration() {
|
static void staticConfiguration() {
|
||||||
SmackConfiguration.DEBUG = true;
|
SmackConfiguration.DEBUG = false;
|
||||||
ReconnectionManager.setEnabledPerDefault(true);
|
ReconnectionManager.setEnabledPerDefault(true);
|
||||||
ReconnectionManager.setDefaultReconnectionPolicy(ReconnectionManager.ReconnectionPolicy.RANDOM_INCREASING_DELAY);
|
ReconnectionManager.setDefaultReconnectionPolicy(ReconnectionManager.ReconnectionPolicy.RANDOM_INCREASING_DELAY);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue