refined create conference dialog

Daniel Gultsch created

Change summary

src/main/java/eu/siacs/conversations/services/XmppConnectionService.java | 20 
src/main/java/eu/siacs/conversations/ui/ChooseContactActivity.java       | 64 
src/main/java/eu/siacs/conversations/ui/CreateConferenceDialog.java      |  9 
src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java   | 35 
src/main/java/eu/siacs/conversations/ui/XmppActivity.java                | 15 
src/main/java/eu/siacs/conversations/utils/CryptoHelper.java             | 14 
src/main/res/layout/create_conference_dialog.xml                         | 12 
src/main/res/values/strings.xml                                          |  2 
8 files changed, 86 insertions(+), 85 deletions(-)

Detailed changes

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

@@ -29,6 +29,7 @@ import android.security.KeyChain;
 import android.support.annotation.BoolRes;
 import android.support.annotation.IntegerRes;
 import android.support.v4.app.RemoteInput;
+import android.text.TextUtils;
 import android.util.DisplayMetrics;
 import android.util.Log;
 import android.util.LruCache;
@@ -2375,7 +2376,7 @@ public class XmppConnectionService extends Service {
 	}
 
 	public boolean createAdhocConference(final Account account,
-	                                     final String subject,
+	                                     final String name,
 	                                     final Iterable<Jid> jids,
 	                                     final UiCallback<Conversation> callback) {
 		Log.d(Config.LOGTAG, account.getJid().asBareJid().toString() + ": creating adhoc conference with " + jids.toString());
@@ -2388,24 +2389,25 @@ public class XmppConnectionService extends Service {
 					}
 					return false;
 				}
-				final Jid jid = Jid.of(new BigInteger(64, getRNG()).toString(Character.MAX_RADIX), server, null);
+				final Jid jid = Jid.of(CryptoHelper.pronounceable(getRNG()), server, null);
 				final Conversation conversation = findOrCreateConversation(account, jid, true, false, true);
 				joinMuc(conversation, new OnConferenceJoined() {
 					@Override
 					public void onConferenceJoined(final Conversation conversation) {
-						pushConferenceConfiguration(conversation, IqGenerator.defaultRoomConfiguration(), new OnConfigurationPushed() {
+						final Bundle configuration = IqGenerator.defaultRoomConfiguration();
+						if (!TextUtils.isEmpty(name)) {
+							configuration.putString("muc#roomconfig_roomname", name);
+						}
+						pushConferenceConfiguration(conversation, configuration, new OnConfigurationPushed() {
 							@Override
 							public void onPushSucceeded() {
-								if (subject != null && !subject.trim().isEmpty()) {
-									pushSubjectToConference(conversation, subject.trim());
-								}
 								for (Jid invite : jids) {
 									invite(conversation, invite);
 								}
 								if (account.countPresences() > 1) {
 									directInvite(conversation, account.getJid().asBareJid());
 								}
-								saveConversationAsBookmark(conversation, subject);
+								saveConversationAsBookmark(conversation, name);
 								if (callback != null) {
 									callback.success(conversation);
 								}
@@ -3755,8 +3757,8 @@ public class XmppConnectionService extends Service {
 		if (!conversation.getJid().isBareJid()) {
 			bookmark.setNick(conversation.getJid().getResource());
 		}
-		if (name != null && !name.trim().isEmpty()) {
-			bookmark.setBookmarkName(name.trim());
+		if (!TextUtils.isEmpty(name)) {
+			bookmark.setBookmarkName(name);
 		}
 		bookmark.setAutojoin(getPreferences().getBoolean("autojoin", getResources().getBoolean(R.bool.autojoin)));
 		account.getBookmarks().add(bookmark);

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

@@ -39,6 +39,11 @@ import rocks.xmpp.addr.Jid;
 
 public class ChooseContactActivity extends AbstractSearchableListItemActivity implements MultiChoiceModeListener {
     public static final String EXTRA_TITLE_RES_ID = "extra_title_res_id";
+    public static final String EXTRA_GROUP_CHAT_NAME = "extra_group_chat_name";
+    public static final String EXTRA_SELECT_MULTIPLE = "extra_select_multiple";
+    public static final String EXTRA_SHOW_ENTER_JID = "extra_show_enter_jid";
+    public static final String EXTRA_CONVERSATION = "extra_conversation";
+    private static final String EXTRA_FILTERED_CONTACTS = "extra_filtered_contacts";
     private List<String> mActivatedAccounts = new ArrayList<>();
     private Set<String> selected = new HashSet<>();
     private Set<String> filterContacts;
@@ -60,14 +65,31 @@ public class ChooseContactActivity extends AbstractSearchableListItemActivity im
         } else {
             contacts.add(conversation.getJid().asBareJid().toString());
         }
-        intent.putExtra("filter_contacts", contacts.toArray(new String[contacts.size()]));
-        intent.putExtra("conversation", conversation.getUuid());
-        intent.putExtra("multiple", true);
-        intent.putExtra("show_enter_jid", true);
+        intent.putExtra(EXTRA_FILTERED_CONTACTS, contacts.toArray(new String[contacts.size()]));
+        intent.putExtra(EXTRA_CONVERSATION, conversation.getUuid());
+        intent.putExtra(EXTRA_SELECT_MULTIPLE, true);
+        intent.putExtra(EXTRA_SHOW_ENTER_JID, true);
         intent.putExtra(EXTRA_ACCOUNT, conversation.getAccount().getJid().asBareJid().toString());
         return intent;
     }
 
+    public static List<Jid> extractJabberIds(Intent result) {
+        List<Jid> jabberIds = new ArrayList<>();
+        try {
+            if (result.getBooleanExtra(EXTRA_SELECT_MULTIPLE, false)) {
+                String[] toAdd = result.getStringArrayExtra("contacts");
+                for (String item : toAdd) {
+                    jabberIds.add(Jid.of(item));
+                }
+            } else {
+                jabberIds.add(Jid.of(result.getStringExtra("contact")));
+            }
+            return jabberIds;
+        } catch (IllegalArgumentException e) {
+            return jabberIds;
+        }
+    }
+
     @Override
     public void onCreate(final Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
@@ -80,14 +102,14 @@ public class ChooseContactActivity extends AbstractSearchableListItemActivity im
             }
         }
 
-        String[] contacts = getIntent().getStringArrayExtra("filter_contacts");
+        String[] contacts = getIntent().getStringArrayExtra(EXTRA_FILTERED_CONTACTS);
         if (contacts != null) {
             Collections.addAll(filterContacts, contacts);
         }
 
         Intent intent = getIntent();
 
-        final boolean multiple = intent.getBooleanExtra("multiple", false);
+        final boolean multiple = intent.getBooleanExtra(EXTRA_SELECT_MULTIPLE, false);
         if (multiple) {
             getListView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
             getListView().setMultiChoiceModeListener(this);
@@ -110,14 +132,13 @@ public class ChooseContactActivity extends AbstractSearchableListItemActivity im
                 account = ((Contact) mListItem).getAccount().getJid().asBareJid().toString();
             }
             data.putExtra(EXTRA_ACCOUNT, account);
-            data.putExtra("conversation", request.getStringExtra("conversation"));
-            data.putExtra("multiple", false);
-            data.putExtra("subject", request.getStringExtra("subject"));
+            data.putExtra(EXTRA_SELECT_MULTIPLE, false);
+            copy(request, data);
             setResult(RESULT_OK, data);
             finish();
         });
         final Intent i = getIntent();
-        this.showEnterJid = i != null && i.getBooleanExtra("show_enter_jid", false);
+        this.showEnterJid = i != null && i.getBooleanExtra(EXTRA_SHOW_ENTER_JID, false);
         this.binding.fab.setOnClickListener(this::onFabClicked);
         if (this.showEnterJid) {
             this.binding.fab.setVisibility(View.VISIBLE);
@@ -171,16 +192,19 @@ public class ChooseContactActivity extends AbstractSearchableListItemActivity im
     private void submitSelection() {
         final Intent request = getIntent();
         final Intent data = new Intent();
-        data.putExtra("conversation", request.getStringExtra("conversation"));
-        String[] selection = getSelectedContactJids();
-        data.putExtra("contacts", selection);
-        data.putExtra("multiple", true);
+        data.putExtra("contacts", getSelectedContactJids());
+        data.putExtra(EXTRA_SELECT_MULTIPLE, true);
         data.putExtra(EXTRA_ACCOUNT, request.getStringExtra(EXTRA_ACCOUNT));
-        data.putExtra("subject", request.getStringExtra("subject"));
+        copy(request, data);
         setResult(RESULT_OK, data);
         finish();
     }
 
+    private static void copy(Intent from, Intent to) {
+        to.putExtra(EXTRA_CONVERSATION, from.getStringExtra(EXTRA_CONVERSATION));
+        to.putExtra(EXTRA_GROUP_CHAT_NAME, from.getStringExtra(EXTRA_GROUP_CHAT_NAME));
+    }
+
     @Override
     public void onItemCheckedStateChanged(ActionMode mode, int position, long id, boolean checked) {
         Contact item = (Contact) getListItems().get(position);
@@ -207,7 +231,7 @@ public class ChooseContactActivity extends AbstractSearchableListItemActivity im
     public @StringRes
     int getTitleFromIntent() {
         final Intent intent = getIntent();
-        boolean multiple = intent != null && intent.getBooleanExtra("multiple", false);
+        boolean multiple = intent != null && intent.getBooleanExtra(EXTRA_SELECT_MULTIPLE, false);
         @StringRes int fallback = multiple ? R.string.title_activity_choose_contacts : R.string.title_activity_choose_contact;
         return intent != null ? intent.getIntExtra(EXTRA_TITLE_RES_ID, fallback) : fallback;
     }
@@ -216,7 +240,7 @@ public class ChooseContactActivity extends AbstractSearchableListItemActivity im
     public boolean onCreateOptionsMenu(final Menu menu) {
         super.onCreateOptionsMenu(menu);
         final Intent i = getIntent();
-        boolean showEnterJid = i != null && i.getBooleanExtra("show_enter_jid", false);
+        boolean showEnterJid = i != null && i.getBooleanExtra(EXTRA_SHOW_ENTER_JID, false);
         menu.findItem(R.id.action_scan_qr_code).setVisible(isCameraFeatureAvailable() && showEnterJid);
         return true;
     }
@@ -288,10 +312,8 @@ public class ChooseContactActivity extends AbstractSearchableListItemActivity im
             final Intent data = new Intent();
             data.putExtra("contact", contactJid.toString());
             data.putExtra(EXTRA_ACCOUNT, accountJid.toString());
-            data.putExtra("conversation",
-                    request.getStringExtra("conversation"));
-            data.putExtra("multiple", false);
-            data.putExtra("subject", request.getStringExtra("subject"));
+            data.putExtra(EXTRA_SELECT_MULTIPLE, false);
+            copy(request, data);
             setResult(RESULT_OK, data);
             finish();
 

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

@@ -17,6 +17,7 @@ import java.util.List;
 
 import eu.siacs.conversations.R;
 import eu.siacs.conversations.databinding.CreateConferenceDialogBinding;
+import eu.siacs.conversations.ui.util.DelayedHintHelper;
 
 public class CreateConferenceDialog extends DialogFragment {
 
@@ -46,13 +47,9 @@ public class CreateConferenceDialog extends DialogFragment {
         ArrayList<String> mActivatedAccounts = getArguments().getStringArrayList(ACCOUNTS_LIST_KEY);
         StartConversationActivity.populateAccountSpinner(getActivity(), mActivatedAccounts, binding.account);
         builder.setView(binding.getRoot());
-        builder.setPositiveButton(R.string.choose_participants, new DialogInterface.OnClickListener() {
-            @Override
-            public void onClick(DialogInterface dialog, int which) {
-                mListener.onCreateDialogPositiveClick(binding.account, binding.subject.getText().toString());
-            }
-        });
+        builder.setPositiveButton(R.string.choose_participants, (dialog, which) -> mListener.onCreateDialogPositiveClick(binding.account, binding.groupChatName.getText().toString().trim()));
         builder.setNegativeButton(R.string.cancel, null);
+        DelayedHintHelper.setHint(R.string.providing_a_name_is_optional, binding.groupChatName);
         return builder.create();
     }
 

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

@@ -653,26 +653,10 @@ public class StartConversationActivity extends XmppActivity implements XmppConne
 				this.mPostponedActivityResult = null;
 				if (requestCode == REQUEST_CREATE_CONFERENCE) {
 					Account account = extractAccount(intent);
-					final String subject = intent.getStringExtra("subject");
-					List<Jid> jids = new ArrayList<>();
-					if (intent.getBooleanExtra("multiple", false)) {
-						String[] toAdd = intent.getStringArrayExtra("contacts");
-						for (String item : toAdd) {
-							try {
-								jids.add(Jid.of(item));
-							} catch (IllegalArgumentException e) {
-								//ignored
-							}
-						}
-					} else {
-						try {
-							jids.add(Jid.of(intent.getStringExtra("contact")));
-						} catch (Exception e) {
-							//ignored
-						}
-					}
+					final String name = intent.getStringExtra(ChooseContactActivity.EXTRA_GROUP_CHAT_NAME);
+					final List<Jid> jids = ChooseContactActivity.extractJabberIds(intent);
 					if (account != null && jids.size() > 0) {
-						if (xmppConnectionService.createAdhocConference(account, subject, jids, mAdhocConferenceCallback)) {
+						if (xmppConnectionService.createAdhocConference(account, name, jids, mAdhocConferenceCallback)) {
 							mToast = Toast.makeText(this, R.string.creating_conference, Toast.LENGTH_LONG);
 							mToast.show();
 						}
@@ -945,7 +929,7 @@ public class StartConversationActivity extends XmppActivity implements XmppConne
 	}
 
 	@Override
-	public void onCreateDialogPositiveClick(Spinner spinner, String subject) {
+	public void onCreateDialogPositiveClick(Spinner spinner, String name) {
 		if (!xmppConnectionServiceBound) {
 			return;
 		}
@@ -954,10 +938,10 @@ public class StartConversationActivity extends XmppActivity implements XmppConne
 			return;
 		}
 		Intent intent = new Intent(getApplicationContext(), ChooseContactActivity.class);
-		intent.putExtra("multiple", true);
-		intent.putExtra("show_enter_jid", true);
-		intent.putExtra("subject", subject);
-		intent.putExtra(EXTRA_ACCOUNT, account.getJid().asBareJid().toString());
+		intent.putExtra(ChooseContactActivity.EXTRA_SHOW_ENTER_JID, false);
+		intent.putExtra(ChooseContactActivity.EXTRA_SELECT_MULTIPLE, true);
+		intent.putExtra(ChooseContactActivity.EXTRA_GROUP_CHAT_NAME, name.trim());
+		intent.putExtra(ChooseContactActivity.EXTRA_ACCOUNT, account.getJid().asBareJid().toString());
 		intent.putExtra(ChooseContactActivity.EXTRA_TITLE_RES_ID, R.string.choose_participants);
 		startActivityForResult(intent, REQUEST_CREATE_CONFERENCE);
 	}
@@ -1039,8 +1023,7 @@ public class StartConversationActivity extends XmppActivity implements XmppConne
 		}
 
 		@Override
-		public void onCreateContextMenu(final ContextMenu menu, final View v,
-		                                final ContextMenuInfo menuInfo) {
+		public void onCreateContextMenu(final ContextMenu menu, final View v, final ContextMenuInfo menuInfo) {
 			super.onCreateContextMenu(menu, v, menuInfo);
 			final StartConversationActivity activity = (StartConversationActivity) getActivity();
 			if (activity == null) {

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

@@ -924,22 +924,11 @@ public abstract class XmppActivity extends ActionBarActivity {
 
 		public static ConferenceInvite parse(Intent data) {
 			ConferenceInvite invite = new ConferenceInvite();
-			invite.uuid = data.getStringExtra("conversation");
+			invite.uuid = data.getStringExtra(ChooseContactActivity.EXTRA_CONVERSATION);
 			if (invite.uuid == null) {
 				return null;
 			}
-			try {
-				if (data.getBooleanExtra("multiple", false)) {
-					String[] toAdd = data.getStringArrayExtra("contacts");
-					for (String item : toAdd) {
-						invite.jids.add(Jid.of(item));
-					}
-				} else {
-					invite.jids.add(Jid.of(data.getStringExtra("contact")));
-				}
-			} catch (final IllegalArgumentException ignored) {
-				return null;
-			}
+			invite.jids.addAll(ChooseContactActivity.extractJabberIds(data));
 			return invite;
 		}
 

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

@@ -35,6 +35,10 @@ import eu.siacs.conversations.http.AesGcmURLStreamHandler;
 import rocks.xmpp.addr.Jid;
 
 public final class CryptoHelper {
+
+	private static final char[] VOWELS = "aeiou".toCharArray();
+	private static final char[] CONSONANTS = "bcfghjklmnpqrstvwxyz".toCharArray();
+
 	private final static char[] hexArray = "0123456789abcdef".toCharArray();
 
 	public static final Pattern UUID_PATTERN = Pattern.compile("[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}");
@@ -50,6 +54,16 @@ public final class CryptoHelper {
 		return new String(hexChars);
 	}
 
+	public static String pronounceable(SecureRandom random) {
+		char[] output = new char[random.nextInt(4) * 2 + 5];
+		boolean vowel = random.nextBoolean();
+		for(int i = 0; i < output.length; ++i) {
+			output[i] = vowel ? VOWELS[random.nextInt(VOWELS.length)] : CONSONANTS[random.nextInt(CONSONANTS.length)];
+			vowel = !vowel;
+		}
+		return String.valueOf(output);
+	}
+
 	public static byte[] hexToBytes(String hexString) {
 		int len = hexString.length();
 		byte[] array = new byte[len / 2];

src/main/res/layout/create_conference_dialog.xml 🔗

@@ -22,12 +22,6 @@
             android:layout_width="fill_parent"
             android:layout_height="wrap_content"/>
 
-        <View
-            android:layout_width="0dp"
-            android:layout_height="0dp"
-            android:focusable="true"
-            android:focusableInTouchMode="true"/>
-
         <android.support.design.widget.TextInputLayout
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
@@ -35,13 +29,11 @@
             app:hintTextAppearance="@style/TextAppearance.Conversations.Design.Hint">
 
             <android.support.design.widget.TextInputEditText
-                android:id="@+id/subject"
+                android:id="@+id/group_chat_name"
                 style="@style/Widget.Conversations.EditText"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
-                android:hint="@string/topic"
-                android:nextFocusDown="@+id/subject"
-                android:nextFocusUp="@+id/subject"/>
+                android:hint="@string/create_dialog_group_chat_name"/>
         </android.support.design.widget.TextInputLayout>
     </LinearLayout>
 </layout>

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

@@ -717,4 +717,6 @@
     <string name="contact_name">Contact name</string>
     <string name="nickname">Nickname</string>
     <string name="group_chat_name">Name</string>
+    <string name="providing_a_name_is_optional">Providing a name is optional</string>
+    <string name="create_dialog_group_chat_name">Group chat name</string>
 </resources>