~singpolyma/cheogram-android

a420cb5886c1c979f2678507c450712a73272a47 — Daniel Gultsch 5 years ago 96d3421
refactored some ManageAccount, WelcomeActivity and a few other things into 'full' flavor
22 files changed, 364 insertions(+), 255 deletions(-)

M build.gradle
A src/full/AndroidManifest.xml
R src/{main/java/eu/siacs/conversations/ui/MagicCreateActivity.java => full/java/eu/siacs/conversations/ui/MagicCreateActivity.java}
R src/{main/java/eu/siacs/conversations/ui/ManageAccountActivity.java => full/java/eu/siacs/conversations/ui/ManageAccountActivity.java}
R src/{main/java/eu/siacs/conversations/ui/ShareViaAccountActivity.java => full/java/eu/siacs/conversations/ui/ShareViaAccountActivity.java}
R src/{main/java/eu/siacs/conversations/ui/WelcomeActivity.java => full/java/eu/siacs/conversations/ui/WelcomeActivity.java}
R src/{main/java/eu/siacs/conversations/ui/adapter/AccountAdapter.java => full/java/eu/siacs/conversations/ui/adapter/AccountAdapter.java}
A src/full/java/eu/siacs/conversations/utils/SignupUtils.java
M src/main/AndroidManifest.xml
M src/main/java/eu/siacs/conversations/services/NotificationService.java
M src/main/java/eu/siacs/conversations/services/XmppConnectionService.java
M src/main/java/eu/siacs/conversations/ui/ConversationsActivity.java
M src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java
M src/main/java/eu/siacs/conversations/ui/PublishProfilePictureActivity.java
M src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java
M src/main/java/eu/siacs/conversations/ui/UriHandlerActivity.java
M src/main/java/eu/siacs/conversations/ui/XmppActivity.java
A src/main/java/eu/siacs/conversations/utils/AccountUtils.java
M src/main/java/eu/siacs/conversations/utils/ExceptionHelper.java
M src/main/java/eu/siacs/conversations/utils/XmppUri.java
M src/main/res/values/strings.xml
A src/quick/java/eu/siacs/conversations/utils/SignupUtils.java
M build.gradle => build.gradle +5 -3
@@ 21,7 21,8 @@ repositories {
configurations {
    playstoreImplementation
    compatImplementation
    freeCompatImplementation
    fullFreeCompatImplementation
    quickFreeCompatImplementation
}

ext {


@@ 41,10 42,11 @@ dependencies {
    implementation "com.android.support:appcompat-v7:$supportLibVersion"
    implementation "com.android.support:exifinterface:$supportLibVersion"
    implementation "com.android.support:cardview-v7:$supportLibVersion"
    compatImplementation "com.android.support:support-emoji-appcompat:$supportLibVersion"
    implementation "com.android.support:support-emoji:$supportLibVersion"
    implementation "com.android.support:design:$supportLibVersion"
    freeCompatImplementation "com.android.support:support-emoji-bundled:$supportLibVersion"
    compatImplementation "com.android.support:support-emoji-appcompat:$supportLibVersion"
    fullFreeCompatImplementation "com.android.support:support-emoji-bundled:$supportLibVersion"
    quickFreeCompatImplementation "com.android.support:support-emoji-bundled:$supportLibVersion"
    implementation 'org.bouncycastle:bcmail-jdk15on:1.58'
    implementation 'com.google.zxing:core:3.3.0'
    implementation 'de.measite.minidns:minidns-hla:0.2.4'

A src/full/AndroidManifest.xml => src/full/AndroidManifest.xml +21 -0
@@ 0,0 1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="eu.siacs.conversations">

    <application tools:ignore="GoogleAppIndexingWarning">
        <activity
            android:name=".ui.ManageAccountActivity"
            android:label="@string/title_activity_manage_accounts"
            android:launchMode="singleTask" />
        <activity
            android:name=".ui.WelcomeActivity"
            android:label="@string/app_name"
            android:launchMode="singleTask"/>
        <activity
            android:name=".ui.MagicCreateActivity"
            android:label="@string/create_account"
            android:launchMode="singleTask"/>

    </application>
</manifest>

R src/main/java/eu/siacs/conversations/ui/MagicCreateActivity.java => src/full/java/eu/siacs/conversations/ui/MagicCreateActivity.java +1 -1
@@ 77,7 77,7 @@ public class MagicCreateActivity extends XmppActivity implements TextWatcher {
					intent.putExtra("init", true);
					intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
					Toast.makeText(MagicCreateActivity.this, R.string.secure_password_generated, Toast.LENGTH_SHORT).show();
					WelcomeActivity.addInviteUri(intent, getIntent());
					StartConversationActivity.addInviteUri(intent, getIntent());
					startActivity(intent);
				}
			} catch (IllegalArgumentException e) {

R src/main/java/eu/siacs/conversations/ui/ManageAccountActivity.java => src/full/java/eu/siacs/conversations/ui/ManageAccountActivity.java +0 -0
R src/main/java/eu/siacs/conversations/ui/ShareViaAccountActivity.java => src/full/java/eu/siacs/conversations/ui/ShareViaAccountActivity.java +0 -0
R src/main/java/eu/siacs/conversations/ui/WelcomeActivity.java => src/full/java/eu/siacs/conversations/ui/WelcomeActivity.java +1 -15
@@ 15,8 15,6 @@ import eu.siacs.conversations.utils.XmppUri;

public class WelcomeActivity extends XmppActivity {

	public static final String EXTRA_INVITE_URI = "eu.siacs.conversations.invite_uri";

	@Override
	protected void refreshUiReal() {



@@ 80,19 78,7 @@ public class WelcomeActivity extends XmppActivity {
	}

	public void addInviteUri(Intent intent) {
		addInviteUri(intent, getIntent());
	}

	public static void addInviteUri(Intent intent, XmppUri uri) {
		if (uri.isJidValid()) {
			intent.putExtra(EXTRA_INVITE_URI, uri.toString());
		}
	}

	public static void addInviteUri(Intent to, Intent from) {
		if (from != null && from.hasExtra(EXTRA_INVITE_URI)) {
			to.putExtra(EXTRA_INVITE_URI, from.getStringExtra(EXTRA_INVITE_URI));
		}
		StartConversationActivity.addInviteUri(intent, getIntent());
	}

	public static void launch(AppCompatActivity activity) {

R src/main/java/eu/siacs/conversations/ui/adapter/AccountAdapter.java => src/full/java/eu/siacs/conversations/ui/adapter/AccountAdapter.java +0 -0
A src/full/java/eu/siacs/conversations/utils/SignupUtils.java => src/full/java/eu/siacs/conversations/utils/SignupUtils.java +47 -0
@@ 0,0 1,47 @@
package eu.siacs.conversations.utils;

import android.app.Activity;
import android.content.Intent;

import eu.siacs.conversations.Config;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.ui.ConversationsActivity;
import eu.siacs.conversations.ui.EditAccountActivity;
import eu.siacs.conversations.ui.ManageAccountActivity;
import eu.siacs.conversations.ui.StartConversationActivity;
import eu.siacs.conversations.ui.WelcomeActivity;

public class SignupUtils {

    public static Intent getSignUpIntent(final Activity activity) {
        Intent intent = new Intent(activity, WelcomeActivity.class);
        StartConversationActivity.addInviteUri(intent, activity.getIntent());
        return intent;
    }

    public static Intent getRedirectionIntent(final ConversationsActivity activity) {
        final XmppConnectionService service = activity.xmppConnectionService;
        Account pendingAccount = AccountUtils.getPendingAccount(service);
        Intent intent;
        if (pendingAccount != null) {
            intent = new Intent(activity, EditAccountActivity.class);
            intent.putExtra("jid", pendingAccount.getJid().asBareJid().toString());
        } else {
            if (service.getAccounts().size() == 0) {
                if (Config.X509_VERIFICATION) {
                    intent = new Intent(activity, ManageAccountActivity.class);
                } else if (Config.MAGIC_CREATE_DOMAIN != null) {
                    intent = getSignUpIntent(activity);
                } else {
                    intent = new Intent(activity, EditAccountActivity.class);
                }
            } else {
                intent = new Intent(activity, StartConversationActivity.class);
            }
        }
        intent.putExtra("init", true);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
        return intent;
    }
}
\ No newline at end of file

M src/main/AndroidManifest.xml => src/main/AndroidManifest.xml +0 -12
@@ 148,14 148,6 @@
            </intent-filter>
        </activity>
        <activity
            android:name=".ui.WelcomeActivity"
            android:label="@string/app_name"
            android:launchMode="singleTask"/>
        <activity
            android:name=".ui.MagicCreateActivity"
            android:label="@string/create_account"
            android:launchMode="singleTask"/>
        <activity
            android:name=".ui.SettingsActivity"
            android:label="@string/title_activity_settings">
            <intent-filter>


@@ 173,10 165,6 @@
            android:name=".ui.ChangePasswordActivity"
            android:label="@string/change_password_on_server"/>
        <activity
            android:name=".ui.ManageAccountActivity"
            android:label="@string/title_activity_manage_accounts"
            android:launchMode="singleTask"/>
        <activity
            android:name=".ui.ShareViaAccountActivity"
            android:label="@string/title_activity_share_via_account"
            android:launchMode="singleTop"/>

M src/main/java/eu/siacs/conversations/services/NotificationService.java => src/main/java/eu/siacs/conversations/services/NotificationService.java +10 -5
@@ 56,8 56,9 @@ import eu.siacs.conversations.entities.Conversational;
import eu.siacs.conversations.entities.Message;
import eu.siacs.conversations.persistance.FileBackend;
import eu.siacs.conversations.ui.ConversationsActivity;
import eu.siacs.conversations.ui.ManageAccountActivity;
import eu.siacs.conversations.ui.EditAccountActivity;
import eu.siacs.conversations.ui.TimePreference;
import eu.siacs.conversations.utils.AccountUtils;
import eu.siacs.conversations.utils.Compatibility;
import eu.siacs.conversations.utils.GeoHelper;
import eu.siacs.conversations.utils.UIHelper;


@@ 923,10 924,14 @@ public class NotificationService {
            mBuilder.setLocalOnly(true);
        }
        mBuilder.setPriority(Notification.PRIORITY_LOW);
        mBuilder.setContentIntent(PendingIntent.getActivity(mXmppConnectionService,
                145,
                new Intent(mXmppConnectionService, ManageAccountActivity.class),
                PendingIntent.FLAG_UPDATE_CURRENT));
        final Intent intent;
        if (AccountUtils.MANAGE_ACCOUNT_ACTIVITY != null) {
            intent = new Intent(mXmppConnectionService, AccountUtils.MANAGE_ACCOUNT_ACTIVITY);
        } else {
            intent = new Intent(mXmppConnectionService, EditAccountActivity.class);
            intent.putExtra("jid", errors.get(0).getJid().asBareJid().toEscapedString());
        }
        mBuilder.setContentIntent(PendingIntent.getActivity(mXmppConnectionService,145, intent, PendingIntent.FLAG_UPDATE_CURRENT));
        if (Compatibility.runsTwentySix()) {
            mBuilder.setChannelId("error");
        }

M src/main/java/eu/siacs/conversations/services/XmppConnectionService.java => src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +0 -12
@@ 3903,18 3903,6 @@ public class XmppConnectionService extends Service {
		return mPushManagementService;
	}

	public Account getPendingAccount() {
		Account pending = null;
		for (Account account : getAccounts()) {
			if (!account.isOptionSet(Account.OPTION_LOGGED_IN_SUCCESSFULLY)) {
				pending = account;
			} else {
				return null;
			}
		}
		return pending;
	}

	public void changeStatus(Account account, PresenceTemplate template, String signature) {
		if (!template.getStatusMessage().isEmpty()) {
			databaseBackend.insertPresenceTemplate(template);

M src/main/java/eu/siacs/conversations/ui/ConversationsActivity.java => src/main/java/eu/siacs/conversations/ui/ConversationsActivity.java +5 -29
@@ 78,6 78,7 @@ import eu.siacs.conversations.ui.util.MenuDoubleTabUtil;
import eu.siacs.conversations.ui.util.PendingItem;
import eu.siacs.conversations.utils.EmojiWrapper;
import eu.siacs.conversations.utils.ExceptionHelper;
import eu.siacs.conversations.utils.SignupUtils;
import eu.siacs.conversations.utils.XmppUri;
import eu.siacs.conversations.xmpp.OnUpdateBlocklist;
import rocks.xmpp.addr.Jid;


@@ 177,7 178,10 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio
        }
        boolean isConversationsListEmpty = xmppConnectionService.isConversationsListEmpty(ignore);
        if (isConversationsListEmpty && mRedirectInProcess.compareAndSet(false, true)) {
            final Intent intent = getRedirectionIntent(noAnimation);
            final Intent intent = SignupUtils.getRedirectionIntent(this);
            if (noAnimation) {
                intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
            }
            runOnUiThread(() -> {
                startActivity(intent);
                if (noAnimation) {


@@ 188,34 192,6 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio
        return mRedirectInProcess.get();
    }

    private Intent getRedirectionIntent(boolean noAnimation) {
        Account pendingAccount = xmppConnectionService.getPendingAccount();
        Intent intent;
        if (pendingAccount != null) {
            intent = new Intent(this, EditAccountActivity.class);
            intent.putExtra("jid", pendingAccount.getJid().asBareJid().toString());
        } else {
            if (xmppConnectionService.getAccounts().size() == 0) {
                if (Config.X509_VERIFICATION) {
                    intent = new Intent(this, ManageAccountActivity.class);
                } else if (Config.MAGIC_CREATE_DOMAIN != null) {
                    intent = new Intent(this, WelcomeActivity.class);
                    WelcomeActivity.addInviteUri(intent, getIntent());
                } else {
                    intent = new Intent(this, EditAccountActivity.class);
                }
            } else {
                intent = new Intent(this, StartConversationActivity.class);
            }
        }
        intent.putExtra("init", true);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
        if (noAnimation) {
            intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
        }
        return intent;
    }

    private void showDialogsIfMainIsOverview() {
        if (xmppConnectionService == null) {
            return;

M src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java => src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java +6 -5
@@ 67,6 67,7 @@ import eu.siacs.conversations.ui.util.MenuDoubleTabUtil;
import eu.siacs.conversations.ui.util.PendingItem;
import eu.siacs.conversations.ui.util.SoftKeyboardUtils;
import eu.siacs.conversations.utils.CryptoHelper;
import eu.siacs.conversations.utils.SignupUtils;
import eu.siacs.conversations.utils.UIHelper;
import eu.siacs.conversations.utils.XmppUri;
import eu.siacs.conversations.xml.Element;


@@ 279,8 280,9 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
		if (mAccount != null
				&& mAccount.getStatus() != Account.State.ONLINE
				&& mFetchingAvatar) {
			//TODO: maybe better redirect to StartConversationActivity
			startActivity(new Intent(this, ManageAccountActivity.class));
			Intent intent = new Intent(this, StartConversationActivity.class);
			StartConversationActivity.addInviteUri(intent, getIntent());
			startActivity(intent);
			finish();
		} else if (mInitMode && mAccount != null && mAccount.getStatus() == Account.State.ONLINE) {
			if (!mFetchingAvatar) {


@@ 312,8 314,7 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
		}

		if (xmppConnectionService.getAccounts().size() == 0 && Config.MAGIC_CREATE_DOMAIN != null) {
			Intent intent = new Intent(EditAccountActivity.this, WelcomeActivity.class);
			WelcomeActivity.addInviteUri(intent, getIntent());
			Intent intent = SignupUtils.getSignUpIntent(this);
			startActivity(intent);
		}
	}


@@ 406,7 407,7 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
			if (wasFirstAccount) {
				intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
			}
			WelcomeActivity.addInviteUri(intent, getIntent());
			StartConversationActivity.addInviteUri(intent, getIntent());
			startActivity(intent);
			finish();
		});

M src/main/java/eu/siacs/conversations/ui/PublishProfilePictureActivity.java => src/main/java/eu/siacs/conversations/ui/PublishProfilePictureActivity.java +2 -2
@@ 50,7 50,7 @@ public class PublishProfilePictureActivity extends XmppActivity implements XmppC
        runOnUiThread(() -> {
            if (mInitialAccountSetup) {
                Intent intent = new Intent(getApplicationContext(), StartConversationActivity.class);
                WelcomeActivity.addInviteUri(intent, getIntent());
                StartConversationActivity.addInviteUri(intent, getIntent());
                intent.putExtra("init", true);
                startActivity(intent);
            }


@@ 94,7 94,7 @@ public class PublishProfilePictureActivity extends XmppActivity implements XmppC
            if (mInitialAccountSetup) {
                Intent intent = new Intent(getApplicationContext(), StartConversationActivity.class);
                if (xmppConnectionService != null && xmppConnectionService.getAccounts().size() == 1) {
                    WelcomeActivity.addInviteUri(intent, getIntent());
                    StartConversationActivity.addInviteUri(intent, getIntent());
                    intent.putExtra("init", true);
                }
                startActivity(intent);

M src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java => src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java +10 -2
@@ 82,6 82,8 @@ import rocks.xmpp.addr.Jid;

public class StartConversationActivity extends XmppActivity implements XmppConnectionService.OnConversationUpdate, OnRosterUpdate, OnUpdateBlocklist, CreateConferenceDialog.CreateConferenceDialogListener, JoinConferenceDialog.JoinConferenceDialogListener {

	public static final String EXTRA_INVITE_URI = "eu.siacs.conversations.invite_uri";

	private final int REQUEST_SYNC_CONTACTS = 0x28cf;
	private final int REQUEST_CREATE_CONFERENCE = 0x39da;
	private final PendingItem<Intent> pendingViewIntent = new PendingItem<>();


@@ 236,7 238,7 @@ public class StartConversationActivity extends XmppActivity implements XmppConne
	}

	private static boolean isViewIntent(final Intent i) {
		return i != null && (Intent.ACTION_VIEW.equals(i.getAction()) || Intent.ACTION_SENDTO.equals(i.getAction()) || i.hasExtra(WelcomeActivity.EXTRA_INVITE_URI));
		return i != null && (Intent.ACTION_VIEW.equals(i.getAction()) || Intent.ACTION_SENDTO.equals(i.getAction()) || i.hasExtra(EXTRA_INVITE_URI));
	}

	protected void hideToast() {


@@ 749,7 751,7 @@ public class StartConversationActivity extends XmppActivity implements XmppConne
	}

	protected boolean processViewIntent(@NonNull Intent intent) {
		final String inviteUri = intent.getStringExtra(WelcomeActivity.EXTRA_INVITE_URI);
		final String inviteUri = intent.getStringExtra(EXTRA_INVITE_URI);
		if (inviteUri != null) {
			Invite invite = new Invite(inviteUri);
			if (invite.isJidValid()) {


@@ 1165,6 1167,12 @@ public class StartConversationActivity extends XmppActivity implements XmppConne
		}
	}

	public static void addInviteUri(Intent to, Intent from) {
		if (from != null && from.hasExtra(EXTRA_INVITE_URI)) {
			to.putExtra(EXTRA_INVITE_URI, from.getStringExtra(EXTRA_INVITE_URI));
		}
	}

	private class Invite extends XmppUri {

		public String account;

M src/main/java/eu/siacs/conversations/ui/UriHandlerActivity.java => src/main/java/eu/siacs/conversations/ui/UriHandlerActivity.java +173 -156
@@ 2,177 2,194 @@ package eu.siacs.conversations.ui;

import android.Manifest;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.support.v13.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.content.Intent;
import android.net.Uri;
import android.widget.Toast;

import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.persistance.DatabaseBackend;
import eu.siacs.conversations.utils.SignupUtils;
import eu.siacs.conversations.utils.XmppUri;
import rocks.xmpp.addr.Jid;

public class UriHandlerActivity extends AppCompatActivity {

	public static final String ACTION_SCAN_QR_CODE = "scan_qr_code";
	private static final int REQUEST_SCAN_QR_CODE = 0x1234;
	private static final int REQUEST_CAMERA_PERMISSIONS_TO_SCAN = 0x6789;

	private boolean handled = false;

	public static void scan(Activity activity) {
		if (ContextCompat.checkSelfPermission(activity, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) {
			Intent intent = new Intent(activity, UriHandlerActivity.class);
			intent.setAction(UriHandlerActivity.ACTION_SCAN_QR_CODE);
			intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
			activity.startActivity(intent);
		} else {
			ActivityCompat.requestPermissions(activity, new String[]{Manifest.permission.CAMERA}, REQUEST_CAMERA_PERMISSIONS_TO_SCAN);
		}
	}

	public static void onRequestPermissionResult(Activity activity, int requestCode, int[] grantResults) {
		if (requestCode != REQUEST_CAMERA_PERMISSIONS_TO_SCAN) {
			return;
		}
		if (grantResults.length > 0) {
			if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
				scan(activity);
			} else {
				Toast.makeText(activity, R.string.qr_code_scanner_needs_access_to_camera, Toast.LENGTH_SHORT).show();
			}
		}
	}

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		this.handled = savedInstanceState != null && savedInstanceState.getBoolean("handled", false);
		getLayoutInflater().inflate(R.layout.toolbar, findViewById(android.R.id.content));
		setSupportActionBar(findViewById(R.id.toolbar));
	}

	@Override
	public void onStart() {
		super.onStart();
		handleIntent(getIntent());
	}

	@Override
	public void onSaveInstanceState(Bundle savedInstanceState) {
		savedInstanceState.putBoolean("handled", this.handled);
		super.onSaveInstanceState(savedInstanceState);
	}

	@Override
	public void onNewIntent(Intent intent) {
		handleIntent(intent);
	}

	private void handleUri(Uri uri) {
		handleUri(uri, false);
	}

	private void handleUri(Uri uri, final boolean scanned) {
		final Intent intent;
		final XmppUri xmppUri = new XmppUri(uri);
		final List<Jid> accounts = DatabaseBackend.getInstance(this).getAccountJids(); //TODO only look at enabled accounts

		if (!xmppUri.isJidValid()) {
			Toast.makeText(this, R.string.invalid_jid, Toast.LENGTH_SHORT).show();
			return;
		}

		if (accounts.size() == 0 && Config.MAGIC_CREATE_DOMAIN != null) {
			intent = new Intent(getApplicationContext(), WelcomeActivity.class);
			WelcomeActivity.addInviteUri(intent, xmppUri);
			startActivity(intent);
			return;
		}

		if (xmppUri.isAction(XmppUri.ACTION_MESSAGE)) {
			final Jid jid = xmppUri.getJid();
			final String body = xmppUri.getBody();

			if (jid != null) {
				intent = new Intent(getApplicationContext(), ShareViaAccountActivity.class);
				intent.putExtra(ShareViaAccountActivity.EXTRA_CONTACT, jid.toString());
				intent.putExtra(ShareViaAccountActivity.EXTRA_BODY, body);
			} else {
				intent = new Intent(getApplicationContext(), ShareWithActivity.class);
				intent.setAction(Intent.ACTION_SEND);
				intent.setType("text/plain");
				intent.putExtra(Intent.EXTRA_TEXT, body);
			}
		} else if (accounts.contains(xmppUri.getJid())) {
			intent = new Intent(getApplicationContext(), EditAccountActivity.class);
			intent.setAction(Intent.ACTION_VIEW);
			intent.putExtra("jid", xmppUri.getJid().asBareJid().toString());
			intent.setData(uri);
			intent.putExtra("scanned", scanned);
		} else {
			intent = new Intent(getApplicationContext(), StartConversationActivity.class);
			intent.setAction(Intent.ACTION_VIEW);
			intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
			intent.putExtra("scanned", scanned);
			intent.setData(uri);
		}

		startActivity(intent);
	}

	private void handleIntent(Intent data) {
		if (handled) {
			return;
		}
		if (data == null || data.getAction() == null) {
			finish();
			return;
		}

		handled = true;

		switch (data.getAction()) {
			case Intent.ACTION_VIEW:
			case Intent.ACTION_SENDTO:
				handleUri(data.getData());
				break;
			case ACTION_SCAN_QR_CODE:
				Intent intent = new Intent(this, ScanActivity.class);
				startActivityForResult(intent, REQUEST_SCAN_QR_CODE);
				return;
		}

		finish();
	}

	private static final Pattern VCARD_XMPP_PATTERN = Pattern.compile("\nIMPP([^:]*):(xmpp:.+)\n");

	@Override
	public void onActivityResult(int requestCode, int resultCode, Intent intent) {
		super.onActivityResult(requestCode, requestCode, intent);
		if (requestCode == REQUEST_SCAN_QR_CODE && resultCode == RESULT_OK) {
			String result = intent.getStringExtra(ScanActivity.INTENT_EXTRA_RESULT);
			if (result != null) {
				if (result.startsWith("BEGIN:VCARD\n")) {
					Matcher matcher = VCARD_XMPP_PATTERN.matcher(result);
					if (matcher.find()) {
						result = matcher.group(2);
					}
				}
				Uri uri = Uri.parse(result);
				handleUri(uri, true);
			}
		}
		finish();
	}
    public static final String ACTION_SCAN_QR_CODE = "scan_qr_code";
    private static final int REQUEST_SCAN_QR_CODE = 0x1234;
    private static final int REQUEST_CAMERA_PERMISSIONS_TO_SCAN = 0x6789;

    private boolean handled = false;

    public static void scan(Activity activity) {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M || ContextCompat.checkSelfPermission(activity, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) {
            Intent intent = new Intent(activity, UriHandlerActivity.class);
            intent.setAction(UriHandlerActivity.ACTION_SCAN_QR_CODE);
            intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
            activity.startActivity(intent);
        } else {
            activity.requestPermissions(new String[]{Manifest.permission.CAMERA}, REQUEST_CAMERA_PERMISSIONS_TO_SCAN);
        }
    }

    public static void onRequestPermissionResult(Activity activity, int requestCode, int[] grantResults) {
        if (requestCode != REQUEST_CAMERA_PERMISSIONS_TO_SCAN) {
            return;
        }
        if (grantResults.length > 0) {
            if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                scan(activity);
            } else {
                Toast.makeText(activity, R.string.qr_code_scanner_needs_access_to_camera, Toast.LENGTH_SHORT).show();
            }
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        this.handled = savedInstanceState != null && savedInstanceState.getBoolean("handled", false);
        getLayoutInflater().inflate(R.layout.toolbar, findViewById(android.R.id.content));
        setSupportActionBar(findViewById(R.id.toolbar));
    }

    @Override
    public void onStart() {
        super.onStart();
        handleIntent(getIntent());
    }

    @Override
    public void onSaveInstanceState(Bundle savedInstanceState) {
        savedInstanceState.putBoolean("handled", this.handled);
        super.onSaveInstanceState(savedInstanceState);
    }

    @Override
    public void onNewIntent(Intent intent) {
        handleIntent(intent);
    }

    private void handleUri(Uri uri) {
        handleUri(uri, false);
    }

    private void handleUri(Uri uri, final boolean scanned) {
        final Intent intent;
        final XmppUri xmppUri = new XmppUri(uri);
        final List<Jid> accounts = DatabaseBackend.getInstance(this).getAccountJids(); //TODO only look at enabled accounts

        if (accounts.size() == 0) {
            if (xmppUri.isJidValid()) {
                intent = SignupUtils.getSignUpIntent(this);
                startActivity(intent);
            } else {
                Toast.makeText(this, R.string.invalid_jid, Toast.LENGTH_SHORT).show();
            }

            return;
        }

        if (xmppUri.isAction(XmppUri.ACTION_MESSAGE)) {

            final Jid jid = xmppUri.getJid();
            final String body = xmppUri.getBody();

            if (jid != null) {
                Class clazz;
                try {
                    clazz = Class.forName("eu.siacs.conversations.ui.ShareViaAccountActivity");
                } catch (ClassNotFoundException e) {
                    clazz = null;

                }
                if (clazz != null) {
                    intent = new Intent(this, clazz);
                    intent.putExtra("contact", jid.toEscapedString());
                    intent.putExtra("body", body);
                } else {
                    intent = new Intent(this, StartConversationActivity.class);
                    intent.setData(uri);
                    intent.putExtra("account", accounts.get(0).toEscapedString());
                }

            } else {
                intent = new Intent(this, ShareWithActivity.class);
                intent.setAction(Intent.ACTION_SEND);
                intent.setType("text/plain");
                intent.putExtra(Intent.EXTRA_TEXT, body);
            }
        } else if (accounts.contains(xmppUri.getJid())) {
            intent = new Intent(getApplicationContext(), EditAccountActivity.class);
            intent.setAction(Intent.ACTION_VIEW);
            intent.putExtra("jid", xmppUri.getJid().asBareJid().toString());
            intent.setData(uri);
            intent.putExtra("scanned", scanned);
        } else if (xmppUri.isJidValid()) {
            intent = new Intent(getApplicationContext(), StartConversationActivity.class);
            intent.setAction(Intent.ACTION_VIEW);
            intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
            intent.putExtra("scanned", scanned);
            intent.setData(uri);
        } else {
            Toast.makeText(this, R.string.invalid_jid, Toast.LENGTH_SHORT).show();
            return;
        }

        startActivity(intent);
    }

    private void handleIntent(Intent data) {
        if (handled) {
            return;
        }
        if (data == null || data.getAction() == null) {
            finish();
            return;
        }

        handled = true;

        switch (data.getAction()) {
            case Intent.ACTION_VIEW:
            case Intent.ACTION_SENDTO:
                handleUri(data.getData());
                break;
            case ACTION_SCAN_QR_CODE:
                Intent intent = new Intent(this, ScanActivity.class);
                startActivityForResult(intent, REQUEST_SCAN_QR_CODE);
                return;
        }

        finish();
    }

    private static final Pattern VCARD_XMPP_PATTERN = Pattern.compile("\nIMPP([^:]*):(xmpp:.+)\n");

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent intent) {
        super.onActivityResult(requestCode, requestCode, intent);
        if (requestCode == REQUEST_SCAN_QR_CODE && resultCode == RESULT_OK) {
            String result = intent.getStringExtra(ScanActivity.INTENT_EXTRA_RESULT);
            if (result != null) {
                if (result.startsWith("BEGIN:VCARD\n")) {
                    Matcher matcher = VCARD_XMPP_PATTERN.matcher(result);
                    if (matcher.find()) {
                        result = matcher.group(2);
                    }
                }
                Uri uri = Uri.parse(result);
                handleUri(uri, true);
            }
        }
        finish();
    }
}
\ No newline at end of file

M src/main/java/eu/siacs/conversations/ui/XmppActivity.java => src/main/java/eu/siacs/conversations/ui/XmppActivity.java +2 -1
@@ 73,6 73,7 @@ import eu.siacs.conversations.services.XmppConnectionService.XmppConnectionBinde
import eu.siacs.conversations.ui.util.MenuDoubleTabUtil;
import eu.siacs.conversations.ui.util.PresenceSelector;
import eu.siacs.conversations.ui.util.SoftKeyboardUtils;
import eu.siacs.conversations.utils.AccountUtils;
import eu.siacs.conversations.utils.ExceptionHelper;
import eu.siacs.conversations.utils.ThemeHelper;
import eu.siacs.conversations.xmpp.OnKeyStatusUpdated;


@@ 338,7 339,7 @@ public abstract class XmppActivity extends ActionBarActivity {
				startActivity(new Intent(this, SettingsActivity.class));
				break;
			case R.id.action_accounts:
				startActivity(new Intent(this, ManageAccountActivity.class));
				AccountUtils.launchManageAccounts(this);
				break;
			case android.R.id.home:
				finish();

A src/main/java/eu/siacs/conversations/utils/AccountUtils.java => src/main/java/eu/siacs/conversations/utils/AccountUtils.java +59 -0
@@ 0,0 1,59 @@
package eu.siacs.conversations.utils;

import android.app.Activity;
import android.content.Intent;
import android.widget.Toast;

import java.util.List;

import eu.siacs.conversations.R;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.services.XmppConnectionService;

public class AccountUtils {

    public static final Class MANAGE_ACCOUNT_ACTIVITY;

    static {
        MANAGE_ACCOUNT_ACTIVITY = getManageAccountActivityClass();
    }


    public static Account getFirstEnabled(XmppConnectionService service) {
        final List<Account> accounts = service.getAccounts();
        for(Account account : accounts) {
            if (!account.isOptionSet(Account.OPTION_DISABLED)) {
                return account;
            }
        }
        return null;
    }

    public static Account getPendingAccount(XmppConnectionService service) {
        Account pending = null;
        for (Account account : service.getAccounts()) {
            if (!account.isOptionSet(Account.OPTION_LOGGED_IN_SUCCESSFULLY)) {
                pending = account;
            } else {
                return null;
            }
        }
        return pending;
    }

    public static void launchManageAccounts(Activity activity) {
        if (MANAGE_ACCOUNT_ACTIVITY != null) {
            activity.startActivity(new Intent(activity, MANAGE_ACCOUNT_ACTIVITY));
        } else {
            Toast.makeText(activity, R.string.feature_not_implemented, Toast.LENGTH_SHORT).show();
        }
    }

    private static Class getManageAccountActivityClass() {
        try {
            return Class.forName("eu.siacs.conversations.ui.ManageAccountActivity");
        } catch (ClassNotFoundException e) {
            return null;
        }
    }
}

M src/main/java/eu/siacs/conversations/utils/ExceptionHelper.java => src/main/java/eu/siacs/conversations/utils/ExceptionHelper.java +3 -11
@@ 50,18 50,10 @@ public class ExceptionHelper {
			if (neverSend || Config.BUG_REPORTS == null) {
				return false;
			}
			List<Account> accounts = service.getAccounts();
			Account account = null;
			for (int i = 0; i < accounts.size(); ++i) {
				if (accounts.get(i).isEnabled()) {
					account = accounts.get(i);
					break;
				}
			}
			final Account account = AccountUtils.getFirstEnabled(service);
			if (account == null) {
				return false;
			}
			final Account finalAccount = account;
			FileInputStream file = activity.openFileInput(FILENAME);
			InputStreamReader inputStreamReader = new InputStreamReader(file);
			BufferedReader stacktrace = new BufferedReader(inputStreamReader);


@@ 93,8 85,8 @@ public class ExceptionHelper {
			builder.setMessage(activity.getText(R.string.crash_report_message));
			builder.setPositiveButton(activity.getText(R.string.send_now), (dialog, which) -> {

				Log.d(Config.LOGTAG, "using account=" + finalAccount.getJid().asBareJid() + " to send in stack trace");
				Conversation conversation = service.findOrCreateConversation(finalAccount, Config.BUG_REPORTS, false, true);
				Log.d(Config.LOGTAG, "using account=" + account.getJid().asBareJid() + " to send in stack trace");
				Conversation conversation = service.findOrCreateConversation(account, Config.BUG_REPORTS, false, true);
				Message message = new Message(conversation, report.toString(), Message.ENCRYPTION_NONE);
				service.sendMessage(message);
			});

M src/main/java/eu/siacs/conversations/utils/XmppUri.java => src/main/java/eu/siacs/conversations/utils/XmppUri.java +1 -1
@@ 180,7 180,7 @@ public class XmppUri {

	public Jid getJid() {
		try {
			return this.jid == null ? null : Jid.of(this.jid.toLowerCase());
			return this.jid == null ? null : Jid.of(this.jid);
		} catch (IllegalArgumentException e) {
			return null;
		}

M src/main/res/values/strings.xml => src/main/res/values/strings.xml +1 -0
@@ 748,4 748,5 @@
    <string name="video_720p">High (720p)</string>
    <string name="cancelled">cancelled</string>
    <string name="already_drafting_message">You are already drafting a message.</string>
    <string name="feature_not_implemented">Feature not implemented</string>
</resources>

A src/quick/java/eu/siacs/conversations/utils/SignupUtils.java => src/quick/java/eu/siacs/conversations/utils/SignupUtils.java +17 -0
@@ 0,0 1,17 @@
package eu.siacs.conversations.utils;

import android.app.Activity;
import android.content.Intent;

import eu.siacs.conversations.ui.ConversationsActivity;

public class SignupUtils {

    public static Intent getSignUpIntent(Activity activity) {
        return null;
    }

    public static Intent getRedirectionIntent(ConversationsActivity activity) {
        return null;
    }
}
\ No newline at end of file