Primitive XMPP connection

This commit is contained in:
Paul Schaub 2018-08-01 11:43:18 +02:00
parent 8e51695e69
commit 7bea4d5308
Signed by: vanitasvitae
GPG Key ID: 62BEE9264BF17311
30 changed files with 575 additions and 40 deletions

Binary file not shown.

View File

@ -0,0 +1,29 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<Objective-C-extensions>
<file>
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Import" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Macro" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Typedef" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Enum" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Constant" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Global" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Struct" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="FunctionPredecl" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Function" />
</file>
<class>
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Property" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Synthesize" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InitMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="StaticMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InstanceMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="DeallocMethod" />
</class>
<extensions>
<pair source="cpp" header="h" fileNamingConvention="NONE" />
<pair source="c" header="h" fileNamingConvention="NONE" />
</extensions>
</Objective-C-extensions>
</code_scheme>
</component>

View File

@ -24,7 +24,7 @@
</value>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">

View File

@ -8,12 +8,12 @@ buildscript {
}
ext {
smackVersion="4.2.3-SNAPSHOT"
smackVersion="4.4.0-alpha2-SNAPSHOT"
}
dependencies {
classpath 'com.android.tools.build:gradle:3.0.1'
classpath 'com.android.tools.build:gradle:3.1.3'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}

View File

@ -1,6 +1,6 @@
#Mon Jan 22 17:04:57 CET 2018
#Wed Aug 01 11:38:19 CEST 2018
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip

View File

@ -29,18 +29,24 @@ dependencies {
implementation 'com.android.support:support-emoji:27.0.2'
implementation 'com.android.support.constraint:constraint-layout:1.0.2'
// The holy ButterKnife \o/
compile 'com.jakewharton:butterknife:8.8.1'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.1'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
// External UI
compile 'de.hdodenhof:circleimageview:2.0.0'
// Smack
compile "org.igniterealtime.smack:smack-android-extensions:$smackVersion"
compile "org.igniterealtime.smack:smack-omemo-signal:$smackVersion"
compile "org.igniterealtime.smack:smack-tcp:$smackVersion"
compile "org.igniterealtime.smack:smack-experimental:$smackVersion"
compile 'com.jakewharton:butterknife:8.8.1'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'
// SQLCipher
compile 'net.zetetic:android-database-sqlcipher:3.5.9@aar'
compile 'de.hdodenhof:circleimageview:2.0.0'
// Test stuff
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.1'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
}

View File

@ -34,6 +34,7 @@
android:resource="@xml/automotive_app_desc" />
<service android:name=".service.MyMessagingService"/>
<service android:name=".service.SlamXmppService" />
<receiver android:name=".receiver.MessageReadReceiver">
<intent-filter>

View File

@ -18,14 +18,16 @@
package de.vanitasvitae.slam;
import android.app.Application;
import android.content.Intent;
import de.vanitasvitae.slam.mvp.DummyPresenterFactory;
import de.vanitasvitae.slam.mvp.PresenterFactory;
import de.vanitasvitae.slam.service.SlamXmppService;
public class SlamApplication extends Application {
public SlamApplication() {
super();
PresenterFactory.setInstance(new DummyPresenterFactory());
PresenterFactory.setInstance(new PresenterFactory());
}
}

View File

@ -0,0 +1,32 @@
/*
* Copyright 2018 Paul Schaub
*
* This code is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package de.vanitasvitae.slam.mvp.contracts;
/**
* Created by Paul Schaub on 24.02.18.
*/
public interface BaseContract {
interface BaseView<T extends BasePresenter> {
void setPresenter(T presenter);
}
interface BasePresenter {
}
}

View File

@ -26,7 +26,7 @@ import de.vanitasvitae.slam.xmpp.Resource;
*/
public interface ContactDetailContract {
interface View {
interface View extends BaseContract.BaseView<Presenter> {
void setContactAvatar();
void setNickname(String nickname);
void setResources(List<Resource> presences);
@ -34,7 +34,7 @@ public interface ContactDetailContract {
void addFingerprints(List<?> fingerprints);
}
interface Presenter {
interface Presenter extends BaseContract.BasePresenter {
void onAvatarClick();
void onSharedMediaClick();
void onAudioCallClick();

View File

@ -31,7 +31,7 @@ import de.vanitasvitae.slam.xmpp.Contact;
*/
public interface ContactListContract {
interface View {
interface View extends BaseContract.BaseView<Presenter> {
void addContactListItems(List<Contact> contacts);
void clearContactListItems();
void onUpdateContactPresence();
@ -41,7 +41,7 @@ public interface ContactListContract {
void navigateToContactDetail(BareJid contact);
}
interface Presenter {
interface Presenter extends BaseContract.BasePresenter {
void onContactListItemClick();
void onContactListItemLongClick();
void addNewContact();

View File

@ -30,14 +30,14 @@ import de.vanitasvitae.slam.xmpp.message.AbstractMessage;
*/
public interface ConversationContract {
interface View {
interface View extends BaseContract.BaseView<Presenter> {
void addMessageItems(List<AbstractMessage> messages, boolean end);
void highlightMessageItem();
void correctMessageItem();
void navigateToContactProfile();
}
interface Presenter {
interface Presenter extends BaseContract.BasePresenter {
void setPeersJid(EntityBareJid jid);
void onConversationScrolledToTop();
void onComposingMessageChanged(String composingMessage);

View File

@ -29,13 +29,13 @@ import de.vanitasvitae.slam.xmpp.Conversation;
*/
public interface ConversationListContract {
interface View {
interface View extends BaseContract.BaseView<Presenter> {
void populateConversationList(List<Conversation> conversations);
void navigateToConversation(BareJid contact);
void navigateToContactDetail(BareJid contact);
}
interface Presenter {
interface Presenter extends BaseContract.BasePresenter {
void onConversationClick();
void onConversationLongClick();
void load();

View File

@ -17,13 +17,15 @@
*/
package de.vanitasvitae.slam.mvp.contracts;
import de.vanitasvitae.slam.service.SlamXmppService;
/**
* Model-View-Presenter contract of the login screen.
* Created by Paul Schaub on 01.02.18.
*/
public interface LoginContract {
interface View {
interface View extends BaseContract.BaseView<Presenter> {
void showInvalidJidError();
void hideInvalidJidError();
void showInvalidPasswordError();
@ -33,11 +35,15 @@ public interface LoginContract {
void showProgressIndicator();
void hideProgressIndicator();
void navigateToMainActivity();
void disableLoginButton();
void enableLoginButton();
}
interface Presenter {
interface Presenter extends BaseContract.BasePresenter {
void jidChanged(String jid);
void passwordChanged(String password);
void loginClicked();
void bindService(SlamXmppService service);
void unbindService();
}
}

View File

@ -25,7 +25,7 @@ import java.util.List;
*/
public interface SearchContract {
interface View {
interface View extends BaseContract.BaseView<Presenter> {
void addSearchResults(List<?> results);
void clearSearchResults();
void showLoadingIndicator();
@ -34,7 +34,7 @@ public interface SearchContract {
void hideEmptySearchResults();
}
interface Presenter {
interface Presenter extends BaseContract.BasePresenter {
void onSearchQueryChanged(String query);
void onSearchResultClick();
void onSearchScrolledToBottom();

View File

@ -17,12 +17,14 @@
*/
package de.vanitasvitae.slam.mvp.contracts.message;
import de.vanitasvitae.slam.mvp.contracts.BaseContract;
/**
* Model-View-Presenter contract for an abstract message.
*/
public interface AbstractMessageContract {
interface View {
interface View extends BaseContract.BaseView<Presenter> {
void setDirection(Direction direction);
void setStatusSending();
void setStatusSendingFailed();
@ -33,7 +35,7 @@ public interface AbstractMessageContract {
void displayErrorMessage();
}
interface Presenter {
interface Presenter extends BaseContract.BasePresenter {
void onDeleteMessage();
void onReadMessage();
void onMessageClick();

View File

@ -17,18 +17,38 @@
*/
package de.vanitasvitae.slam.mvp.presenter;
import android.content.Context;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.widget.Toast;
import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.chat2.Chat;
import org.jivesoftware.smack.chat2.ChatManager;
import org.jivesoftware.smack.chat2.IncomingChatMessageListener;
import org.jivesoftware.smack.packet.Message;
import org.jxmpp.jid.BareJid;
import org.jxmpp.jid.EntityBareJid;
import org.jxmpp.jid.impl.JidCreate;
import org.jxmpp.stringprep.XmppStringprepException;
import java.io.IOException;
import java.net.UnknownHostException;
import de.vanitasvitae.slam.mvp.contracts.LoginContract;
import de.vanitasvitae.slam.service.SlamXmppConnection;
import de.vanitasvitae.slam.service.SlamXmppService;
import de.vanitasvitae.slam.xmpp.Account;
public class LoginPresenter implements LoginContract.Presenter {
private static final String TAG = "LoginPresenter";
private final LoginContract.View view;
private BareJid jid;
private String password;
private SlamXmppService service;
public LoginPresenter(LoginContract.View view) {
this.view = view;
@ -39,19 +59,115 @@ public class LoginPresenter implements LoginContract.Presenter {
try {
this.jid = JidCreate.entityBareFrom(jid);
view.hideInvalidJidError();
if (password != null && !password.isEmpty()) {
view.enableLoginButton();
}
} catch (XmppStringprepException e) {
this.jid = null;
view.showInvalidJidError();
view.disableLoginButton();
}
}
@Override
public void passwordChanged(String password) {
this.password = password;
if (password == null || password.isEmpty()) {
view.disableLoginButton();
} else if (jid != null) {
view.enableLoginButton();
}
}
@Override
public void loginClicked() {
if (jid == null) {
view.showInvalidJidError();
return;
}
if (password == null) {
view.showInvalidPasswordError();
return;
}
if (service != null) {
view.disableLoginButton();
final Account account = new Account(jid);
Thread loginThread = new Thread(new Runnable() {
@Override
public void run() {
SlamXmppConnection connection = null;
try {
connection = new SlamXmppConnection(
jid.asEntityBareJidOrThrow(), password);
} catch (UnknownHostException e) {
e.printStackTrace();
((AppCompatActivity)view).runOnUiThread(new Runnable() {
public void run() {
Toast.makeText((Context)view, "Unknown host", Toast.LENGTH_SHORT).show();
}
});
return;
}
service.addConnection(account, connection);
final SlamXmppConnection finalConnection = connection;
connection.login(new SlamXmppConnection.LoginCallback() {
@Override
public void success() {
((AppCompatActivity)view).runOnUiThread(new Runnable() {
public void run() {
view.navigateToMainActivity();
}
});
ChatManager.getInstanceFor(finalConnection.getConnection())
.addIncomingListener(new IncomingChatMessageListener() {
@Override
public void newIncomingMessage(final EntityBareJid from, final Message message, Chat chat) {
final AppCompatActivity activity = (AppCompatActivity) view;
activity.runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(activity.getApplicationContext(), from.toString() + ": " + message.getBody(), Toast.LENGTH_LONG).show();
}
});
}
});
}
@Override
public void failure(final Exception e) {
e.printStackTrace();
((AppCompatActivity)view).runOnUiThread(new Runnable() {
public void run() {
Toast.makeText((Context)view, e.getMessage(), Toast.LENGTH_LONG).show();
view.enableLoginButton();
}
});
}
});
}
});
loginThread.start();
} else {
view.showServerNotFoundError();
}
}
@Override
public void bindService(SlamXmppService service) {
Log.d(TAG, "bindService()");
this.service = service;
}
@Override
public void unbindService() {
Log.d(TAG, "unbindService()");
this.service = null;
}
}

View File

@ -27,12 +27,13 @@ import java.util.ArrayList;
import java.util.List;
import de.vanitasvitae.slam.mvp.contracts.ConversationContract;
import de.vanitasvitae.slam.xmpp.message.AbstractMessage;
public class DummyConversationPresenter implements ConversationContract.Presenter {
private final ConversationContract.View view;
private final List<Message> dummyMessages = new ArrayList<>();
private final List<AbstractMessage> dummyMessages = new ArrayList<>();
public DummyConversationPresenter(ConversationContract.View view) {
this.view = view;
@ -41,6 +42,7 @@ public class DummyConversationPresenter implements ConversationContract.Presente
}
private void populateDummyMessages() {
/*
try {
BareJid alice = JidCreate.bareFrom("alice@wonderland.lit");
@ -66,6 +68,7 @@ public class DummyConversationPresenter implements ConversationContract.Presente
} catch (XmppStringprepException e) {
e.printStackTrace();
}
*/
}
@Override

View File

@ -23,6 +23,7 @@ import org.jxmpp.jid.impl.JidCreate;
import org.jxmpp.stringprep.XmppStringprepException;
import de.vanitasvitae.slam.mvp.contracts.LoginContract;
import de.vanitasvitae.slam.service.SlamXmppService;
/**
* Dummy presenter, that has no model.
@ -82,4 +83,14 @@ public class DummyLoginPresenter implements LoginContract.Presenter {
}
}, 250);
}
@Override
public void bindService(SlamXmppService service) {
}
@Override
public void unbindService() {
}
}

View File

@ -45,7 +45,7 @@ public class ContactDetailActivity extends ThemedAppCompatActivity
public static final String TAG = "Slam!";
private final ContactDetailContract.Presenter presenter;
private ContactDetailContract.Presenter presenter;
private final ContactDetailResourcesFragment resourcesFragment = new ContactDetailResourcesFragment();
private final ContactDetailInfoFragment infoFragment = new ContactDetailInfoFragment();
@ -71,7 +71,7 @@ public class ContactDetailActivity extends ThemedAppCompatActivity
private int animateProfileCirclePercent = 30;
public ContactDetailActivity() {
this.presenter = PresenterFactory.getInstance().createContactDetailPresenter(this);
setPresenter(PresenterFactory.getInstance().createContactDetailPresenter(this));
}
@Override
@ -151,6 +151,11 @@ public class ContactDetailActivity extends ThemedAppCompatActivity
}
@Override
public void setPresenter(ContactDetailContract.Presenter presenter) {
this.presenter = presenter;
}
class DetailFragmentPagerAdapter extends FragmentPagerAdapter {
public DetailFragmentPagerAdapter(FragmentManager fm) {

View File

@ -47,13 +47,13 @@ public class ContactListFragment extends Fragment implements ContactListContract
@BindView(R.id.recycler_list)
RecyclerView recyclerView;
private final ContactListContract.Presenter presenter;
private ContactListContract.Presenter presenter;
private final List<Contact> contacts = new ArrayList<>();
public ContactListFragment() {
super();
this.presenter = PresenterFactory.getInstance().createContactListPresenter(this);
setPresenter(PresenterFactory.getInstance().createContactListPresenter(this));
}
@Override
@ -142,4 +142,8 @@ public class ContactListFragment extends Fragment implements ContactListContract
}
@Override
public void setPresenter(ContactListContract.Presenter presenter) {
this.presenter = presenter;
}
}

View File

@ -56,7 +56,7 @@ public class ConversationFragment extends Fragment implements ConversationContra
@BindView(R.id.recycler_chat)
RecyclerView recyclerView;
private final ConversationContract.Presenter presenter;
private ConversationContract.Presenter presenter;
Map<String, Integer> messageIdIndizes = new HashMap<>();
List<AbstractMessage> messages = new ArrayList<>();
@ -87,7 +87,7 @@ public class ConversationFragment extends Fragment implements ConversationContra
public ConversationFragment() {
super();
this.presenter = PresenterFactory.getInstance().createConversationPresenter(this);
setPresenter(PresenterFactory.getInstance().createConversationPresenter(this));
}
@Override
@ -117,6 +117,11 @@ public class ConversationFragment extends Fragment implements ConversationContra
recyclerView.getAdapter().notifyDataSetChanged();
}
@Override
public void setPresenter(ConversationContract.Presenter presenter) {
this.presenter = presenter;
}
@Override
public void addMessageItems(List<AbstractMessage> messages, boolean end) {
if (end) {

View File

@ -49,12 +49,12 @@ public class ConversationListFragment extends Fragment implements ConversationLi
@BindView(R.id.recycler_list)
RecyclerView recyclerView;
private final ConversationListContract.Presenter presenter;
private ConversationListContract.Presenter presenter;
private final List<Conversation> conversations = new ArrayList<>();
public ConversationListFragment() {
super();
this.presenter = PresenterFactory.getInstance().createConversationListPresenter(this);
setPresenter(PresenterFactory.getInstance().createConversationListPresenter(this));
}
@Override
@ -72,6 +72,11 @@ public class ConversationListFragment extends Fragment implements ConversationLi
recyclerView.getAdapter().notifyDataSetChanged();
}
@Override
public void setPresenter(ConversationListContract.Presenter presenter) {
this.presenter = presenter;
}
@Override
public void populateConversationList(List<Conversation> conversations) {
this.conversations.clear();

View File

@ -17,8 +17,12 @@
*/
package de.vanitasvitae.slam.mvp.view;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.support.design.widget.TextInputEditText;
import android.support.design.widget.TextInputLayout;
import android.support.v7.widget.Toolbar;
@ -40,8 +44,9 @@ import de.vanitasvitae.slam.R;
import de.vanitasvitae.slam.mvp.PresenterFactory;
import de.vanitasvitae.slam.mvp.view.abstr.ThemedAppCompatActivity;
import de.vanitasvitae.slam.mvp.contracts.LoginContract;
import de.vanitasvitae.slam.service.SlamXmppService;
public class LoginActivity extends ThemedAppCompatActivity implements LoginContract.View {
public class LoginActivity extends ThemedAppCompatActivity implements LoginContract.View, ServiceConnection {
// Presenter of this view
private LoginContract.Presenter presenter;
@ -67,9 +72,11 @@ public class LoginActivity extends ThemedAppCompatActivity implements LoginContr
@BindView(R.id.button_login)
Button buttonLogin;
private SlamXmppService slamService;
public LoginActivity() {
super();
this.presenter = PresenterFactory.getInstance().createLoginPresenter(this);
setPresenter(PresenterFactory.getInstance().createLoginPresenter(this));
}
@Override
@ -103,8 +110,29 @@ public class LoginActivity extends ThemedAppCompatActivity implements LoginContr
});
}
@Override
protected void onResume() {
super.onResume();
// Start xmpp service
Intent serviceIntent = new Intent(this, SlamXmppService.class);
bindService(serviceIntent, this, Context.BIND_AUTO_CREATE);
}
@Override
protected void onPause() {
super.onPause();
unbindService(this);
}
@Override
public void setPresenter(LoginContract.Presenter presenter) {
this.presenter = presenter;
}
@OnClick(R.id.button_login)
void login() {
Intent serviceIntent = new Intent(getApplicationContext(), SlamXmppService.class);
getApplicationContext().startService(serviceIntent);
presenter.loginClicked();
}
@ -162,5 +190,28 @@ public class LoginActivity extends ThemedAppCompatActivity implements LoginContr
startActivity(new Intent(this, MainActivity.class));
finish();
}
@Override
public void disableLoginButton() {
buttonLogin.setEnabled(false);
}
@Override
public void enableLoginButton() {
buttonLogin.setEnabled(true);
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
SlamXmppService.SlamBinder binder = (SlamXmppService.SlamBinder) service;
slamService = binder.getService();
presenter.bindService(slamService);
}
@Override
public void onServiceDisconnected(ComponentName name) {
slamService = null;
presenter.unbindService();
}
}

View File

@ -31,10 +31,10 @@ import de.vanitasvitae.slam.mvp.contracts.SearchContract;
*/
public class SearchFragment extends Fragment implements SearchContract.View {
private final SearchContract.Presenter presenter;
private SearchContract.Presenter presenter;
public SearchFragment() {
this.presenter = PresenterFactory.getInstance().createSearchPresenter(this);
setPresenter(PresenterFactory.getInstance().createSearchPresenter(this));
}
@Override
@ -66,4 +66,9 @@ public class SearchFragment extends Fragment implements SearchContract.View {
public void hideEmptySearchResults() {
}
@Override
public void setPresenter(SearchContract.Presenter presenter) {
this.presenter = presenter;
}
}

View File

@ -34,6 +34,8 @@ import de.vanitasvitae.slam.xmpp.message.AbstractMessage;
public abstract class MessageView<T extends AbstractMessage> extends RecyclerView.ViewHolder
implements AbstractMessageContract.View {
protected AbstractMessageContract.Presenter presenter;
public MessageView(View itemView) {
super(itemView);
}
@ -83,4 +85,9 @@ public abstract class MessageView<T extends AbstractMessage> extends RecyclerVie
public void displayErrorMessage() {
}
@Override
public void setPresenter(AbstractMessageContract.Presenter presenter) {
this.presenter = presenter;
}
}

View File

@ -0,0 +1,86 @@
/*
* Copyright 2018 Paul Schaub
*
* This code is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package de.vanitasvitae.slam.service;
import android.util.Log;
import org.jivesoftware.smack.AbstractXMPPConnection;
import org.jivesoftware.smack.tcp.XMPPTCPConnection;
import org.jivesoftware.smack.tcp.XMPPTCPConnectionConfiguration;
import org.jivesoftware.smack.util.StringUtils;
import org.jxmpp.jid.EntityBareJid;
import org.jxmpp.jid.parts.Resourcepart;
import org.jxmpp.stringprep.XmppStringprepException;
import java.net.InetAddress;
import java.net.UnknownHostException;
/**
* Created by Paul Schaub on 24.02.18.
*/
public class SlamXmppConnection {
private static final String TAG = "SlamConn";
private final EntityBareJid jid;
private final AbstractXMPPConnection connection;
private final Resourcepart resourcepart;
public SlamXmppConnection(EntityBareJid jid, String password) throws UnknownHostException {
this.jid = jid;
// Resource
String res = "Slam-" + StringUtils.randomString(12);
try {
this.resourcepart = Resourcepart.from(res);
} catch (XmppStringprepException e) {
throw new AssertionError("Resourcepart \"" + res + "\" appears to be invalid.", e);
}
// Configuration
XMPPTCPConnectionConfiguration configuration = XMPPTCPConnectionConfiguration.builder()
.setHost(this.jid.getDomain().toString())
.setHostAddress(InetAddress.getByName(jid.getDomain().toString()))
.setXmppDomain(jid.asDomainBareJid())
.setUsernameAndPassword(jid.getLocalpart().toString(), password)
.setResource(resourcepart)
.build();
this.connection = new XMPPTCPConnection(configuration);
}
public AbstractXMPPConnection getConnection() {
return connection;
}
public void login(final LoginCallback callback) {
try {
getConnection().connect().login();
Log.d(TAG, "Account " + jid.toString() + " logged in.");
callback.success();
} catch (Exception e) {
Log.d(TAG, "Account " + jid.toString() + " could not log in.");
e.printStackTrace();
callback.failure(e);
}
}
public interface LoginCallback {
void success();
void failure(Exception e);
}
}

View File

@ -0,0 +1,78 @@
/*
* Copyright 2018 Paul Schaub
*
* This code is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package de.vanitasvitae.slam.service;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.Log;
import java.util.HashMap;
import de.vanitasvitae.slam.xmpp.Account;
/**
* Created by Paul Schaub on 24.02.18.
*/
public class SlamXmppService extends Service {
private static final String TAG = "SlamService";
private final IBinder binder = new SlamBinder();
private Account currentAccount;
private final HashMap<Account, SlamXmppConnection> connections = new HashMap<>();
@Nullable
@Override
public IBinder onBind(Intent intent) {
return binder;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG,"onStartCommand()");
return Service.START_STICKY;
}
public void addConnection(@NonNull Account account, SlamXmppConnection connection) {
Log.d(TAG, "Adding a new connection for " + account.getJid().toString());
this.connections.put(account, connection);
}
@Override
public void onDestroy() {
Log.d(TAG, "onDestroy()");
for (SlamXmppConnection c : connections.values()) {
c.getConnection().disconnect();
}
super.onDestroy();
}
public SlamXmppConnection getConnection(@NonNull Account account) {
return connections.get(account);
}
public class SlamBinder extends Binder {
public SlamXmppService getService() {
return SlamXmppService.this;
}
}
}

View File

@ -0,0 +1,69 @@
package de.vanitasvitae.slam.task;
import android.os.AsyncTask;
import android.support.annotation.NonNull;
import org.jxmpp.jid.EntityBareJid;
import java.net.InetAddress;
import java.net.UnknownHostException;
import de.vanitasvitae.slam.mvp.contracts.LoginContract;
import de.vanitasvitae.slam.service.SlamXmppConnection;
/**
* Created by Paul Schaub on 26.02.18.
*/
public class LoginTask extends AsyncTask<LoginTask.Credentials, Void, SlamXmppConnection> {
private final LoginContract.View view;
private Exception exception;
public LoginTask(LoginContract.View view) {
this.view = view;
}
@Override
protected SlamXmppConnection doInBackground(Credentials... credentials) {
if (credentials.length != 1) {
throw new IllegalArgumentException("Please only present one set of credentials at a time.");
}
SlamXmppConnection connection;
try {
connection = new SlamXmppConnection(credentials[0].jid, credentials[0].password);
} catch (UnknownHostException e) {
exception = e;
return null;
}
return null;
}
@Override
protected void onPreExecute() {
}
@Override
protected void onPostExecute(SlamXmppConnection result) {
if (exception == null) {
return;
}
if (exception instanceof UnknownHostException) {
view.showServerNotFoundError();
return;
}
}
public static class Credentials {
private final EntityBareJid jid;
private final String password;
public Credentials(@NonNull EntityBareJid jid, @NonNull String password) {
this.jid = jid;
this.password = password;
}
}
}

View File

@ -17,8 +17,20 @@
*/
package de.vanitasvitae.slam.xmpp;
import org.jxmpp.jid.BareJid;
/**
* Created by Paul Schaub on 24.02.18.
*/
public class Account {
private final BareJid jid;
public Account(BareJid jid) {
this.jid = jid;
}
public BareJid getJid() {
return jid;
}
}