From 53fea9e1fe25a1f0f2a7fe219195b0009ecb4f5b Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Sat, 2 May 2015 11:38:56 +0200 Subject: replace send button with quick action button as long as no text has been entered --- .../conversations/ui/ConversationActivity.java | 23 +- .../conversations/ui/ConversationFragment.java | 275 +++++++++++++-------- 2 files changed, 192 insertions(+), 106 deletions(-) (limited to 'src/main/java/eu/siacs') diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java index aec755fce..a76efbc35 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java @@ -60,11 +60,11 @@ public class ConversationActivity extends XmppActivity public static final int REQUEST_SEND_MESSAGE = 0x0201; public static final int REQUEST_DECRYPT_PGP = 0x0202; public static final int REQUEST_ENCRYPT_MESSAGE = 0x0207; - private static final int ATTACHMENT_CHOICE_CHOOSE_IMAGE = 0x0301; - private static final int ATTACHMENT_CHOICE_TAKE_PHOTO = 0x0302; - private static final int ATTACHMENT_CHOICE_CHOOSE_FILE = 0x0303; - private static final int ATTACHMENT_CHOICE_RECORD_VOICE = 0x0304; - private static final int ATTACHMENT_CHOICE_LOCATION = 0x0305; + public static final int ATTACHMENT_CHOICE_CHOOSE_IMAGE = 0x0301; + public static final int ATTACHMENT_CHOICE_TAKE_PHOTO = 0x0302; + public static final int ATTACHMENT_CHOICE_CHOOSE_FILE = 0x0303; + public static final int ATTACHMENT_CHOICE_RECORD_VOICE = 0x0304; + public static final int ATTACHMENT_CHOICE_LOCATION = 0x0305; private static final String STATE_OPEN_CONVERSATION = "state_open_conversation"; private static final String STATE_PANEL_OPEN = "state_panel_open"; private static final String STATE_PENDING_URI = "state_pending_uri"; @@ -452,7 +452,18 @@ public class ConversationActivity extends XmppActivity } } - private void attachFile(final int attachmentChoice) { + public void attachFile(final int attachmentChoice) { + switch (attachmentChoice) { + case ATTACHMENT_CHOICE_LOCATION: + getPreferences().edit().putString("recently_used_quick_action","location").apply(); + break; + case ATTACHMENT_CHOICE_RECORD_VOICE: + getPreferences().edit().putString("recently_used_quick_action","voice").apply(); + break; + case ATTACHMENT_CHOICE_TAKE_PHOTO: + getPreferences().edit().putString("recently_used_quick_action","photo").apply(); + break; + } final Conversation conversation = getSelectedConversation(); final int encryption = conversation.getNextEncryption(forceEncryption()); if (encryption == Message.ENCRYPTION_PGP) { diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java index 5b1e9b4d6..37ae00a30 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java @@ -119,7 +119,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa @Override public void onScroll(AbsListView view, int firstVisibleItem, - int visibleItemCount, int totalItemCount) { + int visibleItemCount, int totalItemCount) { synchronized (ConversationFragment.this.messageList) { if (firstVisibleItem < 5 && messagesLoaded && messageList.size() > 0) { long timestamp = ConversationFragment.this.messageList.get(0).getTimeSent(); @@ -145,7 +145,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa try { Message tmpMessage = messageList.get(newPosition); - while(tmpMessage.wasMergedIntoPrevious()) { + while (tmpMessage.wasMergedIntoPrevious()) { offset++; tmpMessage = tmpMessage.prev(); } @@ -174,7 +174,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa if (ConversationFragment.this.conversation != conversation) { return; } - messageLoaderToast = Toast.makeText(activity,resId,Toast.LENGTH_LONG); + messageLoaderToast = Toast.makeText(activity, resId, Toast.LENGTH_LONG); messageLoaderToast.show(); } }); @@ -208,7 +208,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa @Override public void onClick(View v) { - activity.verifyOtrSessionDialog(conversation,v); + activity.verifyOtrSessionDialog(conversation, v); } }; private ConcurrentLinkedQueue mEncryptedMessages = new ConcurrentLinkedQueue<>(); @@ -219,7 +219,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { if (actionId == EditorInfo.IME_ACTION_SEND) { InputMethodManager imm = (InputMethodManager) v.getContext() - .getSystemService(Context.INPUT_METHOD_SERVICE); + .getSystemService(Context.INPUT_METHOD_SERVICE); imm.hideSoftInputFromWindow(v.getWindowToken(), 0); sendMessage(); return true; @@ -232,7 +232,25 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa @Override public void onClick(View v) { - sendMessage(); + Object tag = v.getTag(); + if (tag instanceof SendButtonAction) { + SendButtonAction action = (SendButtonAction) tag; + switch (action) { + case TAKE_PHOTO: + activity.attachFile(ConversationActivity.ATTACHMENT_CHOICE_TAKE_PHOTO); + break; + case SEND_LOCATION: + activity.attachFile(ConversationActivity.ATTACHMENT_CHOICE_LOCATION); + break; + case RECORD_VOICE: + activity.attachFile(ConversationActivity.ATTACHMENT_CHOICE_RECORD_VOICE); + break; + default: + sendMessage(); + } + } else { + sendMessage(); + } } }; private OnClickListener clickToMuc = new OnClickListener() { @@ -262,7 +280,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa } Message message = new Message(conversation, mEditMessage.getText() .toString(), conversation.getNextEncryption(activity - .forceEncryption())); + .forceEncryption())); if (conversation.getMode() == Conversation.MODE_MULTI) { if (conversation.getNextCounterpart() != null) { message.setCounterpart(conversation.getNextCounterpart()); @@ -282,13 +300,13 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa if (conversation.getMode() == Conversation.MODE_MULTI && conversation.getNextCounterpart() != null) { this.mEditMessage.setHint(getString( - R.string.send_private_message_to, - conversation.getNextCounterpart().getResourcepart())); + R.string.send_private_message_to, + conversation.getNextCounterpart().getResourcepart())); } else { switch (conversation.getNextEncryption(activity.forceEncryption())) { case Message.ENCRYPTION_NONE: mEditMessage - .setHint(getString(R.string.send_plain_text_message)); + .setHint(getString(R.string.send_plain_text_message)); break; case Message.ENCRYPTION_OTR: mEditMessage.setHint(getString(R.string.send_otr_message)); @@ -304,7 +322,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa } private void setupIme() { - if (((ConversationActivity)getActivity()).usingEnterKey()) { + if (((ConversationActivity) getActivity()).usingEnterKey()) { mEditMessage.setInputType(mEditMessage.getInputType() & (~InputType.TYPE_TEXT_VARIATION_SHORT_MESSAGE)); } else { mEditMessage.setInputType(mEditMessage.getInputType() | InputType.TYPE_TEXT_VARIATION_SHORT_MESSAGE); @@ -313,8 +331,8 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa @Override public View onCreateView(final LayoutInflater inflater, - ViewGroup container, Bundle savedInstanceState) { - final View view = inflater.inflate(R.layout.fragment_conversation,container, false); + ViewGroup container, Bundle savedInstanceState) { + final View view = inflater.inflate(R.layout.fragment_conversation, container, false); view.setOnClickListener(null); mEditMessage = (EditMessage) view.findViewById(R.id.textinput); setupIme(); @@ -365,21 +383,21 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa } }); messageListAdapter - .setOnContactPictureLongClicked(new OnContactPictureLongClicked() { + .setOnContactPictureLongClicked(new OnContactPictureLongClicked() { - @Override - public void onContactPictureLongClicked(Message message) { - if (message.getStatus() <= Message.STATUS_RECEIVED) { - if (message.getConversation().getMode() == Conversation.MODE_MULTI) { - if (message.getCounterpart() != null) { - privateMessageWith(message.getCounterpart()); + @Override + public void onContactPictureLongClicked(Message message) { + if (message.getStatus() <= Message.STATUS_RECEIVED) { + if (message.getConversation().getMode() == Conversation.MODE_MULTI) { + if (message.getCounterpart() != null) { + privateMessageWith(message.getCounterpart()); + } } + } else { + activity.showQrCode(); } - } else { - activity.showQrCode(); } - } - }); + }); messagesView.setAdapter(messageListAdapter); registerForContextMenu(messagesView); @@ -389,7 +407,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa @Override public void onCreateContextMenu(ContextMenu menu, View v, - ContextMenuInfo menuInfo) { + ContextMenuInfo menuInfo) { synchronized (this.messageList) { super.onCreateContextMenu(menu, v, menuInfo); AdapterView.AdapterContextMenuInfo acmi = (AdapterContextMenuInfo) menuInfo; @@ -416,7 +434,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa if ((m.getType() == Message.TYPE_TEXT || m.getType() == Message.TYPE_PRIVATE || m.getDownloadable() != null) - && (!GeoHelper.isGeoUri(m.getBody()))) { + && (!GeoHelper.isGeoUri(m.getBody()))) { shareWith.setVisible(false); } if (m.getStatus() != Message.STATUS_SEND_FAILED) { @@ -425,17 +443,17 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa if (((m.getType() != Message.TYPE_IMAGE && m.getDownloadable() == null) || m.getImageParams().url == null) && !GeoHelper.isGeoUri(m.getBody())) { copyUrl.setVisible(false); - } + } if (m.getType() != Message.TYPE_TEXT || m.getDownloadable() != null || !m.bodyContainsDownloadable()) { downloadImage.setVisible(false); - } + } if (!((m.getDownloadable() != null && !(m.getDownloadable() instanceof DownloadablePlaceholder)) - || (m.isFileOrImage() && (m.getStatus() == Message.STATUS_WAITING - || m.getStatus() == Message.STATUS_OFFERED)))) { + || (m.isFileOrImage() && (m.getStatus() == Message.STATUS_WAITING + || m.getStatus() == Message.STATUS_OFFERED)))) { cancelTransmission.setVisible(false); - } + } } } @@ -483,12 +501,12 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa } shareIntent.setType(mime); } - activity.startActivity(Intent.createChooser(shareIntent,getText(R.string.share_with))); + activity.startActivity(Intent.createChooser(shareIntent, getText(R.string.share_with))); } private void copyText(Message message) { if (activity.copyTextToClipboard(message.getMergedBody(), - R.string.message_text)) { + R.string.message_text)) { Toast.makeText(activity, R.string.message_copied_to_clipboard, Toast.LENGTH_SHORT).show(); } @@ -498,7 +516,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa if (message.getType() == Message.TYPE_FILE || message.getType() == Message.TYPE_IMAGE) { DownloadableFile file = activity.xmppConnectionService.getFileBackend().getFile(message); if (!file.exists()) { - Toast.makeText(activity,R.string.file_deleted,Toast.LENGTH_SHORT).show(); + Toast.makeText(activity, R.string.file_deleted, Toast.LENGTH_SHORT).show(); message.setDownloadable(new DownloadablePlaceholder(Downloadable.STATUS_DELETED)); return; } @@ -519,20 +537,20 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa if (activity.copyTextToClipboard(url, resId)) { Toast.makeText(activity, R.string.url_copied_to_clipboard, Toast.LENGTH_SHORT).show(); - } + } } private void downloadImage(Message message) { activity.xmppConnectionService.getHttpConnectionManager() - .createNewConnection(message); + .createNewConnection(message); } private void cancelTransmission(Message message) { Downloadable downloadable = message.getDownloadable(); - if (downloadable!=null) { + if (downloadable != null) { downloadable.cancel(); } else { - activity.xmppConnectionService.markMessage(message,Message.STATUS_SEND_FAILED); + activity.xmppConnectionService.markMessage(message, Message.STATUS_SEND_FAILED); } } @@ -548,9 +566,9 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa mEditMessage.getText().insert(0, nick + ": "); } else { if (mEditMessage.getText().charAt( - mEditMessage.getSelectionStart() - 1) != ' ') { + mEditMessage.getSelectionStart() - 1) != ' ') { nick = " " + nick; - } + } mEditMessage.getText().insert(mEditMessage.getSelectionStart(), nick + " "); } @@ -563,7 +581,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa if (this.conversation != null) { final String msg = mEditMessage.getText().toString(); this.conversation.setNextMessage(msg); - updateChatState(this.conversation,msg); + updateChatState(this.conversation, msg); } } @@ -586,7 +604,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa final String msg = mEditMessage.getText().toString(); this.conversation.setNextMessage(msg); if (this.conversation != conversation) { - updateChatState(this.conversation,msg); + updateChatState(this.conversation, msg); } this.conversation.trim(); } @@ -632,7 +650,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa @Override public void onClick(View v) { - final Contact contact = conversation == null ? null :conversation.getContact(); + final Contact contact = conversation == null ? null : conversation.getContact(); if (contact != null) { activity.xmppConnectionService.createContact(contact); activity.switchToContactDetails(contact); @@ -655,7 +673,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa intent.setAction(VerifyOTRActivity.ACTION_VERIFY_CONTACT); intent.putExtra("contact", conversation.getContact().getJid().toBareJid().toString()); intent.putExtra("account", conversation.getAccount().getJid().toBareJid().toString()); - intent.putExtra("mode",VerifyOTRActivity.MODE_ANSWER_QUESTION); + intent.putExtra("mode", VerifyOTRActivity.MODE_ANSWER_QUESTION); startActivity(intent); } }; @@ -665,11 +683,11 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa final Contact contact = conversation.getContact(); final int mode = conversation.getMode(); if (conversation.isBlocked()) { - showSnackbar(R.string.contact_blocked, R.string.unblock,this.mUnblockClickListener); + showSnackbar(R.string.contact_blocked, R.string.unblock, this.mUnblockClickListener); } else if (!contact.showInRoster() && contact.getOption(Contact.Options.PENDING_SUBSCRIPTION_REQUEST)) { - showSnackbar(R.string.contact_added_you, R.string.add_back,this.mAddBackClickListener); + showSnackbar(R.string.contact_added_you, R.string.add_back, this.mAddBackClickListener); } else if (mode == Conversation.MODE_MULTI - &&!conversation.getMucOptions().online() + && !conversation.getMucOptions().online() && account.getStatus() == Account.State.ONLINE) { switch (conversation.getMucOptions().getError()) { case MucOptions.ERROR_NICK_IN_USE: @@ -693,18 +711,18 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa default: break; } - } else if (askForPassphraseIntent != null ) { - showSnackbar(R.string.openpgp_messages_found,R.string.decrypt, clickToDecryptListener); + } else if (askForPassphraseIntent != null) { + showSnackbar(R.string.openpgp_messages_found, R.string.decrypt, clickToDecryptListener); } else if (mode == Conversation.MODE_SINGLE && conversation.smpRequested()) { - showSnackbar(R.string.smp_requested, R.string.verify,this.mAnswerSmpClickListener); + showSnackbar(R.string.smp_requested, R.string.verify, this.mAnswerSmpClickListener); } else if (mode == Conversation.MODE_SINGLE - &&conversation.hasValidOtrSession() + && conversation.hasValidOtrSession() && (conversation.getOtrSession().getSessionStatus() == SessionStatus.ENCRYPTED) && (!conversation.isOtrFingerprintVerified())) { showSnackbar(R.string.unknown_otr_fingerprint, R.string.verify, clickToVerify); } else if (conversation.isMuted()) { - showSnackbar(R.string.notifications_disabled, R.string.enable,this.mUnmuteClickListener); + showSnackbar(R.string.notifications_disabled, R.string.enable, this.mUnmuteClickListener); } else { hideSnackbar(); } @@ -722,12 +740,12 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa for (final Message message : this.messageList) { if (message.getEncryption() == Message.ENCRYPTION_PGP && (message.getStatus() == Message.STATUS_RECEIVED || message - .getStatus() >= Message.STATUS_SEND) + .getStatus() >= Message.STATUS_SEND) && message.getDownloadable() == null) { if (!mEncryptedMessages.contains(message)) { mEncryptedMessages.add(message); } - } + } } decryptNext(); updateStatusMessages(); @@ -790,53 +808,108 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa updateChatMsgHint(); } - public void updateSendButton() { - Conversation c = this.conversation; - if (activity.useSendButtonToIndicateStatus() && c != null - && c.getAccount().getStatus() == Account.State.ONLINE) { - if (c.getMode() == Conversation.MODE_SINGLE) { - switch (c.getContact().getMostAvailableStatus()) { + enum SendButtonAction {TEXT, TAKE_PHOTO, SEND_LOCATION, RECORD_VOICE} + + private int getSendButtonImageResource(SendButtonAction action, int status) { + switch (action) { + case TEXT: + switch (status) { case Presences.CHAT: - this.mSendButton - .setImageResource(R.drawable.ic_action_send_now_online); - break; case Presences.ONLINE: - this.mSendButton - .setImageResource(R.drawable.ic_action_send_now_online); - break; + return R.drawable.ic_send_text_online; case Presences.AWAY: - this.mSendButton - .setImageResource(R.drawable.ic_action_send_now_away); - break; + return R.drawable.ic_send_text_away; case Presences.XA: - this.mSendButton - .setImageResource(R.drawable.ic_action_send_now_away); - break; case Presences.DND: - this.mSendButton - .setImageResource(R.drawable.ic_action_send_now_dnd); + return R.drawable.ic_send_text_dnd; + default: + return R.drawable.ic_send_text_offline; + } + case TAKE_PHOTO: + switch (status) { + case Presences.CHAT: + case Presences.ONLINE: + return R.drawable.ic_send_photo_online; + case Presences.AWAY: + return R.drawable.ic_send_photo_away; + case Presences.XA: + case Presences.DND: + return R.drawable.ic_send_photo_dnd; + default: + return R.drawable.ic_send_photo_offline; + } + case RECORD_VOICE: + switch (status) { + case Presences.CHAT: + case Presences.ONLINE: + return R.drawable.ic_send_voice_online; + case Presences.AWAY: + return R.drawable.ic_send_voice_away; + case Presences.XA: + case Presences.DND: + return R.drawable.ic_send_voice_dnd; + default: + return R.drawable.ic_send_voice_offline; + } + case SEND_LOCATION: + switch (status) { + case Presences.CHAT: + case Presences.ONLINE: + return R.drawable.ic_send_location_online; + case Presences.AWAY: + return R.drawable.ic_send_location_away; + case Presences.XA: + case Presences.DND: + return R.drawable.ic_send_location_dnd; + default: + return R.drawable.ic_send_location_offline; + } + } + return R.drawable.ic_send_text_offline; + } + + public void updateSendButton() { + final Conversation c = this.conversation; + final SendButtonAction action; + final int status; + if (c.getMode() == Conversation.MODE_MULTI) { + action = SendButtonAction.TEXT; + } else { + if (this.mEditMessage == null || this.mEditMessage.getText().length() == 0) { + String setting = activity.getPreferences().getString("quick_action","recent"); + if (setting.equals("recent")) { + setting = activity.getPreferences().getString("recently_used_quick_action","text"); + } + switch (setting) { + case "photo": + action = SendButtonAction.TAKE_PHOTO; + break; + case "location": + action = SendButtonAction.SEND_LOCATION; + break; + case "voice": + action = SendButtonAction.RECORD_VOICE; break; default: - this.mSendButton - .setImageResource(R.drawable.ic_action_send_now_offline); + action = SendButtonAction.TEXT; break; } - } else if (c.getMode() == Conversation.MODE_MULTI) { - if (c.getMucOptions().online()) { - this.mSendButton - .setImageResource(R.drawable.ic_action_send_now_online); - } else { - this.mSendButton - .setImageResource(R.drawable.ic_action_send_now_offline); - } } else { - this.mSendButton - .setImageResource(R.drawable.ic_action_send_now_offline); + action = SendButtonAction.TEXT; + } + } + if (activity.useSendButtonToIndicateStatus() && c != null + && c.getAccount().getStatus() == Account.State.ONLINE) { + if (c.getMode() == Conversation.MODE_SINGLE) { + status = c.getContact().getMostAvailableStatus(); + } else { + status = c.getMucOptions().online() ? Presences.ONLINE : Presences.OFFLINE; } } else { - this.mSendButton - .setImageResource(R.drawable.ic_action_send_now_offline); + status = Presences.OFFLINE; } + this.mSendButton.setTag(action); + this.mSendButton.setImageResource(getSendButtonImageResource(action, status)); } protected void updateStatusMessages() { @@ -865,7 +938,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa } protected void showSnackbar(final int message, final int action, - final OnClickListener clickListener) { + final OnClickListener clickListener) { snackbar.setVisibility(View.VISIBLE); snackbar.setOnClickListener(null); snackbarMessage.setText(message); @@ -897,7 +970,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa @Override public void userInputRequried(PendingIntent pi, - Contact contact) { + Contact contact) { activity.runIntent( pi, ConversationActivity.REQUEST_ENCRYPT_MESSAGE); @@ -921,11 +994,11 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa @Override public void onClick(DialogInterface dialog, - int which) { + int which) { conversation - .setNextEncryption(Message.ENCRYPTION_NONE); + .setNextEncryption(Message.ENCRYPTION_NONE); xmppService.databaseBackend - .updateConversation(conversation); + .updateConversation(conversation); message.setEncryption(Message.ENCRYPTION_NONE); xmppService.sendMessage(message); messageSent(); @@ -936,9 +1009,9 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa if (conversation.getMucOptions().pgpKeysInUse()) { if (!conversation.getMucOptions().everybodyHasKeys()) { Toast warning = Toast - .makeText(getActivity(), - R.string.missing_public_keys, - Toast.LENGTH_LONG); + .makeText(getActivity(), + R.string.missing_public_keys, + Toast.LENGTH_LONG); warning.setGravity(Gravity.CENTER_VERTICAL, 0, 0); warning.show(); } @@ -950,12 +1023,12 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa @Override public void onClick(DialogInterface dialog, - int which) { + int which) { conversation - .setNextEncryption(Message.ENCRYPTION_NONE); + .setNextEncryption(Message.ENCRYPTION_NONE); message.setEncryption(Message.ENCRYPTION_NONE); xmppService.databaseBackend - .updateConversation(conversation); + .updateConversation(conversation); xmppService.sendMessage(message); messageSent(); } @@ -968,7 +1041,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa } public void showNoPGPKeyDialog(boolean plural, - DialogInterface.OnClickListener listener) { + DialogInterface.OnClickListener listener) { AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); builder.setIconAttribute(android.R.attr.alertDialogIcon); if (plural) { @@ -1026,6 +1099,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa if (status == Account.State.ONLINE && conversation.setOutgoingChatState(ChatState.COMPOSING)) { activity.xmppConnectionService.sendChatState(conversation); } + updateSendButton(); } @Override @@ -1042,6 +1116,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa if (status == Account.State.ONLINE && conversation.setOutgoingChatState(Config.DEFAULT_CHATSTATE)) { activity.xmppConnectionService.sendChatState(conversation); } + updateSendButton(); } } -- cgit v1.2.3 From c4bfffe6a9027d041cccf610b448cb6c1367c83d Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Sat, 2 May 2015 12:10:56 +0200 Subject: mark account with incompatible server when no sasl mechansim could be found --- .../siacs/conversations/xmpp/XmppConnection.java | 43 ++++++++++++---------- 1 file changed, 24 insertions(+), 19 deletions(-) (limited to 'src/main/java/eu/siacs') diff --git a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java index 0b6bb15b7..a2b58a14f 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java @@ -581,26 +581,31 @@ public class XmppConnection implements Runnable { } else if (mechanisms.contains("DIGEST-MD5")) { saslMechanism = new DigestMd5(tagWriter, account, mXmppConnectionService.getRNG()); } - final JSONObject keys = account.getKeys(); - try { - if (keys.has(Account.PINNED_MECHANISM_KEY) && - keys.getInt(Account.PINNED_MECHANISM_KEY) > saslMechanism.getPriority() ) { - Log.e(Config.LOGTAG, "Auth failed. Authentication mechanism " + saslMechanism.getMechanism() + - " has lower priority (" + String.valueOf(saslMechanism.getPriority()) + - ") than pinned priority (" + keys.getInt(Account.PINNED_MECHANISM_KEY) + - "). Possible downgrade attack?"); - disconnect(true); - changeStatus(Account.State.SECURITY_ERROR); - } - } catch (final JSONException e) { - Log.d(Config.LOGTAG, "Parse error while checking pinned auth mechanism"); - } - Log.d(Config.LOGTAG,account.getJid().toString()+": Authenticating with " + saslMechanism.getMechanism()); - auth.setAttribute("mechanism", saslMechanism.getMechanism()); - if (!saslMechanism.getClientFirstMessage().isEmpty()) { - auth.setContent(saslMechanism.getClientFirstMessage()); + if (saslMechanism != null) { + final JSONObject keys = account.getKeys(); + try { + if (keys.has(Account.PINNED_MECHANISM_KEY) && + keys.getInt(Account.PINNED_MECHANISM_KEY) > saslMechanism.getPriority()) { + Log.e(Config.LOGTAG, "Auth failed. Authentication mechanism " + saslMechanism.getMechanism() + + " has lower priority (" + String.valueOf(saslMechanism.getPriority()) + + ") than pinned priority (" + keys.getInt(Account.PINNED_MECHANISM_KEY) + + "). Possible downgrade attack?"); + disconnect(true); + changeStatus(Account.State.SECURITY_ERROR); + } + } catch (final JSONException e) { + Log.d(Config.LOGTAG, "Parse error while checking pinned auth mechanism"); + } + Log.d(Config.LOGTAG, account.getJid().toString() + ": Authenticating with " + saslMechanism.getMechanism()); + auth.setAttribute("mechanism", saslMechanism.getMechanism()); + if (!saslMechanism.getClientFirstMessage().isEmpty()) { + auth.setContent(saslMechanism.getClientFirstMessage()); + } + tagWriter.writeElement(auth); + } else { + disconnect(true); + changeStatus(Account.State.INCOMPATIBLE_SERVER); } - tagWriter.writeElement(auth); } else if (this.streamFeatures.hasChild("sm", "urn:xmpp:sm:" + smVersion) && streamId != null) { -- cgit v1.2.3 From 43db9cdf4b300183cfd58ad9c7b3ad57ee63ad31 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Sun, 3 May 2015 09:30:30 +0200 Subject: turn send button in cancel button while in whisper mode --- .../conversations/ui/ConversationFragment.java | 42 +++++++++++++++------- 1 file changed, 30 insertions(+), 12 deletions(-) (limited to 'src/main/java/eu/siacs') diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java index 37ae00a30..6b11d3109 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java @@ -245,6 +245,13 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa case RECORD_VOICE: activity.attachFile(ConversationActivity.ATTACHMENT_CHOICE_RECORD_VOICE); break; + case CANCEL: + if (conversation != null && conversation.getMode() == Conversation.MODE_MULTI) { + conversation.setNextCounterpart(null); + updateChatMsgHint(); + updateSendButton(); + } + break; default: sendMessage(); } @@ -257,8 +264,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa @Override public void onClick(View v) { - Intent intent = new Intent(getActivity(), - ConferenceDetailsActivity.class); + Intent intent = new Intent(getActivity(), ConferenceDetailsActivity.class); intent.setAction(ConferenceDetailsActivity.ACTION_VIEW_MUC); intent.putExtra("uuid", conversation.getUuid()); startActivity(intent); @@ -271,13 +277,6 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa if (this.conversation == null) { return; } - if (mEditMessage.getText().length() < 1) { - if (this.conversation.getMode() == Conversation.MODE_MULTI) { - conversation.setNextCounterpart(null); - updateChatMsgHint(); - } - return; - } Message message = new Message(conversation, mEditMessage.getText() .toString(), conversation.getNextEncryption(activity .forceEncryption())); @@ -558,6 +557,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa this.mEditMessage.setText(""); this.conversation.setNextCounterpart(counterpart); updateChatMsgHint(); + updateSendButton(); } protected void highlightInConference(String nick) { @@ -808,7 +808,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa updateChatMsgHint(); } - enum SendButtonAction {TEXT, TAKE_PHOTO, SEND_LOCATION, RECORD_VOICE} + enum SendButtonAction {TEXT, TAKE_PHOTO, SEND_LOCATION, RECORD_VOICE, CANCEL} private int getSendButtonImageResource(SendButtonAction action, int status) { switch (action) { @@ -864,6 +864,19 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa default: return R.drawable.ic_send_location_offline; } + case CANCEL: + switch (status) { + case Presences.CHAT: + case Presences.ONLINE: + return R.drawable.ic_send_cancel_online; + case Presences.AWAY: + return R.drawable.ic_send_cancel_away; + case Presences.XA: + case Presences.DND: + return R.drawable.ic_send_cancel_dnd; + default: + return R.drawable.ic_send_cancel_offline; + } } return R.drawable.ic_send_text_offline; } @@ -872,10 +885,15 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa final Conversation c = this.conversation; final SendButtonAction action; final int status; + final boolean empty = this.mEditMessage == null || this.mEditMessage.getText().length() == 0; if (c.getMode() == Conversation.MODE_MULTI) { - action = SendButtonAction.TEXT; + if (empty && c.getNextCounterpart() != null) { + action = SendButtonAction.CANCEL; + } else { + action = SendButtonAction.TEXT; + } } else { - if (this.mEditMessage == null || this.mEditMessage.getText().length() == 0) { + if (empty) { String setting = activity.getPreferences().getString("quick_action","recent"); if (setting.equals("recent")) { setting = activity.getPreferences().getString("recently_used_quick_action","text"); -- cgit v1.2.3 From d15da64c5df63584d55a994d568345059a1f1c20 Mon Sep 17 00:00:00 2001 From: Alexander Groshev Date: Sun, 3 May 2015 20:53:27 +0300 Subject: Fix typos in URL to the project --- src/main/java/eu/siacs/conversations/generator/PresenceGenerator.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/main/java/eu/siacs') diff --git a/src/main/java/eu/siacs/conversations/generator/PresenceGenerator.java b/src/main/java/eu/siacs/conversations/generator/PresenceGenerator.java index 526005f33..c40c6d051 100644 --- a/src/main/java/eu/siacs/conversations/generator/PresenceGenerator.java +++ b/src/main/java/eu/siacs/conversations/generator/PresenceGenerator.java @@ -49,7 +49,7 @@ public class PresenceGenerator extends AbstractGenerator { Element cap = packet.addChild("c", "http://jabber.org/protocol/caps"); cap.setAttribute("hash", "sha-1"); - cap.setAttribute("node", "http://conversions.im"); + cap.setAttribute("node", "http://conversations.im"); cap.setAttribute("ver", capHash); } return packet; @@ -61,4 +61,4 @@ public class PresenceGenerator extends AbstractGenerator { packet.setAttribute("type","unavailable"); return packet; } -} \ No newline at end of file +} -- cgit v1.2.3 From 2582ece2105f98a7a20d72d8c8dc70772a48286f Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Mon, 4 May 2015 04:38:12 +0200 Subject: open market if share location plugin isn't installed --- .../eu/siacs/conversations/ui/ConversationActivity.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'src/main/java/eu/siacs') diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java index a76efbc35..349d8ffe8 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java @@ -409,6 +409,7 @@ public class ConversationActivity extends XmppActivity public void onPresenceSelected() { Intent intent = new Intent(); boolean chooser = false; + String fallbackPackageId = null; switch (attachmentChoice) { case ATTACHMENT_CHOICE_CHOOSE_IMAGE: intent.setAction(Intent.ACTION_GET_CONTENT); @@ -436,6 +437,7 @@ public class ConversationActivity extends XmppActivity break; case ATTACHMENT_CHOICE_LOCATION: intent.setAction("eu.siacs.conversations.location.request"); + fallbackPackageId = "eu.siacs.conversations.sharelocation"; break; } if (intent.resolveActivity(getPackageManager()) != null) { @@ -446,12 +448,25 @@ public class ConversationActivity extends XmppActivity } else { startActivityForResult(intent, attachmentChoice); } + } else if (fallbackPackageId != null) { + startActivity(getInstallApkIntent(fallbackPackageId)); } } }); } } + private Intent getInstallApkIntent(final String packageId) { + Intent intent = new Intent(Intent.ACTION_VIEW); + intent.setData(Uri.parse("market://details?id="+packageId)); + if (intent.resolveActivity(getPackageManager()) != null) { + return intent; + } else { + intent.setData(Uri.parse("http://play.google.com/store/apps/details?id="+packageId)); + return intent; + } + } + public void attachFile(final int attachmentChoice) { switch (attachmentChoice) { case ATTACHMENT_CHOICE_LOCATION: -- cgit v1.2.3 From 61fd5d669651042c553f9782492d7d2c4035a54f Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Mon, 4 May 2015 09:54:10 +0200 Subject: clean up in attachment chooser code. fixed #1168 --- .../conversations/ui/ConversationActivity.java | 102 ++++++++++----------- 1 file changed, 51 insertions(+), 51 deletions(-) (limited to 'src/main/java/eu/siacs') diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java index 349d8ffe8..b11ff0024 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java @@ -398,61 +398,61 @@ public class ConversationActivity extends XmppActivity } private void selectPresenceToAttachFile(final int attachmentChoice, final int encryption) { - if (attachmentChoice == ATTACHMENT_CHOICE_LOCATION && encryption != Message.ENCRYPTION_OTR) { - getSelectedConversation().setNextCounterpart(null); - Intent intent = new Intent("eu.siacs.conversations.location.request"); - startActivityForResult(intent,attachmentChoice); - } else { - selectPresence(getSelectedConversation(), new OnPresenceSelected() { + final OnPresenceSelected callback = new OnPresenceSelected() { - @Override - public void onPresenceSelected() { - Intent intent = new Intent(); - boolean chooser = false; - String fallbackPackageId = null; - switch (attachmentChoice) { - case ATTACHMENT_CHOICE_CHOOSE_IMAGE: - intent.setAction(Intent.ACTION_GET_CONTENT); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { - intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE,true); - } - intent.setType("image/*"); - chooser = true; - break; - case ATTACHMENT_CHOICE_TAKE_PHOTO: - Uri uri = xmppConnectionService.getFileBackend().getTakePhotoUri(); - intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE); - intent.putExtra(MediaStore.EXTRA_OUTPUT, uri); - mPendingImageUris.clear(); - mPendingImageUris.add(uri); - break; - case ATTACHMENT_CHOICE_CHOOSE_FILE: - chooser = true; - intent.setType("*/*"); - intent.addCategory(Intent.CATEGORY_OPENABLE); - intent.setAction(Intent.ACTION_GET_CONTENT); - break; - case ATTACHMENT_CHOICE_RECORD_VOICE: - intent.setAction(MediaStore.Audio.Media.RECORD_SOUND_ACTION); - break; - case ATTACHMENT_CHOICE_LOCATION: - intent.setAction("eu.siacs.conversations.location.request"); - fallbackPackageId = "eu.siacs.conversations.sharelocation"; - break; - } - if (intent.resolveActivity(getPackageManager()) != null) { - if (chooser) { - startActivityForResult( - Intent.createChooser(intent, getString(R.string.perform_action_with)), - attachmentChoice); - } else { - startActivityForResult(intent, attachmentChoice); + @Override + public void onPresenceSelected() { + Intent intent = new Intent(); + boolean chooser = false; + String fallbackPackageId = null; + switch (attachmentChoice) { + case ATTACHMENT_CHOICE_CHOOSE_IMAGE: + intent.setAction(Intent.ACTION_GET_CONTENT); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { + intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE,true); } - } else if (fallbackPackageId != null) { - startActivity(getInstallApkIntent(fallbackPackageId)); + intent.setType("image/*"); + chooser = true; + break; + case ATTACHMENT_CHOICE_TAKE_PHOTO: + Uri uri = xmppConnectionService.getFileBackend().getTakePhotoUri(); + intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE); + intent.putExtra(MediaStore.EXTRA_OUTPUT, uri); + mPendingImageUris.clear(); + mPendingImageUris.add(uri); + break; + case ATTACHMENT_CHOICE_CHOOSE_FILE: + chooser = true; + intent.setType("*/*"); + intent.addCategory(Intent.CATEGORY_OPENABLE); + intent.setAction(Intent.ACTION_GET_CONTENT); + break; + case ATTACHMENT_CHOICE_RECORD_VOICE: + intent.setAction(MediaStore.Audio.Media.RECORD_SOUND_ACTION); + break; + case ATTACHMENT_CHOICE_LOCATION: + intent.setAction("eu.siacs.conversations.location.request"); + fallbackPackageId = "eu.siacs.conversations.sharelocation"; + break; + } + if (intent.resolveActivity(getPackageManager()) != null) { + if (chooser) { + startActivityForResult( + Intent.createChooser(intent, getString(R.string.perform_action_with)), + attachmentChoice); + } else { + startActivityForResult(intent, attachmentChoice); } + } else if (fallbackPackageId != null) { + startActivity(getInstallApkIntent(fallbackPackageId)); } - }); + } + }; + if (attachmentChoice == ATTACHMENT_CHOICE_LOCATION && encryption != Message.ENCRYPTION_OTR) { + getSelectedConversation().setNextCounterpart(null); + callback.onPresenceSelected(); + } else { + selectPresence(getSelectedConversation(),callback); } } -- cgit v1.2.3 From e6aa604aded25c304816164624b94bb8abe3d69f Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Tue, 5 May 2015 06:10:47 +0200 Subject: enabled sm logging by default at least for development branch --- src/main/java/eu/siacs/conversations/Config.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/main/java/eu/siacs') diff --git a/src/main/java/eu/siacs/conversations/Config.java b/src/main/java/eu/siacs/conversations/Config.java index 5cca6c0b7..5bf320a11 100644 --- a/src/main/java/eu/siacs/conversations/Config.java +++ b/src/main/java/eu/siacs/conversations/Config.java @@ -28,7 +28,7 @@ public final class Config { public static final boolean NO_PROXY_LOOKUP = false; //useful to debug ibb public static final boolean DISABLE_STRING_PREP = false; // setting to true might increase startup performance - public static final boolean EXTENDED_SM_LOGGING = false; // log stanza counts + public static final boolean EXTENDED_SM_LOGGING = true; // log stanza counts public static final long MILLISECONDS_IN_DAY = 24 * 60 * 60 * 1000; public static final long MAM_MAX_CATCHUP = MILLISECONDS_IN_DAY / 2; -- cgit v1.2.3 From 5136bf9832b9a7aeb59926b42fe6a6632452c1ef Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Tue, 5 May 2015 06:17:34 +0200 Subject: r/o support for vcard avatars. pep avatars will be prefered --- .../eu/siacs/conversations/entities/Contact.java | 26 ++++++++--- .../siacs/conversations/generator/IqGenerator.java | 9 +++- .../siacs/conversations/parser/MessageParser.java | 2 +- .../siacs/conversations/parser/PresenceParser.java | 15 ++++++ .../services/XmppConnectionService.java | 53 ++++++++++++++++++---- .../eu/siacs/conversations/xmpp/pep/Avatar.java | 50 ++++++++++++++++---- 6 files changed, 127 insertions(+), 28 deletions(-) (limited to 'src/main/java/eu/siacs') diff --git a/src/main/java/eu/siacs/conversations/entities/Contact.java b/src/main/java/eu/siacs/conversations/entities/Contact.java index cef03ebe4..4ad105b1d 100644 --- a/src/main/java/eu/siacs/conversations/entities/Contact.java +++ b/src/main/java/eu/siacs/conversations/entities/Contact.java @@ -15,6 +15,7 @@ import eu.siacs.conversations.utils.UIHelper; import eu.siacs.conversations.xml.Element; import eu.siacs.conversations.xmpp.jid.InvalidJidException; import eu.siacs.conversations.xmpp.jid.Jid; +import eu.siacs.conversations.xmpp.pep.Avatar; public class Contact implements ListItem, Blockable { public static final String TABLENAME = "contacts"; @@ -40,11 +41,11 @@ public class Contact implements ListItem, Blockable { protected int subscription = 0; protected String systemAccount; protected String photoUri; - protected String avatar; protected JSONObject keys = new JSONObject(); protected JSONArray groups = new JSONArray(); protected Presences presences = new Presences(); protected Account account; + protected Avatar avatar; public Contact(final String account, final String systemName, final String serverName, final Jid jid, final int subscription, final String photoUri, @@ -61,7 +62,11 @@ public class Contact implements ListItem, Blockable { } catch (JSONException e) { this.keys = new JSONObject(); } - this.avatar = avatar; + if (avatar != null) { + this.avatar = new Avatar(); + this.avatar.sha1sum = avatar; + this.avatar.origin = Avatar.Origin.VCARD; //always assume worst + } try { this.groups = (groups == null ? new JSONArray() : new JSONArray(groups)); } catch (JSONException e) { @@ -187,7 +192,7 @@ public class Contact implements ListItem, Blockable { values.put(SYSTEMACCOUNT, systemAccount); values.put(PHOTOURI, photoUri); values.put(KEYS, keys.toString()); - values.put(AVATAR, avatar); + values.put(AVATAR, avatar == null ? null : avatar.getFilename()); values.put(LAST_PRESENCE, lastseen.presence); values.put(LAST_TIME, lastseen.time); values.put(GROUPS, groups.toString()); @@ -411,17 +416,20 @@ public class Contact implements ListItem, Blockable { return getJid().toDomainJid(); } - public boolean setAvatar(String filename) { - if (this.avatar != null && this.avatar.equals(filename)) { + public boolean setAvatar(Avatar avatar) { + if (this.avatar != null && this.avatar.equals(avatar)) { return false; } else { - this.avatar = filename; + if (this.avatar != null && this.avatar.origin == Avatar.Origin.PEP && avatar.origin == Avatar.Origin.VCARD) { + return false; + } + this.avatar = avatar; return true; } } public String getAvatar() { - return this.avatar; + return avatar == null ? null : avatar.getFilename(); } public boolean deleteOtrFingerprint(String fingerprint) { @@ -478,6 +486,10 @@ public class Contact implements ListItem, Blockable { } } + public boolean isSelf() { + return account.getJid().toBareJid().equals(getJid().toBareJid()); + } + public static class Lastseen { public long time; public String presence; diff --git a/src/main/java/eu/siacs/conversations/generator/IqGenerator.java b/src/main/java/eu/siacs/conversations/generator/IqGenerator.java index 6bc629b58..d7366daa8 100644 --- a/src/main/java/eu/siacs/conversations/generator/IqGenerator.java +++ b/src/main/java/eu/siacs/conversations/generator/IqGenerator.java @@ -91,7 +91,7 @@ public class IqGenerator extends AbstractGenerator { return publish("urn:xmpp:avatar:metadata", item); } - public IqPacket retrieveAvatar(final Avatar avatar) { + public IqPacket retrievePepAvatar(final Avatar avatar) { final Element item = new Element("item"); item.setAttribute("id", avatar.sha1sum); final IqPacket packet = retrieve("urn:xmpp:avatar:data", item); @@ -99,6 +99,13 @@ public class IqGenerator extends AbstractGenerator { return packet; } + public IqPacket retrieveVcardAvatar(final Avatar avatar) { + final IqPacket packet = new IqPacket(IqPacket.TYPE.GET); + packet.setTo(avatar.owner); + packet.addChild("vCard","vcard-temp"); + return packet; + } + public IqPacket retrieveAvatarMetaData(final Jid to) { final IqPacket packet = retrieve("urn:xmpp:avatar:metadata", null); if (to != null) { diff --git a/src/main/java/eu/siacs/conversations/parser/MessageParser.java b/src/main/java/eu/siacs/conversations/parser/MessageParser.java index 76d014688..7870fdbff 100644 --- a/src/main/java/eu/siacs/conversations/parser/MessageParser.java +++ b/src/main/java/eu/siacs/conversations/parser/MessageParser.java @@ -494,7 +494,7 @@ public class MessageParser extends AbstractParser implements } else { Contact contact = account.getRoster().getContact( from); - contact.setAvatar(avatar.getFilename()); + contact.setAvatar(avatar); mXmppConnectionService.getAvatarService().clear( contact); mXmppConnectionService.updateConversationUi(); diff --git a/src/main/java/eu/siacs/conversations/parser/PresenceParser.java b/src/main/java/eu/siacs/conversations/parser/PresenceParser.java index 7505b091b..f7872210d 100644 --- a/src/main/java/eu/siacs/conversations/parser/PresenceParser.java +++ b/src/main/java/eu/siacs/conversations/parser/PresenceParser.java @@ -13,6 +13,7 @@ import eu.siacs.conversations.services.XmppConnectionService; import eu.siacs.conversations.xml.Element; import eu.siacs.conversations.xmpp.OnPresencePacketReceived; import eu.siacs.conversations.xmpp.jid.Jid; +import eu.siacs.conversations.xmpp.pep.Avatar; import eu.siacs.conversations.xmpp.stanzas.PresencePacket; public class PresenceParser extends AbstractParser implements @@ -101,6 +102,20 @@ public class PresenceParser extends AbstractParser implements if (nick != null) { contact.setPresenceName(nick.getContent()); } + Element x = packet.findChild("x","vcard-temp:x:update"); + Avatar avatar = Avatar.parsePresence(x); + if (avatar != null && !contact.isSelf()) { + avatar.owner = from.toBareJid(); + if (mXmppConnectionService.getFileBackend().isAvatarCached(avatar)) { + if (contact.setAvatar(avatar)) { + mXmppConnectionService.getAvatarService().clear(contact); + mXmppConnectionService.updateConversationUi(); + mXmppConnectionService.updateRosterUi(); + } + } else { + mXmppConnectionService.fetchAvatar(account,avatar); + } + } mXmppConnectionService.updateRosterUi(); } diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index ec0b3f928..9cee3538b 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -1893,9 +1893,19 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa fetchAvatar(account, avatar, null); } - public void fetchAvatar(Account account, final Avatar avatar, - final UiCallback callback) { - IqPacket packet = this.mIqGenerator.retrieveAvatar(avatar); + public void fetchAvatar(Account account, final Avatar avatar, final UiCallback callback) { + switch (avatar.origin) { + case PEP: + fetchAvatarPep(account,avatar,callback); + break; + case VCARD: + fetchAvatarVcard(account, avatar, callback); + break; + } + } + + private void fetchAvatarPep(Account account, final Avatar avatar, final UiCallback callback) { + IqPacket packet = this.mIqGenerator.retrievePepAvatar(avatar); sendIqPacket(account, packet, new OnIqPacketReceived() { @Override @@ -1916,7 +1926,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa } else { Contact contact = account.getRoster() .getContact(avatar.owner); - contact.setAvatar(avatar.getFilename()); + contact.setAvatar(avatar); getAvatarService().clear(contact); updateConversationUi(); updateRosterUi(); @@ -1925,8 +1935,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa callback.success(avatar); } Log.d(Config.LOGTAG, account.getJid().toBareJid() - + ": succesfully fetched avatar for " - + avatar.owner); + + ": succesfuly fetched pep avatar for " + avatar.owner); return; } } else { @@ -1949,8 +1958,34 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa }); } - public void checkForAvatar(Account account, - final UiCallback callback) { + private void fetchAvatarVcard(final Account account, final Avatar avatar, final UiCallback callback) { + IqPacket packet = this.mIqGenerator.retrieveVcardAvatar(avatar); + this.sendIqPacket(account,packet,new OnIqPacketReceived() { + @Override + public void onIqPacketReceived(Account account, IqPacket packet) { + if (packet.getType() == IqPacket.TYPE.RESULT) { + Element vCard = packet.findChild("vCard","vcard-temp"); + Element photo = vCard != null ? vCard.findChild("PHOTO") : null; + Element binval = photo != null ? photo.findChild("BINVAL") : null; + if (binval != null) { + avatar.image = binval.getContent(); + if (getFileBackend().save(avatar)) { + Log.d(Config.LOGTAG, account.getJid().toBareJid() + + ": successfully fetched vCard avatar for " + avatar.owner); + Contact contact = account.getRoster() + .getContact(avatar.owner); + contact.setAvatar(avatar); + getAvatarService().clear(contact); + updateConversationUi(); + updateRosterUi(); + } + } + } + } + }); + } + + public void checkForAvatar(Account account, final UiCallback callback) { IqPacket packet = this.mIqGenerator.retrieveAvatarMetaData(null); this.sendIqPacket(account, packet, new OnIqPacketReceived() { @@ -1972,7 +2007,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa getAvatarService().clear(account); callback.success(avatar); } else { - fetchAvatar(account, avatar, callback); + fetchAvatarPep(account, avatar, callback); } return; } diff --git a/src/main/java/eu/siacs/conversations/xmpp/pep/Avatar.java b/src/main/java/eu/siacs/conversations/xmpp/pep/Avatar.java index 9f5ac988b..04d55bbe5 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/pep/Avatar.java +++ b/src/main/java/eu/siacs/conversations/xmpp/pep/Avatar.java @@ -6,6 +6,9 @@ import eu.siacs.conversations.xmpp.jid.Jid; import android.util.Base64; public class Avatar { + + public enum Origin { PEP, VCARD }; + public String type; public String sha1sum; public String image; @@ -13,21 +16,14 @@ public class Avatar { public int width; public long size; public Jid owner; + public Origin origin = Origin.PEP; //default to maintain compat public byte[] getImageAsBytes() { return Base64.decode(image, Base64.DEFAULT); } public String getFilename() { - if (type == null) { - return sha1sum; - } else if (type.equalsIgnoreCase("image/webp")) { - return sha1sum + ".webp"; - } else if (type.equalsIgnoreCase("image/png")) { - return sha1sum + ".png"; - } else { - return sha1sum; - } + return sha1sum; } public static Avatar parseMetadata(Element items) { @@ -64,10 +60,44 @@ public class Avatar { return null; } avatar.type = child.getAttribute("type"); - avatar.sha1sum = child.getAttribute("id"); + String hash = child.getAttribute("id"); + if (!isValidSHA1(hash)) { + return null; + } + avatar.sha1sum = hash; + avatar.origin = Origin.PEP; return avatar; } } return null; } + + @Override + public boolean equals(Object object) { + if (object != null && object instanceof Avatar) { + Avatar other = (Avatar) object; + return other.getFilename().equals(this.getFilename()); + } else { + return false; + } + } + + public static Avatar parsePresence(Element x) { + Element photo = x != null ? x.findChild("photo") : null; + String hash = photo != null ? photo.getContent() : null; + if (hash == null) { + return null; + } + if (!isValidSHA1(hash)) { + return null; + } + Avatar avatar = new Avatar(); + avatar.sha1sum = hash; + avatar.origin = Origin.VCARD; + return avatar; + } + + private static boolean isValidSHA1(String s) { + return s != null && s.matches("[a-fA-F0-9]{40}"); + } } -- cgit v1.2.3 From b7c672e10e974a5eee19fb50556851e1c8d4635b Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Tue, 5 May 2015 10:29:41 +0200 Subject: avoid fetching avatars multiple times in parallel --- .../services/XmppConnectionService.java | 47 ++++++++++++++++++---- 1 file changed, 39 insertions(+), 8 deletions(-) (limited to 'src/main/java/eu/siacs') diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index 9cee3538b..6b53b7588 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -41,6 +41,7 @@ import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.Hashtable; +import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; @@ -210,6 +211,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa private HttpConnectionManager mHttpConnectionManager = new HttpConnectionManager( this); private AvatarService mAvatarService = new AvatarService(this); + private final List mInProgressAvatarFetches = new ArrayList<>(); private MessageArchiveService mMessageArchiveService = new MessageArchiveService(this); private OnConversationUpdate mOnConversationUpdate = null; private Integer convChangedListenerCount = 0; @@ -328,7 +330,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa message.setCounterpart(conversation.getNextCounterpart()); } if (encryption == Message.ENCRYPTION_DECRYPTED) { - getPgpEngine().encrypt(message,callback); + getPgpEngine().encrypt(message, callback); } else { callback.success(message); } @@ -1893,14 +1895,27 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa fetchAvatar(account, avatar, null); } + private static String generateFetchKey(Account account, final Avatar avatar) { + return account.getJid().toBareJid()+"_"+avatar.owner+"_"+avatar.sha1sum; + } + public void fetchAvatar(Account account, final Avatar avatar, final UiCallback callback) { - switch (avatar.origin) { - case PEP: - fetchAvatarPep(account,avatar,callback); - break; - case VCARD: - fetchAvatarVcard(account, avatar, callback); - break; + final String KEY = generateFetchKey(account, avatar); + synchronized(this.mInProgressAvatarFetches) { + if (this.mInProgressAvatarFetches.contains(KEY)) { + return; + } else { + switch (avatar.origin) { + case PEP: + this.mInProgressAvatarFetches.add(KEY); + fetchAvatarPep(account, avatar, callback); + break; + case VCARD: + this.mInProgressAvatarFetches.add(KEY); + fetchAvatarVcard(account, avatar, callback); + break; + } + } } } @@ -1910,6 +1925,9 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa @Override public void onIqPacketReceived(Account account, IqPacket result) { + synchronized (mInProgressAvatarFetches) { + mInProgressAvatarFetches.remove(generateFetchKey(account, avatar)); + } final String ERROR = account.getJid().toBareJid() + ": fetching avatar for " + avatar.owner + " failed "; if (result.getType() == IqPacket.TYPE.RESULT) { @@ -1963,6 +1981,9 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa this.sendIqPacket(account,packet,new OnIqPacketReceived() { @Override public void onIqPacketReceived(Account account, IqPacket packet) { + synchronized(mInProgressAvatarFetches) { + mInProgressAvatarFetches.remove(generateFetchKey(account,avatar)); + } if (packet.getType() == IqPacket.TYPE.RESULT) { Element vCard = packet.findChild("vCard","vcard-temp"); Element photo = vCard != null ? vCard.findChild("PHOTO") : null; @@ -2043,6 +2064,16 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa disconnect(account, force); } if (!account.isOptionSet(Account.OPTION_DISABLED)) { + + synchronized (this.mInProgressAvatarFetches) { + for(Iterator iterator = this.mInProgressAvatarFetches.iterator(); iterator.hasNext();) { + final String KEY = iterator.next(); + if (KEY.startsWith(account.getJid().toBareJid()+"_")) { + iterator.remove(); + } + } + } + if (account.getXmppConnection() == null) { account.setXmppConnection(createConnection(account)); } -- cgit v1.2.3 From db726a59b85146c583432bd9da58a34641356f0c Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Wed, 6 May 2015 04:29:45 +0200 Subject: fwiw don't allow stanza count to go over MAX_INT --- src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'src/main/java/eu/siacs') diff --git a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java index a2b58a14f..0af6045fa 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java @@ -437,6 +437,10 @@ public class XmppConnection implements Runnable { throw new IOException("interrupted mid tag"); } } + if (stanzasReceived == Integer.MAX_VALUE) { + resetStreamId(); + throw new IOException("time to restart the session. cant handle >2 billion pcks"); + } ++stanzasReceived; lastPacketReceived = SystemClock.elapsedRealtime(); return element; @@ -901,6 +905,11 @@ public class XmppConnection implements Runnable { } private synchronized void sendPacket(final AbstractStanza packet) { + if (stanzasSent == Integer.MAX_VALUE) { + resetStreamId(); + disconnect(true); + return; + } final String name = packet.getName(); if (name.equals("iq") || name.equals("message") || name.equals("presence")) { ++stanzasSent; -- cgit v1.2.3 From d74e8a8a0ea20258e9e0eefbea75f94b7559f9b7 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Wed, 6 May 2015 04:33:21 +0200 Subject: fixed npe when missing instructions on failed register --- .../java/eu/siacs/conversations/xmpp/XmppConnection.java | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'src/main/java/eu/siacs') diff --git a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java index 0af6045fa..0aa67da2c 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java @@ -647,10 +647,8 @@ public class XmppConnection implements Runnable { if (packet.query().hasChild("username") && (packet.query().hasChild("password"))) { final IqPacket register = new IqPacket(IqPacket.TYPE.SET); - final Element username = new Element("username") - .setContent(account.getUsername()); - final Element password = new Element("password") - .setContent(account.getPassword()); + final Element username = new Element("username").setContent(account.getUsername()); + final Element password = new Element("password").setContent(account.getPassword()); register.query("jabber:iq:register").addChild(username); register.query().addChild(password); sendIqPacket(register, new OnIqPacketReceived() { @@ -663,7 +661,7 @@ public class XmppConnection implements Runnable { changeStatus(Account.State.REGISTRATION_SUCCESSFUL); } else if (packet.hasChild("error") && (packet.findChild("error") - .hasChild("conflict"))) { + .hasChild("conflict"))) { changeStatus(Account.State.REGISTRATION_CONFLICT); } else { changeStatus(Account.State.REGISTRATION_FAILED); @@ -677,7 +675,7 @@ public class XmppConnection implements Runnable { disconnect(true); Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": could not register. instructions are" - + instructions.getContent()); + + instructions != null ? instructions.getContent() : ""); } } }); @@ -692,7 +690,7 @@ public class XmppConnection implements Runnable { } final IqPacket iq = new IqPacket(IqPacket.TYPE.SET); iq.addChild("bind", "urn:ietf:params:xml:ns:xmpp-bind") - .addChild("resource").setContent(account.getResource()); + .addChild("resource").setContent(account.getResource()); this.sendUnmodifiedIqPacket(iq, new OnIqPacketReceived() { @Override public void onIqPacketReceived(final Account account, final IqPacket packet) { -- cgit v1.2.3 From 05f0aa614f5af638c6d6da5a4c6a119e1ec6eda8 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Thu, 7 May 2015 11:07:15 +0200 Subject: fixed npe when binval value of vcard avatar is null --- .../java/eu/siacs/conversations/services/XmppConnectionService.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src/main/java/eu/siacs') diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index 6b53b7588..e58f760ed 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -1988,8 +1988,9 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa Element vCard = packet.findChild("vCard","vcard-temp"); Element photo = vCard != null ? vCard.findChild("PHOTO") : null; Element binval = photo != null ? photo.findChild("BINVAL") : null; - if (binval != null) { - avatar.image = binval.getContent(); + String image = binval != null ? binval.getContent() : null; + if (image != null) { + avatar.image = image; if (getFileBackend().save(avatar)) { Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": successfully fetched vCard avatar for " + avatar.owner); -- cgit v1.2.3 From e0653c03713efe0e4f2f5438b31d1417b059761b Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Thu, 7 May 2015 14:19:51 +0200 Subject: fixed encrypted ibb file transfer which was broken with ART. fixes #1172 --- .../xmpp/jingle/JingleConnection.java | 2 +- .../xmpp/jingle/JingleInbandTransport.java | 57 ++++++++++++---------- 2 files changed, 33 insertions(+), 26 deletions(-) (limited to 'src/main/java/eu/siacs') diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java index e448f9477..4847d5f12 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java @@ -99,7 +99,7 @@ public class JingleConnection implements Downloadable { file.delete(); } } - Log.d(Config.LOGTAG,"sucessfully transmitted file:" + file.getAbsolutePath()); + Log.d(Config.LOGTAG,"successfully transmitted file:" + file.getAbsolutePath()+" ("+file.getSha1Sum()+")"); if (message.getEncryption() != Message.ENCRYPTION_PGP) { Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE); intent.setData(Uri.fromFile(file)); diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleInbandTransport.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleInbandTransport.java index 9866af03d..4e039ad85 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleInbandTransport.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleInbandTransport.java @@ -8,7 +8,9 @@ import java.security.NoSuchAlgorithmException; import java.util.Arrays; import android.util.Base64; +import android.util.Log; +import eu.siacs.conversations.Config; import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.entities.DownloadableFile; import eu.siacs.conversations.persistance.FileBackend; @@ -110,7 +112,11 @@ public class JingleInbandTransport extends JingleTransport { this.onFileTransmissionStatusChanged = callback; this.file = file; try { - this.remainingSize = this.file.getSize(); + if (this.file.getKey() != null) { + this.remainingSize = (this.file.getSize() / 16 + 1) * 16; + } else { + this.remainingSize = this.file.getSize(); + } this.fileSize = this.remainingSize; this.digest = MessageDigest.getInstance("SHA-1"); this.digest.reset(); @@ -150,29 +156,33 @@ public class JingleInbandTransport extends JingleTransport { byte[] buffer = new byte[this.bufferSize]; try { int count = fileInputStream.read(buffer); - if (count == -1) { + this.remainingSize -= count; + if (count != buffer.length && count != -1) { + int rem = fileInputStream.read(buffer,count,buffer.length-count); + if (rem > 0) { + count += rem; + } + } + this.digest.update(buffer,0,count); + String base64 = Base64.encodeToString(buffer,0,count, Base64.NO_WRAP); + IqPacket iq = new IqPacket(IqPacket.TYPE.SET); + iq.setTo(this.counterpart); + Element data = iq.addChild("data", "http://jabber.org/protocol/ibb"); + data.setAttribute("seq", Integer.toString(this.seq)); + data.setAttribute("block-size", Integer.toString(this.blockSize)); + data.setAttribute("sid", this.sessionId); + data.setContent(base64); + this.account.getXmppConnection().sendIqPacket(iq, this.onAckReceived); + this.seq++; + if (this.remainingSize > 0) { + connection.updateProgress((int) ((((double) (this.fileSize - this.remainingSize)) / this.fileSize) * 100)); + } else { file.setSha1Sum(CryptoHelper.bytesToHex(digest.digest())); - fileInputStream.close(); this.onFileTransmissionStatusChanged.onFileTransmitted(file); - } else { - this.remainingSize -= count; - this.digest.update(buffer); - String base64 = Base64.encodeToString(buffer, Base64.NO_WRAP); - IqPacket iq = new IqPacket(IqPacket.TYPE.SET); - iq.setTo(this.counterpart); - Element data = iq.addChild("data", - "http://jabber.org/protocol/ibb"); - data.setAttribute("seq", Integer.toString(this.seq)); - data.setAttribute("block-size", - Integer.toString(this.blockSize)); - data.setAttribute("sid", this.sessionId); - data.setContent(base64); - this.account.getXmppConnection().sendIqPacket(iq, - this.onAckReceived); - this.seq++; - connection.updateProgress((int) ((((double) (this.fileSize - this.remainingSize)) / this.fileSize) * 100)); + fileInputStream.close(); } } catch (IOException e) { + Log.d(Config.LOGTAG,e.getMessage()); FileBackend.close(fileInputStream); this.onFileTransmissionStatusChanged.onFileTransferAborted(); } @@ -182,14 +192,10 @@ public class JingleInbandTransport extends JingleTransport { try { byte[] buffer = Base64.decode(data, Base64.NO_WRAP); if (this.remainingSize < buffer.length) { - buffer = Arrays - .copyOfRange(buffer, 0, (int) this.remainingSize); + buffer = Arrays.copyOfRange(buffer, 0, (int) this.remainingSize); } this.remainingSize -= buffer.length; - - this.fileOutputStream.write(buffer); - this.digest.update(buffer); if (this.remainingSize <= 0) { file.setSha1Sum(CryptoHelper.bytesToHex(digest.digest())); @@ -200,6 +206,7 @@ public class JingleInbandTransport extends JingleTransport { connection.updateProgress((int) ((((double) (this.fileSize - this.remainingSize)) / this.fileSize) * 100)); } } catch (IOException e) { + Log.d(Config.LOGTAG,e.getMessage()); FileBackend.close(fileOutputStream); this.onFileTransmissionStatusChanged.onFileTransferAborted(); } -- cgit v1.2.3 From c4a4dd239207d95647e50f3132277e2371078d0d Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Fri, 8 May 2015 06:30:06 +0200 Subject: throw proper exception before changing account into error state --- .../siacs/conversations/xmpp/XmppConnection.java | 42 ++++++++++++++++------ 1 file changed, 31 insertions(+), 11 deletions(-) (limited to 'src/main/java/eu/siacs') diff --git a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java index 0aa67da2c..6c67c0726 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java @@ -167,7 +167,7 @@ public class XmppConnection implements Runnable { try { String srvRecordServer; try { - srvRecordServer=IDN.toASCII(namePort.getString("name")); + srvRecordServer = IDN.toASCII(namePort.getString("name")); } catch (final IllegalArgumentException e) { // TODO: Handle me?` srvRecordServer = ""; @@ -224,6 +224,12 @@ public class XmppConnection implements Runnable { if (socket.isConnected()) { socket.close(); } + } catch (final IncompatibleServerException e) { + this.changeStatus(Account.State.INCOMPATIBLE_SERVER); + } catch (final SecurityException e) { + this.changeStatus(Account.State.SECURITY_ERROR); + } catch (final UnauthorizedException e) { + this.changeStatus(Account.State.UNAUTHORIZED); } catch (final UnknownHostException | ConnectException e) { this.changeStatus(Account.State.SERVER_NOT_FOUND); } catch (final IOException | XmlPullParserException | NoSuchAlgorithmException e) { @@ -231,6 +237,13 @@ public class XmppConnection implements Runnable { this.changeStatus(Account.State.OFFLINE); this.attempt--; //don't count attempt when reconnecting instantly anyway } finally { + if (socket != null) { + try { + socket.close(); + } catch (IOException e) { + + } + } if (wakeLock.isHeld()) { try { wakeLock.release(); @@ -279,8 +292,7 @@ public class XmppConnection implements Runnable { processStream(tagReader.readTag()); break; } else if (nextTag.isStart("failure")) { - tagReader.readElement(nextTag); - changeStatus(Account.State.UNAUTHORIZED); + throw new UnauthorizedException(); } else if (nextTag.isStart("challenge")) { final String challenge = tagReader.readElement(nextTag).getContent(); final Element response = new Element("response"); @@ -542,8 +554,7 @@ public class XmppConnection implements Runnable { if (!verifier.verify(account.getServer().getDomainpart(),sslSocket.getSession())) { Log.d(Config.LOGTAG,account.getJid().toBareJid()+": TLS certificate verification failed"); - disconnect(true); - changeStatus(Account.State.SECURITY_ERROR); + throw new SecurityException(); } tagReader.setInputStream(sslSocket.getInputStream()); tagWriter.setOutputStream(sslSocket.getOutputStream()); @@ -554,8 +565,7 @@ public class XmppConnection implements Runnable { sslSocket.close(); } catch (final NoSuchAlgorithmException | KeyManagementException e1) { Log.d(Config.LOGTAG,account.getJid().toBareJid()+": TLS certificate verification failed"); - disconnect(true); - changeStatus(Account.State.SECURITY_ERROR); + throw new SecurityException(); } } @@ -594,8 +604,7 @@ public class XmppConnection implements Runnable { " has lower priority (" + String.valueOf(saslMechanism.getPriority()) + ") than pinned priority (" + keys.getInt(Account.PINNED_MECHANISM_KEY) + "). Possible downgrade attack?"); - disconnect(true); - changeStatus(Account.State.SECURITY_ERROR); + throw new SecurityException(); } } catch (final JSONException e) { Log.d(Config.LOGTAG, "Parse error while checking pinned auth mechanism"); @@ -607,8 +616,7 @@ public class XmppConnection implements Runnable { } tagWriter.writeElement(auth); } else { - disconnect(true); - changeStatus(Account.State.INCOMPATIBLE_SERVER); + throw new IncompatibleServerException(); } } else if (this.streamFeatures.hasChild("sm", "urn:xmpp:sm:" + smVersion) @@ -1098,6 +1106,18 @@ public class XmppConnection implements Runnable { public final ArrayList> identities = new ArrayList<>(); } + private class UnauthorizedException extends IOException { + + } + + private class SecurityException extends IOException { + + } + + private class IncompatibleServerException extends IOException { + + } + public class Features { XmppConnection connection; private boolean carbonsEnabled = false; -- cgit v1.2.3 From d9e5035c084a5bf307d88fb4b69c585ffb5e859b Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Fri, 8 May 2015 06:50:28 +0200 Subject: config option to reset attempt counts when changing network (default=true) --- src/main/java/eu/siacs/conversations/Config.java | 1 + .../services/XmppConnectionService.java | 26 +++++++++++++++------- 2 files changed, 19 insertions(+), 8 deletions(-) (limited to 'src/main/java/eu/siacs') diff --git a/src/main/java/eu/siacs/conversations/Config.java b/src/main/java/eu/siacs/conversations/Config.java index 5bf320a11..9f5d14fde 100644 --- a/src/main/java/eu/siacs/conversations/Config.java +++ b/src/main/java/eu/siacs/conversations/Config.java @@ -29,6 +29,7 @@ public final class Config { public static final boolean NO_PROXY_LOOKUP = false; //useful to debug ibb public static final boolean DISABLE_STRING_PREP = false; // setting to true might increase startup performance public static final boolean EXTENDED_SM_LOGGING = true; // log stanza counts + public static final boolean RESET_ATTEMPT_COUNT_ON_NETWORK_CHANGE = true; //setting to true might increase power consumption public static final long MILLISECONDS_IN_DAY = 24 * 60 * 60 * 1000; public static final long MAM_MAX_CATCHUP = MILLISECONDS_IN_DAY / 2; diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index e58f760ed..34c0a5d10 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -424,6 +424,11 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa final String action = intent == null ? null : intent.getAction(); if (action != null) { switch (action) { + case ConnectivityManager.CONNECTIVITY_ACTION: + if (hasInternetConnection() && Config.RESET_ATTEMPT_COUNT_ON_NETWORK_CHANGE) { + resetAllAttemptCounts(true); + } + break; case ACTION_MERGE_PHONE_CONTACTS: if (mRestoredFromDatabase) { PhoneHelper.loadPhoneContacts(getApplicationContext(), @@ -442,14 +447,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa toggleForegroundService(); break; case ACTION_TRY_AGAIN: - for(Account account : accounts) { - if (account.hasErrorStatus()) { - final XmppConnection connection = account.getXmppConnection(); - if (connection != null) { - connection.resetAttemptCount(); - } - } - } + resetAllAttemptCounts(false); break; case ACTION_DISABLE_ACCOUNT: try { @@ -531,6 +529,18 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa return START_STICKY; } + private void resetAllAttemptCounts(boolean reallyAll) { + Log.d(Config.LOGTAG,"resetting all attepmt counts"); + for(Account account : accounts) { + if (account.hasErrorStatus() || reallyAll) { + final XmppConnection connection = account.getXmppConnection(); + if (connection != null) { + connection.resetAttemptCount(); + } + } + } + } + public boolean hasInternetConnection() { ConnectivityManager cm = (ConnectivityManager) getApplicationContext() .getSystemService(Context.CONNECTIVITY_SERVICE); -- cgit v1.2.3 From 9e78e3e09da47463d97a25acd051a8218fa98e54 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Fri, 8 May 2015 21:36:20 +0200 Subject: only forward incoming chat messages to Pebble App and Gadgetbridge --- .../java/eu/siacs/conversations/services/NotificationService.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src/main/java/eu/siacs') diff --git a/src/main/java/eu/siacs/conversations/services/NotificationService.java b/src/main/java/eu/siacs/conversations/services/NotificationService.java index fc40ce756..e111da955 100644 --- a/src/main/java/eu/siacs/conversations/services/NotificationService.java +++ b/src/main/java/eu/siacs/conversations/services/NotificationService.java @@ -85,7 +85,11 @@ public class NotificationService { i.putExtra("messageType", "PEBBLE_ALERT"); i.putExtra("sender", "Conversations"); /* XXX: Shouldn't be hardcoded, e.g., AbstractGenerator.APP_NAME); */ i.putExtra("notificationData", notificationData); - + // notify Pebble App + i.setPackage("com.getpebble.android"); + mXmppConnectionService.sendBroadcast(i); + // notify Gadgetbridge + i.setPackage("nodomain.freeyourgadget.gadgetbridge"); mXmppConnectionService.sendBroadcast(i); } -- cgit v1.2.3 From 4c486f5e583ddfc1f53f296d8a6fa9672981440a Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Sun, 10 May 2015 03:12:44 +0200 Subject: paint single unicode hearts as red and slightly larger --- .../eu/siacs/conversations/entities/Message.java | 72 ++++++++++++---------- .../conversations/ui/adapter/MessageAdapter.java | 26 ++++++-- .../eu/siacs/conversations/utils/UIHelper.java | 4 ++ 3 files changed, 66 insertions(+), 36 deletions(-) (limited to 'src/main/java/eu/siacs') diff --git a/src/main/java/eu/siacs/conversations/entities/Message.java b/src/main/java/eu/siacs/conversations/entities/Message.java index 7ea3d60b0..95e27c79b 100644 --- a/src/main/java/eu/siacs/conversations/entities/Message.java +++ b/src/main/java/eu/siacs/conversations/entities/Message.java @@ -9,6 +9,7 @@ import java.util.Arrays; import eu.siacs.conversations.Config; import eu.siacs.conversations.utils.GeoHelper; +import eu.siacs.conversations.utils.UIHelper; import eu.siacs.conversations.xmpp.jid.InvalidJidException; import eu.siacs.conversations.xmpp.jid.Jid; @@ -95,9 +96,9 @@ public class Message extends AbstractEntity { } private Message(final String uuid, final String conversationUUid, final Jid counterpart, - final Jid trueCounterpart, final String body, final long timeSent, - final int encryption, final int status, final int type, final String remoteMsgId, - final String relativeFilePath, final String serverMsgId) { + final Jid trueCounterpart, final String body, final long timeSent, + final int encryption, final int status, final int type, final String remoteMsgId, + final String relativeFilePath, final String serverMsgId) { this.uuid = uuid; this.conversationUuid = conversationUUid; this.counterpart = counterpart; @@ -179,7 +180,7 @@ public class Message extends AbstractEntity { values.put(TYPE, type); values.put(REMOTE_MSG_ID, remoteMsgId); values.put(RELATIVE_FILE_PATH, relativeFilePath); - values.put(SERVER_MSG_ID,serverMsgId); + values.put(SERVER_MSG_ID, serverMsgId); return values; } @@ -211,7 +212,7 @@ public class Message extends AbstractEntity { return null; } else { return this.conversation.getAccount().getRoster() - .getContactFromRoster(this.trueCounterpart); + .getContactFromRoster(this.trueCounterpart); } } } @@ -359,34 +360,36 @@ public class Message extends AbstractEntity { public boolean mergeable(final Message message) { return message != null && - (message.getType() == Message.TYPE_TEXT && - this.getDownloadable() == null && - message.getDownloadable() == null && - message.getEncryption() != Message.ENCRYPTION_PGP && - this.getType() == message.getType() && - //this.getStatus() == message.getStatus() && - isStatusMergeable(this.getStatus(),message.getStatus()) && - this.getEncryption() == message.getEncryption() && - this.getCounterpart() != null && - this.getCounterpart().equals(message.getCounterpart()) && - (message.getTimeSent() - this.getTimeSent()) <= (Config.MESSAGE_MERGE_WINDOW * 1000) && - !GeoHelper.isGeoUri(message.getBody()) && - !GeoHelper.isGeoUri(this.body) && - !message.bodyContainsDownloadable() && - !this.bodyContainsDownloadable() && - !message.getBody().startsWith(ME_COMMAND) && - !this.getBody().startsWith(ME_COMMAND) - ); + (message.getType() == Message.TYPE_TEXT && + this.getDownloadable() == null && + message.getDownloadable() == null && + message.getEncryption() != Message.ENCRYPTION_PGP && + this.getType() == message.getType() && + //this.getStatus() == message.getStatus() && + isStatusMergeable(this.getStatus(), message.getStatus()) && + this.getEncryption() == message.getEncryption() && + this.getCounterpart() != null && + this.getCounterpart().equals(message.getCounterpart()) && + (message.getTimeSent() - this.getTimeSent()) <= (Config.MESSAGE_MERGE_WINDOW * 1000) && + !GeoHelper.isGeoUri(message.getBody()) && + !GeoHelper.isGeoUri(this.body) && + !message.bodyContainsDownloadable() && + !this.bodyContainsDownloadable() && + !message.getBody().startsWith(ME_COMMAND) && + !this.getBody().startsWith(ME_COMMAND) && + !this.bodyIsHeart() && + !message.bodyIsHeart() + ); } private static boolean isStatusMergeable(int a, int b) { return a == b || ( - ( a == Message.STATUS_SEND_RECEIVED && b == Message.STATUS_UNSEND) - || (a == Message.STATUS_SEND_RECEIVED && b == Message.STATUS_SEND) - || (a == Message.STATUS_UNSEND && b == Message.STATUS_SEND) - || (a == Message.STATUS_UNSEND && b == Message.STATUS_SEND_RECEIVED) - || (a == Message.STATUS_SEND && b == Message.STATUS_UNSEND) - || (a == Message.STATUS_SEND && b == Message.STATUS_SEND_RECEIVED) + (a == Message.STATUS_SEND_RECEIVED && b == Message.STATUS_UNSEND) + || (a == Message.STATUS_SEND_RECEIVED && b == Message.STATUS_SEND) + || (a == Message.STATUS_UNSEND && b == Message.STATUS_SEND) + || (a == Message.STATUS_UNSEND && b == Message.STATUS_SEND_RECEIVED) + || (a == Message.STATUS_SEND && b == Message.STATUS_UNSEND) + || (a == Message.STATUS_SEND && b == Message.STATUS_SEND_RECEIVED) ); } @@ -443,7 +446,7 @@ public class Message extends AbstractEntity { if (!url.getProtocol().equalsIgnoreCase("http") && !url.getProtocol().equalsIgnoreCase("https")) { return false; - } + } String sUrlPath = url.getPath(); if (sUrlPath == null || sUrlPath.isEmpty()) { @@ -457,14 +460,14 @@ public class Message extends AbstractEntity { String[] extensionParts = sLastUrlPath.split("\\."); if (extensionParts.length == 2 && Arrays.asList(Downloadable.VALID_IMAGE_EXTENSIONS).contains( - extensionParts[extensionParts.length - 1])) { + extensionParts[extensionParts.length - 1])) { return true; } else if (extensionParts.length == 3 && Arrays .asList(Downloadable.VALID_CRYPTO_EXTENSIONS) .contains(extensionParts[extensionParts.length - 1]) && Arrays.asList(Downloadable.VALID_IMAGE_EXTENSIONS).contains( - extensionParts[extensionParts.length - 2])) { + extensionParts[extensionParts.length - 2])) { return true; } else { return false; @@ -474,6 +477,11 @@ public class Message extends AbstractEntity { } } + public boolean bodyIsHeart() { + return body != null && + (body.trim().equals(UIHelper.BLACK_HEART_SUIT) || body.trim().equals(UIHelper.HEAVY_BLACK_HEART_SUIT)); + } + public ImageParams getImageParams() { ImageParams params = getLegacyImageParams(); if (params != null) { diff --git a/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java b/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java index da92fb183..89618dfc6 100644 --- a/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java +++ b/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java @@ -7,7 +7,9 @@ import android.graphics.Typeface; import android.net.Uri; import android.text.Spannable; import android.text.SpannableString; +import android.text.Spanned; import android.text.style.ForegroundColorSpan; +import android.text.style.RelativeSizeSpan; import android.text.style.StyleSpan; import android.util.DisplayMetrics; import android.util.Log; @@ -207,12 +209,24 @@ public class MessageAdapter extends ArrayAdapter { viewHolder.image.setVisibility(View.GONE); viewHolder.messageBody.setVisibility(View.VISIBLE); viewHolder.messageBody.setText(getContext().getString( - R.string.decryption_failed)); + R.string.decryption_failed)); viewHolder.messageBody.setTextColor(activity.getWarningTextColor()); viewHolder.messageBody.setTypeface(null, Typeface.NORMAL); viewHolder.messageBody.setTextIsSelectable(false); } + private void displayHeartMesage(final ViewHolder viewHolder, final String body) { + if (viewHolder.download_button != null) { + viewHolder.download_button.setVisibility(View.GONE); + } + viewHolder.image.setVisibility(View.GONE); + viewHolder.messageBody.setVisibility(View.VISIBLE); + Spannable span = new SpannableString(body); + span.setSpan(new RelativeSizeSpan(4.0f),0,body.length(),Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + span.setSpan(new ForegroundColorSpan(activity.getWarningTextColor()),0,body.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + viewHolder.messageBody.setText(span); + } + private void displayTextMessage(final ViewHolder viewHolder, final Message message) { if (viewHolder.download_button != null) { viewHolder.download_button.setVisibility(View.GONE); @@ -289,7 +303,7 @@ public class MessageAdapter extends ArrayAdapter { viewHolder.image.setVisibility(View.GONE); viewHolder.messageBody.setVisibility(View.GONE); viewHolder.download_button.setVisibility(View.VISIBLE); - viewHolder.download_button.setText(activity.getString(R.string.open_x_file, UIHelper.getFileDescriptionString(activity,message))); + viewHolder.download_button.setText(activity.getString(R.string.open_x_file, UIHelper.getFileDescriptionString(activity, message))); viewHolder.download_button.setOnClickListener(new OnClickListener() { @Override @@ -334,7 +348,7 @@ public class MessageAdapter extends ArrayAdapter { scalledH = (int) (params.height / ((double) params.width / target)); } viewHolder.image.setLayoutParams(new LinearLayout.LayoutParams( - scalledW, scalledH)); + scalledW, scalledH)); activity.loadBitmap(message, viewHolder.image); viewHolder.image.setOnClickListener(new OnClickListener() { @@ -528,7 +542,11 @@ public class MessageAdapter extends ArrayAdapter { if (GeoHelper.isGeoUri(message.getBody())) { displayLocationMessage(viewHolder,message); } else { - displayTextMessage(viewHolder, message); + if (message.bodyIsHeart()) { + displayHeartMesage(viewHolder," "+message.getBody().trim()+" "); + } else { + displayTextMessage(viewHolder, message); + } } } diff --git a/src/main/java/eu/siacs/conversations/utils/UIHelper.java b/src/main/java/eu/siacs/conversations/utils/UIHelper.java index c3195d868..493547536 100644 --- a/src/main/java/eu/siacs/conversations/utils/UIHelper.java +++ b/src/main/java/eu/siacs/conversations/utils/UIHelper.java @@ -17,6 +17,10 @@ import android.text.format.DateUtils; import android.util.Pair; public class UIHelper { + + public static String BLACK_HEART_SUIT = "\u2665"; + public static String HEAVY_BLACK_HEART_SUIT = "\u2764"; + private static final int SHORT_DATE_FLAGS = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_NO_YEAR | DateUtils.FORMAT_ABBREV_ALL; private static final int FULL_DATE_FLAGS = DateUtils.FORMAT_SHOW_TIME -- cgit v1.2.3 From 1e28f600386f1f1dcd734363c932d5ccbd6267fb Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Sun, 10 May 2015 03:14:13 +0200 Subject: changed conversation red to material red --- src/main/java/eu/siacs/conversations/entities/Contact.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/main/java/eu/siacs') diff --git a/src/main/java/eu/siacs/conversations/entities/Contact.java b/src/main/java/eu/siacs/conversations/entities/Contact.java index 4ad105b1d..9dbca59a1 100644 --- a/src/main/java/eu/siacs/conversations/entities/Contact.java +++ b/src/main/java/eu/siacs/conversations/entities/Contact.java @@ -140,10 +140,10 @@ public class Contact implements ListItem, Blockable { tags.add(new Tag("away", 0xffff9800)); break; case Presences.XA: - tags.add(new Tag("not available", 0xffe51c23)); + tags.add(new Tag("not available", 0xfff44336)); break; case Presences.DND: - tags.add(new Tag("dnd", 0xffe51c23)); + tags.add(new Tag("dnd", 0xfff44336)); break; } if (isBlocked()) { -- cgit v1.2.3 From 33d1621e3b2c9a34689dfddc71eeb9ee4d91c348 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Sun, 10 May 2015 11:56:23 +0200 Subject: added white heart to new rendering as well --- src/main/java/eu/siacs/conversations/entities/Message.java | 4 +++- src/main/java/eu/siacs/conversations/utils/UIHelper.java | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'src/main/java/eu/siacs') diff --git a/src/main/java/eu/siacs/conversations/entities/Message.java b/src/main/java/eu/siacs/conversations/entities/Message.java index 95e27c79b..4dac0b98b 100644 --- a/src/main/java/eu/siacs/conversations/entities/Message.java +++ b/src/main/java/eu/siacs/conversations/entities/Message.java @@ -479,7 +479,9 @@ public class Message extends AbstractEntity { public boolean bodyIsHeart() { return body != null && - (body.trim().equals(UIHelper.BLACK_HEART_SUIT) || body.trim().equals(UIHelper.HEAVY_BLACK_HEART_SUIT)); + (body.trim().equals(UIHelper.BLACK_HEART_SUIT) + || body.trim().equals(UIHelper.HEAVY_BLACK_HEART_SUIT) + || body.trim().equals(UIHelper.WHITE_HEART_SUIT)); } public ImageParams getImageParams() { diff --git a/src/main/java/eu/siacs/conversations/utils/UIHelper.java b/src/main/java/eu/siacs/conversations/utils/UIHelper.java index 493547536..2cfd58235 100644 --- a/src/main/java/eu/siacs/conversations/utils/UIHelper.java +++ b/src/main/java/eu/siacs/conversations/utils/UIHelper.java @@ -20,6 +20,7 @@ public class UIHelper { public static String BLACK_HEART_SUIT = "\u2665"; public static String HEAVY_BLACK_HEART_SUIT = "\u2764"; + public static String WHITE_HEART_SUIT = "\u2661"; private static final int SHORT_DATE_FLAGS = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_NO_YEAR | DateUtils.FORMAT_ABBREV_ALL; -- cgit v1.2.3 From 239e86a98a4af8ab7ce7f6b96bed0bb4dc9e4bb5 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Sun, 10 May 2015 12:04:11 +0200 Subject: optimized heart render code a bit --- src/main/java/eu/siacs/conversations/entities/Message.java | 5 +---- src/main/java/eu/siacs/conversations/utils/UIHelper.java | 10 +++++++--- 2 files changed, 8 insertions(+), 7 deletions(-) (limited to 'src/main/java/eu/siacs') diff --git a/src/main/java/eu/siacs/conversations/entities/Message.java b/src/main/java/eu/siacs/conversations/entities/Message.java index 4dac0b98b..c87e5518f 100644 --- a/src/main/java/eu/siacs/conversations/entities/Message.java +++ b/src/main/java/eu/siacs/conversations/entities/Message.java @@ -478,10 +478,7 @@ public class Message extends AbstractEntity { } public boolean bodyIsHeart() { - return body != null && - (body.trim().equals(UIHelper.BLACK_HEART_SUIT) - || body.trim().equals(UIHelper.HEAVY_BLACK_HEART_SUIT) - || body.trim().equals(UIHelper.WHITE_HEART_SUIT)); + return body != null && UIHelper.HEARTS.contains(body.trim()); } public ImageParams getImageParams() { diff --git a/src/main/java/eu/siacs/conversations/utils/UIHelper.java b/src/main/java/eu/siacs/conversations/utils/UIHelper.java index 2cfd58235..9c62dcbfb 100644 --- a/src/main/java/eu/siacs/conversations/utils/UIHelper.java +++ b/src/main/java/eu/siacs/conversations/utils/UIHelper.java @@ -1,6 +1,8 @@ package eu.siacs.conversations.utils; import java.net.URLConnection; +import java.util.ArrayList; +import java.util.Arrays; import java.util.Calendar; import java.util.Date; @@ -18,9 +20,11 @@ import android.util.Pair; public class UIHelper { - public static String BLACK_HEART_SUIT = "\u2665"; - public static String HEAVY_BLACK_HEART_SUIT = "\u2764"; - public static String WHITE_HEART_SUIT = "\u2661"; + private static String BLACK_HEART_SUIT = "\u2665"; + private static String HEAVY_BLACK_HEART_SUIT = "\u2764"; + private static String WHITE_HEART_SUIT = "\u2661"; + + public static final ArrayList HEARTS = new ArrayList<>(Arrays.asList(BLACK_HEART_SUIT,HEAVY_BLACK_HEART_SUIT,WHITE_HEART_SUIT)); private static final int SHORT_DATE_FLAGS = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_NO_YEAR | DateUtils.FORMAT_ABBREV_ALL; -- cgit v1.2.3 From 22b12091a103a164a1d54874ad376d02dfee1519 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Mon, 11 May 2015 07:57:52 +0200 Subject: rewrote parts of message adapter to avoid using NULL views --- .../siacs/conversations/entities/Conversation.java | 6 +++ .../conversations/ui/ConversationFragment.java | 48 +++++++++++++--------- .../conversations/ui/adapter/MessageAdapter.java | 41 +++--------------- 3 files changed, 41 insertions(+), 54 deletions(-) (limited to 'src/main/java/eu/siacs') diff --git a/src/main/java/eu/siacs/conversations/entities/Conversation.java b/src/main/java/eu/siacs/conversations/entities/Conversation.java index bfee50075..95a8c957d 100644 --- a/src/main/java/eu/siacs/conversations/entities/Conversation.java +++ b/src/main/java/eu/siacs/conversations/entities/Conversation.java @@ -16,6 +16,7 @@ import java.security.interfaces.DSAPublicKey; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; +import java.util.Iterator; import java.util.List; import eu.siacs.conversations.Config; @@ -218,6 +219,11 @@ public class Conversation extends AbstractEntity implements Blockable { messages.clear(); messages.addAll(this.messages); } + for(Iterator iterator = messages.iterator(); iterator.hasNext();) { + if (iterator.next().wasMergedIntoPrevious()) { + iterator.remove(); + } + } } @Override diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java index 6b11d3109..b6a7dc767 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java @@ -117,6 +117,27 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa } + private int getIndexOf(String uuid, List messages) { + if (uuid == null) { + return 0; + } + for(int i = 0; i < messages.size(); ++i) { + if (uuid.equals(messages.get(i).getUuid())) { + return i; + } else { + Message next = messages.get(i); + while(next != null && next.wasMergedIntoPrevious()) { + if (uuid.equals(next.getUuid())) { + return i; + } + next = next.next(); + } + + } + } + return 0; + } + @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { @@ -126,7 +147,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa messagesLoaded = false; activity.xmppConnectionService.loadMoreMessages(conversation, timestamp, new XmppConnectionService.OnMoreMessagesLoaded() { @Override - public void onMoreMessagesLoaded(final int count, Conversation conversation) { + public void onMoreMessagesLoaded(final int c, Conversation conversation) { if (ConversationFragment.this.conversation != conversation) { return; } @@ -134,29 +155,18 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa @Override public void run() { final int oldPosition = messagesView.getFirstVisiblePosition(); + Message message = messageList.get(oldPosition); + String uuid = message != null ? message.getUuid() : null; View v = messagesView.getChildAt(0); final int pxOffset = (v == null) ? 0 : v.getTop(); ConversationFragment.this.conversation.populateWithMessages(ConversationFragment.this.messageList); updateStatusMessages(); messageListAdapter.notifyDataSetChanged(); - if (count != 0) { - final int newPosition = oldPosition + count; - int offset = 0; - try { - Message tmpMessage = messageList.get(newPosition); - - while (tmpMessage.wasMergedIntoPrevious()) { - offset++; - tmpMessage = tmpMessage.prev(); - } - } catch (final IndexOutOfBoundsException ignored) { - - } - messagesView.setSelectionFromTop(newPosition - offset, pxOffset); - messagesLoaded = true; - if (messageLoaderToast != null) { - messageLoaderToast.cancel(); - } + int pos = getIndexOf(uuid,messageList); + messagesView.setSelectionFromTop(pos, pxOffset); + messagesLoaded = true; + if (messageLoaderToast != null) { + messageLoaderToast.cancel(); } } }); diff --git a/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java b/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java index 89618dfc6..b23709fc3 100644 --- a/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java +++ b/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java @@ -12,7 +12,6 @@ import android.text.style.ForegroundColorSpan; import android.text.style.RelativeSizeSpan; import android.text.style.StyleSpan; import android.util.DisplayMetrics; -import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.view.View.OnLongClickListener; @@ -26,7 +25,6 @@ import android.widget.Toast; import java.util.List; -import eu.siacs.conversations.Config; import eu.siacs.conversations.R; import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.entities.Contact; @@ -44,7 +42,6 @@ public class MessageAdapter extends ArrayAdapter { private static final int SENT = 0; private static final int RECEIVED = 1; private static final int STATUS = 2; - private static final int NULL = 3; private ConversationActivity activity; @@ -79,14 +76,12 @@ public class MessageAdapter extends ArrayAdapter { @Override public int getViewTypeCount() { - return 4; + return 3; } @Override public int getItemViewType(int position) { - if (getItem(position).wasMergedIntoPrevious()) { - return NULL; - } else if (getItem(position).getType() == Message.TYPE_STATUS) { + if (getItem(position).getType() == Message.TYPE_STATUS) { return STATUS; } else if (getItem(position).getStatus() <= Message.STATUS_RECEIVED) { return RECEIVED; @@ -222,8 +217,8 @@ public class MessageAdapter extends ArrayAdapter { viewHolder.image.setVisibility(View.GONE); viewHolder.messageBody.setVisibility(View.VISIBLE); Spannable span = new SpannableString(body); - span.setSpan(new RelativeSizeSpan(4.0f),0,body.length(),Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); - span.setSpan(new ForegroundColorSpan(activity.getWarningTextColor()),0,body.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + span.setSpan(new RelativeSizeSpan(4.0f), 0, body.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + span.setSpan(new ForegroundColorSpan(activity.getWarningTextColor()), 0, body.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); viewHolder.messageBody.setText(span); } @@ -235,8 +230,7 @@ public class MessageAdapter extends ArrayAdapter { viewHolder.messageBody.setVisibility(View.VISIBLE); if (message.getBody() != null) { final String nick = UIHelper.getMessageDisplayName(message); - final String formattedBody = message.getMergedBody().replaceAll("^" + Message.ME_COMMAND, - nick + " "); + final String formattedBody = message.getMergedBody().replaceAll("^" + Message.ME_COMMAND,nick + " "); if (message.getType() != Message.TYPE_PRIVATE) { if (message.hasMeCommand()) { final Spannable span = new SpannableString(formattedBody); @@ -244,7 +238,7 @@ public class MessageAdapter extends ArrayAdapter { Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); viewHolder.messageBody.setText(span); } else { - viewHolder.messageBody.setText(message.getMergedBody()); + viewHolder.messageBody.setText(formattedBody); } } else { String privateMarker; @@ -373,10 +367,6 @@ public class MessageAdapter extends ArrayAdapter { if (view == null) { viewHolder = new ViewHolder(); switch (type) { - case NULL: - view = activity.getLayoutInflater().inflate( - R.layout.message_null, parent, false); - break; case SENT: view = activity.getLayoutInflater().inflate( R.layout.message_sent, parent, false); @@ -443,25 +433,6 @@ public class MessageAdapter extends ArrayAdapter { viewHolder.status_message.setText(message.getBody()); } return view; - } else if (type == NULL) { - if (viewHolder.message_box != null) { - Log.e(Config.LOGTAG, "detected type=NULL but with wrong cached view"); - view = activity.getLayoutInflater().inflate(R.layout.message_null, parent, false); - view.setTag(new ViewHolder()); - } - if (position == getCount() - 1) { - view.getLayoutParams().height = 1; - } else { - view.getLayoutParams().height = 0; - - } - view.setLayoutParams(view.getLayoutParams()); - return view; - } else if (message.wasMergedIntoPrevious()) { - Log.e(Config.LOGTAG,"detected wasMergedIntoPrevious with wrong type"); - return view; - } else if (viewHolder.messageBody == null || viewHolder.image == null) { - return view; //avoiding weird platform bugs } else if (type == RECEIVED) { Contact contact = message.getContact(); if (contact != null) { -- cgit v1.2.3 From 21deda7b0029b729c94af9f1551278859b78f119 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Mon, 11 May 2015 08:45:38 +0200 Subject: no font padding on red hearts --- src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src/main/java/eu/siacs') diff --git a/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java b/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java index b23709fc3..060bef71c 100644 --- a/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java +++ b/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java @@ -210,12 +210,13 @@ public class MessageAdapter extends ArrayAdapter { viewHolder.messageBody.setTextIsSelectable(false); } - private void displayHeartMesage(final ViewHolder viewHolder, final String body) { + private void displayHeartMessage(final ViewHolder viewHolder, final String body) { if (viewHolder.download_button != null) { viewHolder.download_button.setVisibility(View.GONE); } viewHolder.image.setVisibility(View.GONE); viewHolder.messageBody.setVisibility(View.VISIBLE); + viewHolder.messageBody.setIncludeFontPadding(false); Spannable span = new SpannableString(body); span.setSpan(new RelativeSizeSpan(4.0f), 0, body.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); span.setSpan(new ForegroundColorSpan(activity.getWarningTextColor()), 0, body.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); @@ -228,6 +229,7 @@ public class MessageAdapter extends ArrayAdapter { } viewHolder.image.setVisibility(View.GONE); viewHolder.messageBody.setVisibility(View.VISIBLE); + viewHolder.messageBody.setIncludeFontPadding(true); if (message.getBody() != null) { final String nick = UIHelper.getMessageDisplayName(message); final String formattedBody = message.getMergedBody().replaceAll("^" + Message.ME_COMMAND,nick + " "); @@ -514,7 +516,7 @@ public class MessageAdapter extends ArrayAdapter { displayLocationMessage(viewHolder,message); } else { if (message.bodyIsHeart()) { - displayHeartMesage(viewHolder," "+message.getBody().trim()+" "); + displayHeartMessage(viewHolder, message.getBody().trim()); } else { displayTextMessage(viewHolder, message); } -- cgit v1.2.3 From 53e43daa0d8143d9a5abcd1391153b88a4702914 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Mon, 11 May 2015 09:08:56 +0200 Subject: add a little bit of space between merged messages. --- src/main/java/eu/siacs/conversations/entities/Message.java | 2 +- .../java/eu/siacs/conversations/ui/adapter/MessageAdapter.java | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) (limited to 'src/main/java/eu/siacs') diff --git a/src/main/java/eu/siacs/conversations/entities/Message.java b/src/main/java/eu/siacs/conversations/entities/Message.java index c87e5518f..3c144f5cf 100644 --- a/src/main/java/eu/siacs/conversations/entities/Message.java +++ b/src/main/java/eu/siacs/conversations/entities/Message.java @@ -396,7 +396,7 @@ public class Message extends AbstractEntity { public String getMergedBody() { final Message next = this.next(); if (this.mergeable(next)) { - return getBody().trim() + '\n' + next.getMergedBody(); + return getBody().trim() + "\n\n" + next.getMergedBody(); } return getBody().trim(); } diff --git a/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java b/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java index 060bef71c..0730f0e11 100644 --- a/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java +++ b/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java @@ -232,7 +232,13 @@ public class MessageAdapter extends ArrayAdapter { viewHolder.messageBody.setIncludeFontPadding(true); if (message.getBody() != null) { final String nick = UIHelper.getMessageDisplayName(message); - final String formattedBody = message.getMergedBody().replaceAll("^" + Message.ME_COMMAND,nick + " "); + final String body = message.getMergedBody().replaceAll("^" + Message.ME_COMMAND,nick + " "); + final SpannableString formattedBody = new SpannableString(body); + int i = body.indexOf("\n\n"); + while(i >= 0) { + formattedBody.setSpan(new RelativeSizeSpan(0.2f),i,i+2,Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + i = body.indexOf("\n\n",i+2); + } if (message.getType() != Message.TYPE_PRIVATE) { if (message.hasMeCommand()) { final Spannable span = new SpannableString(formattedBody); -- cgit v1.2.3 From 9156665addb5541cacf640f033f03cec0937f052 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Mon, 11 May 2015 09:20:08 +0200 Subject: increased space between merged messages a bit --- src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/main/java/eu/siacs') diff --git a/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java b/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java index 0730f0e11..ec351622c 100644 --- a/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java +++ b/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java @@ -236,7 +236,7 @@ public class MessageAdapter extends ArrayAdapter { final SpannableString formattedBody = new SpannableString(body); int i = body.indexOf("\n\n"); while(i >= 0) { - formattedBody.setSpan(new RelativeSizeSpan(0.2f),i,i+2,Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + formattedBody.setSpan(new RelativeSizeSpan(0.3f),i,i+2,Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); i = body.indexOf("\n\n",i+2); } if (message.getType() != Message.TYPE_PRIVATE) { -- cgit v1.2.3 From b6f85ba0dd765e72a89a85461b3f8c48f038270c Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Mon, 11 May 2015 14:18:30 +0200 Subject: avoid using paragraph style breaks by accident --- src/main/java/eu/siacs/conversations/entities/Message.java | 4 +++- .../java/eu/siacs/conversations/ui/adapter/MessageAdapter.java | 7 ++++--- 2 files changed, 7 insertions(+), 4 deletions(-) (limited to 'src/main/java/eu/siacs') diff --git a/src/main/java/eu/siacs/conversations/entities/Message.java b/src/main/java/eu/siacs/conversations/entities/Message.java index 3c144f5cf..217b82bb7 100644 --- a/src/main/java/eu/siacs/conversations/entities/Message.java +++ b/src/main/java/eu/siacs/conversations/entities/Message.java @@ -17,6 +17,8 @@ public class Message extends AbstractEntity { public static final String TABLENAME = "messages"; + public static final String MERGE_SEPARATOR = "\u2029\n\n"; + public static final int STATUS_RECEIVED = 0; public static final int STATUS_UNSEND = 1; public static final int STATUS_SEND = 2; @@ -396,7 +398,7 @@ public class Message extends AbstractEntity { public String getMergedBody() { final Message next = this.next(); if (this.mergeable(next)) { - return getBody().trim() + "\n\n" + next.getMergedBody(); + return getBody().trim() + MERGE_SEPARATOR + next.getMergedBody(); } return getBody().trim(); } diff --git a/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java b/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java index ec351622c..29dfced2e 100644 --- a/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java +++ b/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java @@ -234,10 +234,11 @@ public class MessageAdapter extends ArrayAdapter { final String nick = UIHelper.getMessageDisplayName(message); final String body = message.getMergedBody().replaceAll("^" + Message.ME_COMMAND,nick + " "); final SpannableString formattedBody = new SpannableString(body); - int i = body.indexOf("\n\n"); + int i = body.indexOf(Message.MERGE_SEPARATOR); while(i >= 0) { - formattedBody.setSpan(new RelativeSizeSpan(0.3f),i,i+2,Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); - i = body.indexOf("\n\n",i+2); + final int end = i + Message.MERGE_SEPARATOR.length(); + formattedBody.setSpan(new RelativeSizeSpan(0.3f),i,end,Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + i = body.indexOf(Message.MERGE_SEPARATOR,end); } if (message.getType() != Message.TYPE_PRIVATE) { if (message.hasMeCommand()) { -- cgit v1.2.3 From fe5c4cab4608a6b3ded682f4a69da14916cc1d37 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Tue, 12 May 2015 03:56:13 +0200 Subject: don't reinit conversation when coming back to activity. avoids unnecessary scrolling --- src/main/java/eu/siacs/conversations/ui/ConversationActivity.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'src/main/java/eu/siacs') diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java index b11ff0024..6e175d8ef 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java @@ -927,9 +927,7 @@ public class ConversationActivity extends XmppActivity } this.mConversationFragment.reInit(getSelectedConversation()); mOpenConverstaion = null; - } else if (getSelectedConversation() != null) { - this.mConversationFragment.reInit(getSelectedConversation()); - } else { + } else if (getSelectedConversation() == null) { showConversationsOverview(); mPendingImageUris.clear(); mPendingFileUris.clear(); -- cgit v1.2.3 From 93e444ac3ad4b39415d7097566c319904ff14bcd Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Tue, 12 May 2015 03:57:05 +0200 Subject: don't set unknown error in muc --- src/main/java/eu/siacs/conversations/entities/MucOptions.java | 2 -- 1 file changed, 2 deletions(-) (limited to 'src/main/java/eu/siacs') diff --git a/src/main/java/eu/siacs/conversations/entities/MucOptions.java b/src/main/java/eu/siacs/conversations/entities/MucOptions.java index addee8db2..d867a3708 100644 --- a/src/main/java/eu/siacs/conversations/entities/MucOptions.java +++ b/src/main/java/eu/siacs/conversations/entities/MucOptions.java @@ -343,8 +343,6 @@ public class MucOptions { setError(ERROR_BANNED); } else if (error != null && error.hasChild("registration-required")) { setError(ERROR_MEMBERS_ONLY); - } else { - setError(ERROR_UNKNOWN); } } } -- cgit v1.2.3 From d3a6aa9f7a3132f8f67f2de99b4afbaba7823abb Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Tue, 12 May 2015 04:33:04 +0200 Subject: handle conference invites differently to deal with killed activities. fixes #1188 --- .../services/XmppConnectionService.java | 1 + .../ui/ConferenceDetailsActivity.java | 4 + .../conversations/ui/ConversationActivity.java | 6 ++ .../eu/siacs/conversations/ui/XmppActivity.java | 87 ++++++++++++++-------- 4 files changed, 67 insertions(+), 31 deletions(-) (limited to 'src/main/java/eu/siacs') diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index 34c0a5d10..0ed89206d 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -2108,6 +2108,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa } public void invite(Conversation conversation, Jid contact) { + Log.d(Config.LOGTAG,conversation.getAccount().getJid().toBareJid()+": inviting "+contact+" to "+conversation.getJid().toBareJid()); MessagePacket packet = mMessageGenerator.invite(conversation, contact); sendMessagePacket(conversation.getAccount(), packet); } diff --git a/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java b/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java index 8c4f6eafe..07b8819d9 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java @@ -385,6 +385,10 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers @Override void onBackendConnected() { + if (mPendingConferenceInvite != null) { + mPendingConferenceInvite.execute(this); + mPendingConferenceInvite = null; + } if (getIntent().getAction().equals(ACTION_VIEW_MUC)) { this.uuid = getIntent().getExtras().getString("uuid"); } diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java index 6e175d8ef..a2a405c36 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java @@ -901,6 +901,12 @@ public class ConversationActivity extends XmppActivity void onBackendConnected() { this.xmppConnectionService.getNotificationService().setIsInForeground(true); updateConversationList(); + + if (mPendingConferenceInvite != null) { + mPendingConferenceInvite.execute(this); + mPendingConferenceInvite = null; + } + if (xmppConnectionService.getAccounts().size() == 0) { if (!mRedirected) { this.mRedirected = true; diff --git a/src/main/java/eu/siacs/conversations/ui/XmppActivity.java b/src/main/java/eu/siacs/conversations/ui/XmppActivity.java index 392e57a70..71fb62b51 100644 --- a/src/main/java/eu/siacs/conversations/ui/XmppActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/XmppActivity.java @@ -113,6 +113,8 @@ public abstract class XmppActivity extends Activity { } }; + protected ConferenceInvite mPendingConferenceInvite = null; + protected void refreshUi() { final long diff = SystemClock.elapsedRealtime() - mLastUiRefresh; @@ -367,7 +369,7 @@ public abstract class XmppActivity extends Activity { } public void highlightInMuc(Conversation conversation, String nick) { - switchToConversation(conversation,null,nick,false); + switchToConversation(conversation, null, nick, false); } private void switchToConversation(Conversation conversation, String text, String nick, boolean newTask) { @@ -435,7 +437,7 @@ public abstract class XmppActivity extends Activity { @Override public void userInputRequried(PendingIntent pi, - Account account) { + Account account) { try { startIntentSenderForResult(pi.getIntentSender(), REQUEST_ANNOUNCE_PGP, null, 0, 0, 0); @@ -446,13 +448,13 @@ public abstract class XmppActivity extends Activity { @Override public void success(Account account) { xmppConnectionService.databaseBackend - .updateAccount(account); + .updateAccount(account); xmppConnectionService.sendPresence(account); if (conversation != null) { conversation - .setNextEncryption(Message.ENCRYPTION_PGP); + .setNextEncryption(Message.ENCRYPTION_PGP); xmppConnectionService.databaseBackend - .updateConversation(conversation); + .updateConversation(conversation); } } @@ -665,32 +667,13 @@ public abstract class XmppActivity extends Activity { protected void onActivityResult(int requestCode, int resultCode, final Intent data) { super.onActivityResult(requestCode, resultCode, data); - if (requestCode == REQUEST_INVITE_TO_CONVERSATION - && resultCode == RESULT_OK) { - try { - String conversationUuid = data.getStringExtra("conversation"); - Conversation conversation = xmppConnectionService - .findConversationByUuid(conversationUuid); - List jids = new ArrayList(); - if (data.getBooleanExtra("multiple", false)) { - String[] toAdd = data.getStringArrayExtra("contacts"); - for (String item : toAdd) { - jids.add(Jid.fromString(item)); - } - } else { - jids.add(Jid.fromString(data.getStringExtra("contact"))); - } - - if (conversation.getMode() == Conversation.MODE_MULTI) { - for (Jid jid : jids) { - xmppConnectionService.invite(conversation, jid); - } - } else { - jids.add(conversation.getJid().toBareJid()); - xmppConnectionService.createAdhocConference(conversation.getAccount(), jids, adhocCallback); - } - } catch (final InvalidJidException ignored) { - + if (requestCode == REQUEST_INVITE_TO_CONVERSATION && resultCode == RESULT_OK) { + mPendingConferenceInvite = ConferenceInvite.parse(data); + if (xmppConnectionServiceBound && mPendingConferenceInvite != null) { + mPendingConferenceInvite.execute(this); + mPendingConferenceInvite = null; + } else { + Log.d(Config.LOGTAG,"putting invite on pending"); } } } @@ -855,6 +838,48 @@ public abstract class XmppActivity extends Activity { } } + public static class ConferenceInvite { + private String uuid; + private List jids = new ArrayList<>(); + + public static ConferenceInvite parse(Intent data) { + ConferenceInvite invite = new ConferenceInvite(); + invite.uuid = data.getStringExtra("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.fromString(item)); + } + } else { + invite.jids.add(Jid.fromString(data.getStringExtra("contact"))); + } + } catch (final InvalidJidException ignored) { + return null; + } + return invite; + } + + public void execute(XmppActivity activity) { + XmppConnectionService service = activity.xmppConnectionService; + Conversation conversation = service.findConversationByUuid(this.uuid); + if (conversation == null) { + return; + } + if (conversation.getMode() == Conversation.MODE_MULTI) { + for (Jid jid : jids) { + service.invite(conversation, jid); + } + } else { + jids.add(conversation.getJid().toBareJid()); + service.createAdhocConference(conversation.getAccount(), jids, activity.adhocCallback); + } + } + } + public AvatarService avatarService() { return xmppConnectionService.getAvatarService(); } -- cgit v1.2.3 From 93e620d6858cd713c8895256f3233e9d0bd75d74 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Tue, 12 May 2015 04:40:57 +0200 Subject: removed debug logging --- src/main/java/eu/siacs/conversations/ui/XmppActivity.java | 2 -- 1 file changed, 2 deletions(-) (limited to 'src/main/java/eu/siacs') diff --git a/src/main/java/eu/siacs/conversations/ui/XmppActivity.java b/src/main/java/eu/siacs/conversations/ui/XmppActivity.java index 71fb62b51..934c696f0 100644 --- a/src/main/java/eu/siacs/conversations/ui/XmppActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/XmppActivity.java @@ -672,8 +672,6 @@ public abstract class XmppActivity extends Activity { if (xmppConnectionServiceBound && mPendingConferenceInvite != null) { mPendingConferenceInvite.execute(this); mPendingConferenceInvite = null; - } else { - Log.d(Config.LOGTAG,"putting invite on pending"); } } } -- cgit v1.2.3 From 51aeeb766c5c0ad649abad7777bb5e194a6ae997 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Wed, 13 May 2015 11:56:59 +0200 Subject: use zero width white space as message seperator --- src/main/java/eu/siacs/conversations/entities/Message.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/main/java/eu/siacs') diff --git a/src/main/java/eu/siacs/conversations/entities/Message.java b/src/main/java/eu/siacs/conversations/entities/Message.java index 217b82bb7..a8bb9c557 100644 --- a/src/main/java/eu/siacs/conversations/entities/Message.java +++ b/src/main/java/eu/siacs/conversations/entities/Message.java @@ -17,7 +17,7 @@ public class Message extends AbstractEntity { public static final String TABLENAME = "messages"; - public static final String MERGE_SEPARATOR = "\u2029\n\n"; + public static final String MERGE_SEPARATOR = "\u200B\n\n"; public static final int STATUS_RECEIVED = 0; public static final int STATUS_UNSEND = 1; -- cgit v1.2.3 From 6489ddac6c6d3d6eced35ab4640963eb15667bb5 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Wed, 13 May 2015 14:33:52 +0200 Subject: clear avatar cache when uploading new avatar --- src/main/java/eu/siacs/conversations/services/XmppConnectionService.java | 1 + 1 file changed, 1 insertion(+) (limited to 'src/main/java/eu/siacs') diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index 0ed89206d..4f2697a37 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -1879,6 +1879,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa IqPacket result) { if (result.getType() == IqPacket.TYPE.RESULT) { if (account.setAvatar(avatar.getFilename())) { + getAvatarService().clear(account); databaseBackend.updateAccount(account); } callback.success(avatar); -- cgit v1.2.3 From 82878cded1007331e953908dee11c66557e9ae20 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Wed, 13 May 2015 16:23:20 +0200 Subject: show location quick action after receiving a question about the users location --- .../conversations/ui/ConversationFragment.java | 5 ++++- .../eu/siacs/conversations/utils/UIHelper.java | 24 ++++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) (limited to 'src/main/java/eu/siacs') diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java index b6a7dc767..20fc17506 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java @@ -59,6 +59,7 @@ import eu.siacs.conversations.ui.adapter.MessageAdapter; import eu.siacs.conversations.ui.adapter.MessageAdapter.OnContactPictureClicked; import eu.siacs.conversations.ui.adapter.MessageAdapter.OnContactPictureLongClicked; import eu.siacs.conversations.utils.GeoHelper; +import eu.siacs.conversations.utils.UIHelper; import eu.siacs.conversations.xmpp.chatstate.ChatState; import eu.siacs.conversations.xmpp.jid.Jid; @@ -905,7 +906,9 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa } else { if (empty) { String setting = activity.getPreferences().getString("quick_action","recent"); - if (setting.equals("recent")) { + if (!setting.equals("none") && UIHelper.receivedLocationQuestion(conversation.getLatestMessage())) { + setting = "location"; + } else if (setting.equals("recent")) { setting = activity.getPreferences().getString("recently_used_quick_action","text"); } switch (setting) { diff --git a/src/main/java/eu/siacs/conversations/utils/UIHelper.java b/src/main/java/eu/siacs/conversations/utils/UIHelper.java index 9c62dcbfb..e289e0e58 100644 --- a/src/main/java/eu/siacs/conversations/utils/UIHelper.java +++ b/src/main/java/eu/siacs/conversations/utils/UIHelper.java @@ -5,6 +5,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; import java.util.Date; +import java.util.Locale; import eu.siacs.conversations.R; import eu.siacs.conversations.entities.Contact; @@ -26,6 +27,19 @@ public class UIHelper { public static final ArrayList HEARTS = new ArrayList<>(Arrays.asList(BLACK_HEART_SUIT,HEAVY_BLACK_HEART_SUIT,WHITE_HEART_SUIT)); + private static final ArrayList LOCATION_QUESTIONS = new ArrayList<>(Arrays.asList( + "where are you?", //en + "where r u?", //en + "whats your 20?", //en + "what is your 20?", //en + "what's your 20?", //en + "whats your twenty?", //en + "what is your twenty?", //en + "what's your twenty?", //en + "wo bist du?", //de + "wo sind sie?" //de + )); + private static final int SHORT_DATE_FLAGS = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_NO_YEAR | DateUtils.FORMAT_ABBREV_ALL; private static final int FULL_DATE_FLAGS = DateUtils.FORMAT_SHOW_TIME @@ -234,4 +248,14 @@ public class UIHelper { return counterpart.toString().trim(); } } + + public static boolean receivedLocationQuestion(Message message) { + if (message == null + || message.getStatus() != Message.STATUS_RECEIVED + || message.getType() != Message.TYPE_TEXT) { + return false; + } + String body = message.getBody() == null ? null : message.getBody().trim().toLowerCase(Locale.getDefault()); + return LOCATION_QUESTIONS.contains(body); + } } -- cgit v1.2.3 From 4414cf3b277ec7a0a015e23eab197374f3714da6 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Wed, 13 May 2015 17:10:11 +0200 Subject: ignore question marks in location question --- .../eu/siacs/conversations/utils/UIHelper.java | 23 ++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) (limited to 'src/main/java/eu/siacs') diff --git a/src/main/java/eu/siacs/conversations/utils/UIHelper.java b/src/main/java/eu/siacs/conversations/utils/UIHelper.java index e289e0e58..51984c910 100644 --- a/src/main/java/eu/siacs/conversations/utils/UIHelper.java +++ b/src/main/java/eu/siacs/conversations/utils/UIHelper.java @@ -28,16 +28,18 @@ public class UIHelper { public static final ArrayList HEARTS = new ArrayList<>(Arrays.asList(BLACK_HEART_SUIT,HEAVY_BLACK_HEART_SUIT,WHITE_HEART_SUIT)); private static final ArrayList LOCATION_QUESTIONS = new ArrayList<>(Arrays.asList( - "where are you?", //en - "where r u?", //en - "whats your 20?", //en - "what is your 20?", //en - "what's your 20?", //en - "whats your twenty?", //en - "what is your twenty?", //en - "what's your twenty?", //en - "wo bist du?", //de - "wo sind sie?" //de + "where are you", //en + "where r u", //en + "whats your 20", //en + "what is your 20", //en + "what's your 20", //en + "whats your twenty", //en + "what is your twenty", //en + "what's your twenty", //en + "wo bist du", //de + "wo sind sie", //de + "wo seid ihr", //de + "dónde estás" //es )); private static final int SHORT_DATE_FLAGS = DateUtils.FORMAT_SHOW_DATE @@ -256,6 +258,7 @@ public class UIHelper { return false; } String body = message.getBody() == null ? null : message.getBody().trim().toLowerCase(Locale.getDefault()); + body = body.replace("?","").replace("¿",""); return LOCATION_QUESTIONS.contains(body); } } -- cgit v1.2.3 From 8d472157a4b706ef0c5fc422325f0c1ad47e96bd Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Thu, 14 May 2015 11:57:51 +0200 Subject: always log reason for failed file transfer --- .../conversations/xmpp/jingle/JingleInbandTransport.java | 8 ++++++-- .../conversations/xmpp/jingle/JingleSocks5Transport.java | 12 ++++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) (limited to 'src/main/java/eu/siacs') diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleInbandTransport.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleInbandTransport.java index 4e039ad85..29efcf8f1 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleInbandTransport.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleInbandTransport.java @@ -97,11 +97,13 @@ public class JingleInbandTransport extends JingleTransport { file.createNewFile(); this.fileOutputStream = file.createOutputStream(); if (this.fileOutputStream == null) { + Log.d(Config.LOGTAG,account.getJid().toBareJid()+": could not create output stream"); callback.onFileTransferAborted(); return; } this.remainingSize = this.fileSize = file.getExpectedSize(); } catch (final NoSuchAlgorithmException | IOException e) { + Log.d(Config.LOGTAG,account.getJid().toBareJid()+" "+e.getMessage()); callback.onFileTransferAborted(); } } @@ -122,6 +124,7 @@ public class JingleInbandTransport extends JingleTransport { this.digest.reset(); fileInputStream = this.file.createInputStream(); if (fileInputStream == null) { + Log.d(Config.LOGTAG,account.getJid().toBareJid()+": could no create input stream"); callback.onFileTransferAborted(); return; } @@ -130,6 +133,7 @@ public class JingleInbandTransport extends JingleTransport { } } catch (NoSuchAlgorithmException e) { callback.onFileTransferAborted(); + Log.d(Config.LOGTAG,account.getJid().toBareJid()+": "+e.getMessage()); } } @@ -182,7 +186,7 @@ public class JingleInbandTransport extends JingleTransport { fileInputStream.close(); } } catch (IOException e) { - Log.d(Config.LOGTAG,e.getMessage()); + Log.d(Config.LOGTAG,account.getJid().toBareJid()+": "+e.getMessage()); FileBackend.close(fileInputStream); this.onFileTransmissionStatusChanged.onFileTransferAborted(); } @@ -206,7 +210,7 @@ public class JingleInbandTransport extends JingleTransport { connection.updateProgress((int) ((((double) (this.fileSize - this.remainingSize)) / this.fileSize) * 100)); } } catch (IOException e) { - Log.d(Config.LOGTAG,e.getMessage()); + Log.d(Config.LOGTAG,account.getJid().toBareJid()+": "+e.getMessage()); FileBackend.close(fileOutputStream); this.onFileTransmissionStatusChanged.onFileTransferAborted(); } diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java index 72015a058..35375a5dc 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java @@ -1,5 +1,7 @@ package eu.siacs.conversations.xmpp.jingle; +import android.util.Log; + import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; @@ -10,6 +12,7 @@ import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Arrays; +import eu.siacs.conversations.Config; import eu.siacs.conversations.entities.DownloadableFile; import eu.siacs.conversations.persistance.FileBackend; import eu.siacs.conversations.utils.CryptoHelper; @@ -102,6 +105,7 @@ public class JingleSocks5Transport extends JingleTransport { digest.reset(); fileInputStream = file.createInputStream(); if (fileInputStream == null) { + Log.d(Config.LOGTAG, connection.getAccount().getJid().toBareJid() + ": could not create input stream"); callback.onFileTransferAborted(); return; } @@ -121,10 +125,13 @@ public class JingleSocks5Transport extends JingleTransport { callback.onFileTransmitted(file); } } catch (FileNotFoundException e) { + Log.d(Config.LOGTAG, connection.getAccount().getJid().toBareJid() + ": "+e.getMessage()); callback.onFileTransferAborted(); } catch (IOException e) { + Log.d(Config.LOGTAG, connection.getAccount().getJid().toBareJid() + ": "+e.getMessage()); callback.onFileTransferAborted(); } catch (NoSuchAlgorithmException e) { + Log.d(Config.LOGTAG, connection.getAccount().getJid().toBareJid() + ": "+e.getMessage()); callback.onFileTransferAborted(); } finally { FileBackend.close(fileInputStream); @@ -150,6 +157,7 @@ public class JingleSocks5Transport extends JingleTransport { fileOutputStream = file.createOutputStream(); if (fileOutputStream == null) { callback.onFileTransferAborted(); + Log.d(Config.LOGTAG, connection.getAccount().getJid().toBareJid() + ": could not create output stream"); return; } double size = file.getExpectedSize(); @@ -160,6 +168,7 @@ public class JingleSocks5Transport extends JingleTransport { count = inputStream.read(buffer); if (count == -1) { callback.onFileTransferAborted(); + Log.d(Config.LOGTAG, connection.getAccount().getJid().toBareJid() + ": file ended prematurely with "+remainingSize+" bytes remaining"); return; } else { fileOutputStream.write(buffer, 0, count); @@ -173,10 +182,13 @@ public class JingleSocks5Transport extends JingleTransport { file.setSha1Sum(CryptoHelper.bytesToHex(digest.digest())); callback.onFileTransmitted(file); } catch (FileNotFoundException e) { + Log.d(Config.LOGTAG, connection.getAccount().getJid().toBareJid() + ": "+e.getMessage()); callback.onFileTransferAborted(); } catch (IOException e) { + Log.d(Config.LOGTAG, connection.getAccount().getJid().toBareJid() + ": "+e.getMessage()); callback.onFileTransferAborted(); } catch (NoSuchAlgorithmException e) { + Log.d(Config.LOGTAG, connection.getAccount().getJid().toBareJid() + ": "+e.getMessage()); callback.onFileTransferAborted(); } finally { FileBackend.close(fileOutputStream); -- cgit v1.2.3 From 8dfa701043d6e442f24edeb4fec48e9d07377a90 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Thu, 14 May 2015 12:08:43 +0200 Subject: added a few location questions --- src/main/java/eu/siacs/conversations/utils/UIHelper.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'src/main/java/eu/siacs') diff --git a/src/main/java/eu/siacs/conversations/utils/UIHelper.java b/src/main/java/eu/siacs/conversations/utils/UIHelper.java index 51984c910..2f96a83a9 100644 --- a/src/main/java/eu/siacs/conversations/utils/UIHelper.java +++ b/src/main/java/eu/siacs/conversations/utils/UIHelper.java @@ -29,7 +29,8 @@ public class UIHelper { private static final ArrayList LOCATION_QUESTIONS = new ArrayList<>(Arrays.asList( "where are you", //en - "where r u", //en + "where are you now", //en + "where are you right now", //en "whats your 20", //en "what is your 20", //en "what's your 20", //en @@ -37,9 +38,13 @@ public class UIHelper { "what is your twenty", //en "what's your twenty", //en "wo bist du", //de - "wo sind sie", //de + "wo bist du jetzt", //de + "wo bist du gerade", //de "wo seid ihr", //de - "dónde estás" //es + "wo seid ihr jetzt", //de + "wo seid ihr gerade", //de + "dónde estás", //es + "donde estas" //es )); private static final int SHORT_DATE_FLAGS = DateUtils.FORMAT_SHOW_DATE -- cgit v1.2.3 From b69ee7125d49493bea86c6e3095f1236ad895980 Mon Sep 17 00:00:00 2001 From: Andreas Straub Date: Thu, 14 May 2015 15:25:52 +0200 Subject: Force Nameprepping of JID domain parts The IDN.toAscii()/IDN.toUnicode() family only namepreps the original domain passed to it if it contained non-ASCII characters. This means that for all-ASCII domains, no canonicalization is performed, which leads to issues like case-sensitivity. This workaround explicitly namepreps domain parts before calling IDN.toAscii() on them, in order to get a canonicalized representation (most notably, case invariance). A basic DB migration is also included. --- .../conversations/persistance/DatabaseBackend.java | 87 +++++++++++++++++++++- .../java/eu/siacs/conversations/xmpp/jid/Jid.java | 13 +++- 2 files changed, 96 insertions(+), 4 deletions(-) (limited to 'src/main/java/eu/siacs') diff --git a/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java b/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java index 28e1c47e7..ed88e434e 100644 --- a/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java +++ b/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java @@ -4,11 +4,13 @@ import java.util.ArrayList; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; +import eu.siacs.conversations.Config; import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.entities.Contact; import eu.siacs.conversations.entities.Conversation; import eu.siacs.conversations.entities.Message; import eu.siacs.conversations.entities.Roster; +import eu.siacs.conversations.xmpp.jid.InvalidJidException; import eu.siacs.conversations.xmpp.jid.Jid; import android.content.Context; @@ -16,13 +18,14 @@ import android.database.Cursor; import android.database.sqlite.SQLiteCantOpenDatabaseException; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; +import android.util.Log; public class DatabaseBackend extends SQLiteOpenHelper { private static DatabaseBackend instance = null; private static final String DATABASE_NAME = "history"; - private static final int DATABASE_VERSION = 13; + private static final int DATABASE_VERSION = 14; private static String CREATE_CONTATCS_STATEMENT = "create table " + Contact.TABLENAME + "(" + Contact.ACCOUNT + " TEXT, " @@ -130,6 +133,88 @@ public class DatabaseBackend extends SQLiteOpenHelper { db.execSQL("delete from "+Contact.TABLENAME); db.execSQL("update "+Account.TABLENAME+" set "+Account.ROSTERVERSION+" = NULL"); } + if (oldVersion < 14 && newVersion >= 14) { + // migrate db to new, canonicalized JID domainpart representation + + // Conversation table + Cursor cursor = db.rawQuery("select * from " + Conversation.TABLENAME, new String[0]); + while(cursor.moveToNext()) { + String newJid; + try { + newJid = Jid.fromString( + cursor.getString(cursor.getColumnIndex(Conversation.CONTACTJID)) + ).toString(); + } catch (InvalidJidException ignored) { + Log.e(Config.LOGTAG, "Failed to migrate Conversation CONTACTJID " + +cursor.getString(cursor.getColumnIndex(Conversation.CONTACTJID)) + +": " + ignored +". Skipping..."); + continue; + } + + String updateArgs[] = { + newJid, + cursor.getString(cursor.getColumnIndex(Conversation.UUID)), + }; + db.execSQL("update " + Conversation.TABLENAME + + " set " + Conversation.CONTACTJID + " = ? " + + " where " + Conversation.UUID + " = ?", updateArgs); + } + cursor.close(); + + // Contact table + cursor = db.rawQuery("select * from " + Contact.TABLENAME, new String[0]); + while(cursor.moveToNext()) { + String newJid; + try { + newJid = Jid.fromString( + cursor.getString(cursor.getColumnIndex(Contact.JID)) + ).toString(); + } catch (InvalidJidException ignored) { + Log.e(Config.LOGTAG, "Failed to migrate Contact JID " + +cursor.getString(cursor.getColumnIndex(Contact.JID)) + +": " + ignored +". Skipping..."); + continue; + } + + String updateArgs[] = { + newJid, + cursor.getString(cursor.getColumnIndex(Contact.ACCOUNT)), + cursor.getString(cursor.getColumnIndex(Contact.JID)), + }; + db.execSQL("update " + Contact.TABLENAME + + " set " + Contact.JID + " = ? " + + " where " + Contact.ACCOUNT + " = ? " + + " AND " + Contact.JID + " = ?", updateArgs); + } + cursor.close(); + + // Account table + cursor = db.rawQuery("select * from " + Account.TABLENAME, new String[0]); + while(cursor.moveToNext()) { + String newServer; + try { + newServer = Jid.fromParts( + cursor.getString(cursor.getColumnIndex(Account.USERNAME)), + cursor.getString(cursor.getColumnIndex(Account.SERVER)), + "mobile" + ).getDomainpart(); + } catch (InvalidJidException ignored) { + Log.e(Config.LOGTAG, "Failed to migrate Account SERVER " + +cursor.getString(cursor.getColumnIndex(Account.SERVER)) + +": " + ignored +". Skipping..."); + continue; + } + + String updateArgs[] = { + newServer, + cursor.getString(cursor.getColumnIndex(Account.UUID)), + }; + db.execSQL("update " + Account.TABLENAME + + " set " + Account.SERVER + " = ? " + + " where " + Account.UUID + " = ?", updateArgs); + } + cursor.close(); + } } public static synchronized DatabaseBackend getInstance(Context context) { diff --git a/src/main/java/eu/siacs/conversations/xmpp/jid/Jid.java b/src/main/java/eu/siacs/conversations/xmpp/jid/Jid.java index 295e067a6..f989c0c25 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jid/Jid.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jid/Jid.java @@ -130,12 +130,19 @@ public final class Jid { if (resourcepart.isEmpty() || resourcepart.length() > 1023) { throw new InvalidJidException(InvalidJidException.INVALID_PART_LENGTH); } - dp = IDN.toUnicode(jid.substring(domainpartStart, slashLoc), IDN.USE_STD3_ASCII_RULES); + try { + dp = IDN.toUnicode(Stringprep.nameprep(jid.substring(domainpartStart, slashLoc)), IDN.USE_STD3_ASCII_RULES); + } catch (final StringprepException e) { + throw new InvalidJidException(InvalidJidException.STRINGPREP_FAIL, e); + } finaljid = finaljid + dp + "/" + rp; } else { resourcepart = ""; - dp = IDN.toUnicode(jid.substring(domainpartStart, jid.length()), - IDN.USE_STD3_ASCII_RULES); + try{ + dp = IDN.toUnicode(Stringprep.nameprep(jid.substring(domainpartStart, jid.length())), IDN.USE_STD3_ASCII_RULES); + } catch (final StringprepException e) { + throw new InvalidJidException(InvalidJidException.STRINGPREP_FAIL, e); + } finaljid = finaljid + dp; } -- cgit v1.2.3 From b6a7e56bf667cfc0845ca0d50d88a77c43d9a27d Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Fri, 15 May 2015 13:58:11 +0200 Subject: call StartConversationActivity in init mode only after adding the first account --- src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java | 4 +++- .../java/eu/siacs/conversations/ui/PublishProfilePictureActivity.java | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'src/main/java/eu/siacs') diff --git a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java index 7aa7b1c2e..931a1a2fa 100644 --- a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java @@ -223,7 +223,9 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate if (avatar != null) { intent = new Intent(getApplicationContext(), StartConversationActivity.class); - intent.putExtra("init",true); + if (xmppConnectionService != null && xmppConnectionService.getAccounts().size() == 1) { + intent.putExtra("init", true); + } } else { intent = new Intent(getApplicationContext(), PublishProfilePictureActivity.class); diff --git a/src/main/java/eu/siacs/conversations/ui/PublishProfilePictureActivity.java b/src/main/java/eu/siacs/conversations/ui/PublishProfilePictureActivity.java index e8ab8dae7..4333dbdb0 100644 --- a/src/main/java/eu/siacs/conversations/ui/PublishProfilePictureActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/PublishProfilePictureActivity.java @@ -116,7 +116,9 @@ public class PublishProfilePictureActivity extends XmppActivity { if (mInitialAccountSetup) { Intent intent = new Intent(getApplicationContext(), StartConversationActivity.class); - intent.putExtra("init",true); + if (xmppConnectionService != null && xmppConnectionService.getAccounts().size() == 1) { + intent.putExtra("init", true); + } startActivity(intent); } finish(); -- cgit v1.2.3 From 4151b72a6e68faff45e3d166823459eaa07c63a3 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Sat, 16 May 2015 04:12:53 +0200 Subject: let jingle connection and manager handle message status --- .../java/eu/siacs/conversations/services/XmppConnectionService.java | 4 ---- .../java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java | 4 ++++ .../eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java | 6 ++++++ 3 files changed, 10 insertions(+), 4 deletions(-) (limited to 'src/main/java/eu/siacs') diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index 4f2697a37..63d9ba7a8 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -349,7 +349,6 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa } message.setCounterpart(conversation.getNextCounterpart()); message.setType(Message.TYPE_FILE); - message.setStatus(Message.STATUS_OFFERED); String path = getFileBackend().getOriginalPath(uri); if (path!=null) { message.setRelativeFilePath(path); @@ -392,7 +391,6 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa } message.setCounterpart(conversation.getNextCounterpart()); message.setType(Message.TYPE_IMAGE); - message.setStatus(Message.STATUS_OFFERED); new Thread(new Runnable() { @Override @@ -813,7 +811,6 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa Presences presences = contact.getPresences(); if ((message.getCounterpart() != null) && (presences.has(message.getCounterpart().getResourcepart()))) { - markMessage(message, Message.STATUS_OFFERED); mJingleConnectionManager.createNewConnection(message); } else { if (presences.size() == 1) { @@ -823,7 +820,6 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa } catch (InvalidJidException e) { return; } - markMessage(message, Message.STATUS_OFFERED); mJingleConnectionManager.createNewConnection(message); } } diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java index 4847d5f12..6c42d3d2c 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java @@ -271,6 +271,9 @@ public class JingleConnection implements Downloadable { this.mergeCandidates(JingleCandidate.parse(content.socks5transport() .getChildren())); this.fileOffer = packet.getJingleContent().getFileOffer(); + + mXmppConnectionService.sendIqPacket(account,packet.generateResponse(IqPacket.TYPE.RESULT),null); + if (fileOffer != null) { Element fileSize = fileOffer.findChild("size"); Element fileNameElement = fileOffer.findChild("name"); @@ -381,6 +384,7 @@ public class JingleConnection implements Downloadable { @Override public void onIqPacketReceived(Account account, IqPacket packet) { if (packet.getType() != IqPacket.TYPE.ERROR) { + Log.d(Config.LOGTAG,account.getJid().toBareJid()+": other party received offer"); mJingleStatus = JINGLE_STATUS_INITIATED; mXmppConnectionService.markMessage(message, Message.STATUS_OFFERED); } else { diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java index 5dfa3ff40..c19dd04c7 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java @@ -9,6 +9,7 @@ import android.annotation.SuppressLint; import android.util.Log; import eu.siacs.conversations.Config; import eu.siacs.conversations.entities.Account; +import eu.siacs.conversations.entities.Downloadable; import eu.siacs.conversations.entities.Message; import eu.siacs.conversations.services.AbstractConnectionManager; import eu.siacs.conversations.services.XmppConnectionService; @@ -58,7 +59,12 @@ public class JingleConnectionManager extends AbstractConnectionManager { } public JingleConnection createNewConnection(Message message) { + Downloadable old = message.getDownloadable(); + if (old != null) { + old.cancel(); + } JingleConnection connection = new JingleConnection(this); + mXmppConnectionService.markMessage(message,Message.STATUS_WAITING); connection.init(message); this.connections.add(connection); return connection; -- cgit v1.2.3 From fce30f22c9c75fb4bc12992e6d7e7161ce5148b1 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Sat, 16 May 2015 12:49:04 +0200 Subject: made white space check in bodyContainsDownloadable less aggresive --- src/main/java/eu/siacs/conversations/entities/Message.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/main/java/eu/siacs') diff --git a/src/main/java/eu/siacs/conversations/entities/Message.java b/src/main/java/eu/siacs/conversations/entities/Message.java index a8bb9c557..38152edba 100644 --- a/src/main/java/eu/siacs/conversations/entities/Message.java +++ b/src/main/java/eu/siacs/conversations/entities/Message.java @@ -440,7 +440,7 @@ public class Message extends AbstractEntity { * "http://example.com/image.jpg text that will not be shown /abc.png" * or more than one image link in one message. */ - if (body.contains(" ")) { + if (body.trim().contains(" ")) { return false; } try { -- cgit v1.2.3 From d672d578c91f54e17b930c4a08d133095a863d52 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Sun, 17 May 2015 12:32:04 +0200 Subject: fixed crash on failed account registry --- src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/main/java/eu/siacs') diff --git a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java index 6c67c0726..b0d8272de 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java @@ -683,7 +683,7 @@ public class XmppConnection implements Runnable { disconnect(true); Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": could not register. instructions are" - + instructions != null ? instructions.getContent() : ""); + + (instructions != null ? instructions.getContent() : "")); } } }); -- cgit v1.2.3 From fbc43a8d38e62fc2a3b60e7c363c8fe1e2668cc6 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Mon, 18 May 2015 03:17:14 +0200 Subject: don't offer initiator his own candidates --- .../java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src/main/java/eu/siacs') diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java index 6c42d3d2c..c9bb9c93b 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java @@ -213,7 +213,7 @@ public class JingleConnection implements Downloadable { @Override public void onPrimaryCandidateFound(boolean success, - final JingleCandidate candidate) { + final JingleCandidate candidate) { if (success) { final JingleSocks5Transport socksConnection = new JingleSocks5Transport( JingleConnection.this, candidate); @@ -399,7 +399,9 @@ public class JingleConnection implements Downloadable { private List getCandidatesAsElements() { List elements = new ArrayList<>(); for (JingleCandidate c : this.candidates) { - elements.add(c.toElement()); + if (c.isOurs()) { + elements.add(c.toElement()); + } } return elements; } -- cgit v1.2.3 From 1446a59fa594be49277d1ec9d7fe023949bcfc55 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Mon, 18 May 2015 04:34:34 +0200 Subject: use a 20s timeout on socks5 connections --- src/main/java/eu/siacs/conversations/Config.java | 1 + .../eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java | 7 +++++-- 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'src/main/java/eu/siacs') diff --git a/src/main/java/eu/siacs/conversations/Config.java b/src/main/java/eu/siacs/conversations/Config.java index 9f5d14fde..050116b5a 100644 --- a/src/main/java/eu/siacs/conversations/Config.java +++ b/src/main/java/eu/siacs/conversations/Config.java @@ -11,6 +11,7 @@ public final class Config { public static final int PING_MAX_INTERVAL = 300; public static final int PING_MIN_INTERVAL = 30; public static final int PING_TIMEOUT = 10; + public static final int SOCKET_TIMEOUT = 20; public static final int CONNECT_TIMEOUT = 90; public static final int CARBON_GRACE_PERIOD = 60; public static final int MINI_GRACE_PERIOD = 750; diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java index 35375a5dc..8d74f44e3 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java @@ -6,7 +6,9 @@ import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.net.InetSocketAddress; import java.net.Socket; +import java.net.SocketAddress; import java.net.UnknownHostException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; @@ -56,8 +58,9 @@ public class JingleSocks5Transport extends JingleTransport { @Override public void run() { try { - socket = new Socket(candidate.getHost(), - candidate.getPort()); + socket = new Socket(); + SocketAddress address = new InetSocketAddress(candidate.getHost(),candidate.getPort()); + socket.connect(address,Config.SOCKET_TIMEOUT * 1000); inputStream = socket.getInputStream(); outputStream = socket.getOutputStream(); byte[] login = { 0x05, 0x01, 0x00 }; -- cgit v1.2.3 From a0575c81abf9b8b56a3b47753b373218a655c608 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Mon, 18 May 2015 08:48:08 +0200 Subject: use same socket time out for jingle and xmpp connections --- src/main/java/eu/siacs/conversations/Config.java | 2 +- src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src/main/java/eu/siacs') diff --git a/src/main/java/eu/siacs/conversations/Config.java b/src/main/java/eu/siacs/conversations/Config.java index 050116b5a..779cbbe86 100644 --- a/src/main/java/eu/siacs/conversations/Config.java +++ b/src/main/java/eu/siacs/conversations/Config.java @@ -11,7 +11,7 @@ public final class Config { public static final int PING_MAX_INTERVAL = 300; public static final int PING_MIN_INTERVAL = 30; public static final int PING_TIMEOUT = 10; - public static final int SOCKET_TIMEOUT = 20; + public static final int SOCKET_TIMEOUT = 15; public static final int CONNECT_TIMEOUT = 90; public static final int CARBON_GRACE_PERIOD = 60; public static final int MINI_GRACE_PERIOD = 750; diff --git a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java index b0d8272de..9bda3c096 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java @@ -187,7 +187,7 @@ public class XmppConnection implements Runnable { + srvRecordServer + ":" + srvRecordPort); } socket = new Socket(); - socket.connect(addr, 20000); + socket.connect(addr, Config.SOCKET_TIMEOUT * 1000); socketError = false; } catch (final UnknownHostException e) { Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": " + e.getMessage()); -- cgit v1.2.3 From bb603644880f0b32d8a7b54d5158f6fac678aa12 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Tue, 19 May 2015 08:31:56 +0200 Subject: hide block contact from context menu when server feature is not available fixed #1207 --- .../java/eu/siacs/conversations/ui/StartConversationActivity.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'src/main/java/eu/siacs') diff --git a/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java b/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java index a556b8b7f..7863ff945 100644 --- a/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java @@ -65,6 +65,7 @@ import eu.siacs.conversations.ui.adapter.KnownHostsAdapter; import eu.siacs.conversations.ui.adapter.ListItemAdapter; import eu.siacs.conversations.utils.XmppUri; import eu.siacs.conversations.xmpp.OnUpdateBlocklist; +import eu.siacs.conversations.xmpp.XmppConnection; import eu.siacs.conversations.xmpp.jid.InvalidJidException; import eu.siacs.conversations.xmpp.jid.Jid; @@ -757,14 +758,16 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU } else { activity.contact_context_id = acmi.position; final Blockable contact = (Contact) activity.contacts.get(acmi.position); - final MenuItem blockUnblockItem = menu.findItem(R.id.context_contact_block_unblock); - if (blockUnblockItem != null) { + XmppConnection xmpp = contact.getAccount().getXmppConnection(); + if (xmpp != null && xmpp.getFeatures().blocking()) { if (contact.isBlocked()) { blockUnblockItem.setTitle(R.string.unblock_contact); } else { blockUnblockItem.setTitle(R.string.block_contact); } + } else { + blockUnblockItem.setVisible(false); } } } -- cgit v1.2.3 From 73a4ffefdf470be517eb32bc43bb93c3dff72b38 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Wed, 20 May 2015 03:27:52 +0200 Subject: added fall back package id for voice recorder plugin --- src/main/java/eu/siacs/conversations/ui/ConversationActivity.java | 1 + 1 file changed, 1 insertion(+) (limited to 'src/main/java/eu/siacs') diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java index a2a405c36..1b5e51781 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java @@ -429,6 +429,7 @@ public class ConversationActivity extends XmppActivity break; case ATTACHMENT_CHOICE_RECORD_VOICE: intent.setAction(MediaStore.Audio.Media.RECORD_SOUND_ACTION); + fallbackPackageId = "eu.siacs.conversations.voicerecorder"; break; case ATTACHMENT_CHOICE_LOCATION: intent.setAction("eu.siacs.conversations.location.request"); -- cgit v1.2.3