refactored some ManageAccount, WelcomeActivity and a few other things into 'full' flavor

Daniel Gultsch created

Change summary

build.gradle                                                               |   8 
src/full/AndroidManifest.xml                                               |  21 
src/full/java/eu/siacs/conversations/ui/MagicCreateActivity.java           |   2 
src/full/java/eu/siacs/conversations/ui/ManageAccountActivity.java         |   0 
src/full/java/eu/siacs/conversations/ui/ShareViaAccountActivity.java       |   0 
src/full/java/eu/siacs/conversations/ui/WelcomeActivity.java               |  16 
src/full/java/eu/siacs/conversations/ui/adapter/AccountAdapter.java        |   0 
src/full/java/eu/siacs/conversations/utils/SignupUtils.java                |  47 
src/main/AndroidManifest.xml                                               |  12 
src/main/java/eu/siacs/conversations/services/NotificationService.java     |  15 
src/main/java/eu/siacs/conversations/services/XmppConnectionService.java   |  12 
src/main/java/eu/siacs/conversations/ui/ConversationsActivity.java         |  34 
src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java           |  11 
src/main/java/eu/siacs/conversations/ui/PublishProfilePictureActivity.java |   4 
src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java     |  12 
src/main/java/eu/siacs/conversations/ui/UriHandlerActivity.java            | 329 
src/main/java/eu/siacs/conversations/ui/XmppActivity.java                  |   3 
src/main/java/eu/siacs/conversations/utils/AccountUtils.java               |  59 
src/main/java/eu/siacs/conversations/utils/ExceptionHelper.java            |  14 
src/main/java/eu/siacs/conversations/utils/XmppUri.java                    |   2 
src/main/res/values/strings.xml                                            |   1 
src/quick/java/eu/siacs/conversations/utils/SignupUtils.java               |  17 
22 files changed, 364 insertions(+), 255 deletions(-)

Detailed changes

build.gradle 🔗

@@ -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'

src/full/AndroidManifest.xml 🔗

@@ -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>

src/main/java/eu/siacs/conversations/ui/MagicCreateActivity.java → src/full/java/eu/siacs/conversations/ui/MagicCreateActivity.java 🔗

@@ -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) {

src/main/java/eu/siacs/conversations/ui/WelcomeActivity.java → src/full/java/eu/siacs/conversations/ui/WelcomeActivity.java 🔗

@@ -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) {

src/full/java/eu/siacs/conversations/utils/SignupUtils.java 🔗

@@ -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;
+    }
+}

src/main/AndroidManifest.xml 🔗

@@ -147,14 +147,6 @@
                 <action android:name="android.intent.action.VIEW"/>
             </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">
@@ -172,10 +164,6 @@
         <activity
             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"

src/main/java/eu/siacs/conversations/services/NotificationService.java 🔗

@@ -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");
         }

src/main/java/eu/siacs/conversations/services/XmppConnectionService.java 🔗

@@ -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);

src/main/java/eu/siacs/conversations/ui/ConversationsActivity.java 🔗

@@ -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;

src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java 🔗

@@ -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();
 		});

src/main/java/eu/siacs/conversations/ui/PublishProfilePictureActivity.java 🔗

@@ -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);

src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java 🔗

@@ -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;

src/main/java/eu/siacs/conversations/ui/UriHandlerActivity.java 🔗

@@ -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();
+    }
 }

src/main/java/eu/siacs/conversations/ui/XmppActivity.java 🔗

@@ -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();

src/main/java/eu/siacs/conversations/utils/AccountUtils.java 🔗

@@ -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;
+        }
+    }
+}

src/main/java/eu/siacs/conversations/utils/ExceptionHelper.java 🔗

@@ -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);
 			});

src/main/java/eu/siacs/conversations/utils/XmppUri.java 🔗

@@ -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;
 		}

src/main/res/values/strings.xml 🔗

@@ -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>

src/quick/java/eu/siacs/conversations/utils/SignupUtils.java 🔗

@@ -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;
+    }
+}