diff options
Diffstat (limited to 'src/eu/siacs/conversations')
-rw-r--r-- | src/eu/siacs/conversations/entities/Contact.java | 8 | ||||
-rw-r--r-- | src/eu/siacs/conversations/entities/Message.java | 9 | ||||
-rw-r--r-- | src/eu/siacs/conversations/parser/MessageParser.java | 23 | ||||
-rw-r--r-- | src/eu/siacs/conversations/ui/ConversationActivity.java | 624 | ||||
-rw-r--r-- | src/eu/siacs/conversations/ui/ConversationFragment.java | 62 | ||||
-rw-r--r-- | src/eu/siacs/conversations/utils/UIHelper.java | 13 |
6 files changed, 444 insertions, 295 deletions
diff --git a/src/eu/siacs/conversations/entities/Contact.java b/src/eu/siacs/conversations/entities/Contact.java index cff0dd73..8f4b6193 100644 --- a/src/eu/siacs/conversations/entities/Contact.java +++ b/src/eu/siacs/conversations/entities/Contact.java @@ -11,7 +11,6 @@ import org.json.JSONObject; import eu.siacs.conversations.xml.Element; import android.content.ContentValues; import android.database.Cursor; -import android.util.Log; public class Contact { public static final String TABLENAME = "contacts"; @@ -38,6 +37,8 @@ public class Contact { protected Account account; protected boolean inRoster = true; + + public Lastseen lastseen = new Lastseen(); public Contact(String account, String systemName, String serverName, String jid, int subscription, String photoUri, @@ -305,4 +306,9 @@ public class Contact { public static final int DIRTY_PUSH = 6; public static final int DIRTY_DELETE = 7; } + + public class Lastseen { + public long time = 0; + public String presence = null; + } } diff --git a/src/eu/siacs/conversations/entities/Message.java b/src/eu/siacs/conversations/entities/Message.java index cc6bc7c2..c298a652 100644 --- a/src/eu/siacs/conversations/entities/Message.java +++ b/src/eu/siacs/conversations/entities/Message.java @@ -203,6 +203,15 @@ public class Message extends AbstractEntity { this.counterpart = this.counterpart.split("/")[0] + "/" + presence; } + public String getPresence() { + String[] counterparts = this.counterpart.split("/"); + if (counterparts.length == 2) { + return counterparts[1]; + } else { + return null; + } + } + public void setJingleConnection(JingleConnection connection) { this.jingleConnection = connection; } diff --git a/src/eu/siacs/conversations/parser/MessageParser.java b/src/eu/siacs/conversations/parser/MessageParser.java index 8e099728..ab75d676 100644 --- a/src/eu/siacs/conversations/parser/MessageParser.java +++ b/src/eu/siacs/conversations/parser/MessageParser.java @@ -6,6 +6,7 @@ import net.java.otr4j.session.Session; import net.java.otr4j.session.SessionStatus; import android.util.Log; 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.services.XmppConnectionService; @@ -26,6 +27,7 @@ public class MessageParser { Conversation conversation = mXmppConnectionService .findOrCreateConversation(account, fromParts[0], false); conversation.setLatestMarkableMessageId(getMarkableMessageId(packet)); + updateLastseen(packet, account); String pgpBody = getPgpBody(packet); if (pgpBody != null) { return new Message(conversation, packet.getFrom(), pgpBody, @@ -43,6 +45,7 @@ public class MessageParser { String[] fromParts = packet.getFrom().split("/"); Conversation conversation = mXmppConnectionService .findOrCreateConversation(account, fromParts[0], false); + updateLastseen(packet, account); String body = packet.getBody(); if (!conversation.hasValidOtrSession()) { if (properlyAddressed) { @@ -171,6 +174,7 @@ public class MessageParser { return null; // either malformed or boring if (status == Message.STATUS_RECIEVED) { fullJid = message.getAttribute("from"); + updateLastseen(message, account); } else { fullJid = message.getAttribute("to"); } @@ -211,4 +215,23 @@ public class MessageParser { return null; } } + + private void updateLastseen(Element message, Account account) { + String[] fromParts = message.getAttribute("from").split("/"); + String from = fromParts[0]; + String presence = null; + if (fromParts.length >= 2) { + presence = fromParts[1]; + } + Contact contact = account.getRoster().getContact(from); + if (presence!=null) { + contact.lastseen.presence = presence; + contact.lastseen.time = System.currentTimeMillis(); + } else if ((contact.getPresences().size() == 1)&&(contact.getPresences().containsKey(contact.lastseen.presence))) { + contact.lastseen.time = System.currentTimeMillis(); + } else { + contact.lastseen.presence = null; + contact.lastseen.time = System.currentTimeMillis(); + } + } } diff --git a/src/eu/siacs/conversations/ui/ConversationActivity.java b/src/eu/siacs/conversations/ui/ConversationActivity.java index 45a0d632..55c538d6 100644 --- a/src/eu/siacs/conversations/ui/ConversationActivity.java +++ b/src/eu/siacs/conversations/ui/ConversationActivity.java @@ -69,7 +69,7 @@ public class ConversationActivity extends XmppActivity { private static final int REQUEST_RECORD_AUDIO = 0x46189; private static final int REQUEST_SEND_PGP_IMAGE = 0x53883; public static final int REQUEST_ENCRYPT_MESSAGE = 0x378018; - + private static final int ATTACHMENT_CHOICE_CHOOSE_IMAGE = 0x92734; private static final int ATTACHMENT_CHOICE_TAKE_PHOTO = 0x84123; private static final int ATTACHMENT_CHOICE_RECORD_VOICE = 0x75291; @@ -79,11 +79,12 @@ public class ConversationActivity extends XmppActivity { private List<Conversation> conversationList = new ArrayList<Conversation>(); private Conversation selectedConversation = null; private ListView listView; - + private boolean paneShouldBeOpen = true; private boolean useSubject = true; + private boolean showLastseen = false; private ArrayAdapter<Conversation> listAdapter; - + public Message pendingMessage = null; private OnConversationListChangedListener onConvChanged = new OnConversationListChangedListener() { @@ -113,7 +114,7 @@ public class ConversationActivity extends XmppActivity { }); } }; - + protected ConversationActivity activity = this; private DisplayMetrics metrics; private Toast prepareImageToast; @@ -125,7 +126,7 @@ public class ConversationActivity extends XmppActivity { public Conversation getSelectedConversation() { return this.selectedConversation; } - + public void setSelectedConversation(Conversation conversation) { this.selectedConversation = conversation; } @@ -146,7 +147,7 @@ public class ConversationActivity extends XmppActivity { protected void onCreate(Bundle savedInstanceState) { metrics = getResources().getDisplayMetrics(); - + super.onCreate(savedInstanceState); setContentView(R.layout.fragment_conversations_overview); @@ -182,15 +183,18 @@ public class ConversationActivity extends XmppActivity { convName.setText(conv.getName(useSubject)); TextView convLastMsg = (TextView) view .findViewById(R.id.conversation_lastmsg); - ImageView imagePreview = (ImageView) view.findViewById(R.id.conversation_lastimage); - + ImageView imagePreview = (ImageView) view + .findViewById(R.id.conversation_lastimage); + Message latestMessage = conv.getLatestMessage(); - + if (latestMessage.getType() == Message.TYPE_TEXT) { - if ((latestMessage.getEncryption() != Message.ENCRYPTION_PGP)&&(latestMessage.getEncryption() != Message.ENCRYPTION_DECRYPTION_FAILED)) { + if ((latestMessage.getEncryption() != Message.ENCRYPTION_PGP) + && (latestMessage.getEncryption() != Message.ENCRYPTION_DECRYPTION_FAILED)) { convLastMsg.setText(conv.getLatestMessage().getBody()); } else { - convLastMsg.setText(getText(R.string.encrypted_message_received)); + convLastMsg + .setText(getText(R.string.encrypted_message_received)); } convLastMsg.setVisibility(View.VISIBLE); imagePreview.setVisibility(View.GONE); @@ -203,16 +207,16 @@ public class ConversationActivity extends XmppActivity { convLastMsg.setVisibility(View.VISIBLE); imagePreview.setVisibility(View.GONE); if (latestMessage.getStatus() == Message.STATUS_RECEIVED_OFFER) { - convLastMsg.setText(getText(R.string.image_offered_for_download)); + convLastMsg + .setText(getText(R.string.image_offered_for_download)); } else if (latestMessage.getStatus() == Message.STATUS_RECIEVING) { - convLastMsg.setText(getText(R.string.receiving_image)); + convLastMsg + .setText(getText(R.string.receiving_image)); } else { convLastMsg.setText(""); } } } - - if (!conv.isRead()) { convName.setTypeface(null, Typeface.BOLD); @@ -223,14 +227,14 @@ public class ConversationActivity extends XmppActivity { } ((TextView) view.findViewById(R.id.conversation_lastupdate)) - .setText(UIHelper.readableTimeDifference(getContext(), conv - .getLatestMessage().getTimeSent())); + .setText(UIHelper.readableTimeDifference(getContext(), + conv.getLatestMessage().getTimeSent())); ImageView profilePicture = (ImageView) view .findViewById(R.id.conversation_image); - profilePicture.setImageBitmap(UIHelper.getContactPicture( - conv, 56, activity.getApplicationContext(), false)); - + profilePicture.setImageBitmap(UIHelper.getContactPicture(conv, + 56, activity.getApplicationContext(), false)); + return view; } @@ -266,6 +270,11 @@ public class ConversationActivity extends XmppActivity { getActionBar().setTitle(R.string.app_name); invalidateOptionsMenu(); hideKeyboard(); + ConversationFragment selectedFragment = (ConversationFragment) getFragmentManager() + .findFragmentByTag("conversation"); + if (selectedFragment != null) { + selectedFragment.lastSeen.setVisibility(View.GONE); + } } @Override @@ -279,11 +288,17 @@ public class ConversationActivity extends XmppActivity { getSelectedConversation().getName(useSubject)); invalidateOptionsMenu(); if (!getSelectedConversation().isRead()) { - xmppConnectionService.markRead(getSelectedConversation()); + xmppConnectionService + .markRead(getSelectedConversation()); UIHelper.updateNotification(getApplicationContext(), getConversationList(), null, false); listView.invalidateViews(); } + ConversationFragment selectedFragment = (ConversationFragment) getFragmentManager() + .findFragmentByTag("conversation"); + if ((selectedFragment != null) && (showLastseen())) { + selectedFragment.lastSeen.setVisibility(View.VISIBLE); + } } } @@ -307,7 +322,8 @@ public class ConversationActivity extends XmppActivity { MenuItem menuInviteContacts = (MenuItem) menu .findItem(R.id.action_invite); MenuItem menuAttach = (MenuItem) menu.findItem(R.id.action_attach_file); - MenuItem menuClearHistory = (MenuItem) menu.findItem(R.id.action_clear_history); + MenuItem menuClearHistory = (MenuItem) menu + .findItem(R.id.action_clear_history); if ((spl.isOpen() && (spl.isSlideable()))) { menuArchive.setVisible(false); @@ -336,27 +352,34 @@ public class ConversationActivity extends XmppActivity { } return true; } - + private void selectPresenceToAttachFile(final int attachmentChoice) { selectPresence(getSelectedConversation(), new OnPresenceSelected() { - + @Override public void onPresenceSelected(boolean success, String presence) { if (success) { - if (attachmentChoice==ATTACHMENT_CHOICE_TAKE_PHOTO) { - Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); - takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, ImageProvider.getIncomingContentUri()); - if (takePictureIntent.resolveActivity(getPackageManager()) != null) { - startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE); + if (attachmentChoice == ATTACHMENT_CHOICE_TAKE_PHOTO) { + Intent takePictureIntent = new Intent( + MediaStore.ACTION_IMAGE_CAPTURE); + takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, + ImageProvider.getIncomingContentUri()); + if (takePictureIntent + .resolveActivity(getPackageManager()) != null) { + startActivityForResult(takePictureIntent, + REQUEST_IMAGE_CAPTURE); } - } else if (attachmentChoice==ATTACHMENT_CHOICE_CHOOSE_IMAGE) { + } else if (attachmentChoice == ATTACHMENT_CHOICE_CHOOSE_IMAGE) { Intent attachFileIntent = new Intent(); attachFileIntent.setType("image/*"); attachFileIntent.setAction(Intent.ACTION_GET_CONTENT); - Intent chooser = Intent.createChooser(attachFileIntent, getString(R.string.attach_file)); - startActivityForResult(chooser, REQUEST_ATTACH_FILE_DIALOG); - } else if (attachmentChoice==ATTACHMENT_CHOICE_RECORD_VOICE) { - Intent intent = new Intent(MediaStore.Audio.Media.RECORD_SOUND_ACTION); + Intent chooser = Intent.createChooser(attachFileIntent, + getString(R.string.attach_file)); + startActivityForResult(chooser, + REQUEST_ATTACH_FILE_DIALOG); + } else if (attachmentChoice == ATTACHMENT_CHOICE_RECORD_VOICE) { + Intent intent = new Intent( + MediaStore.Audio.Media.RECORD_SOUND_ACTION); startActivityForResult(intent, REQUEST_RECORD_AUDIO); } } @@ -365,45 +388,50 @@ public class ConversationActivity extends XmppActivity { @Override public void onSendPlainTextInstead() { // TODO Auto-generated method stub - + } - },"file"); + }, "file"); } private void attachFile(final int attachmentChoice) { final Conversation conversation = getSelectedConversation(); if (conversation.getNextEncryption() == Message.ENCRYPTION_PGP) { if (hasPgp()) { - if (conversation.getContact().getPgpKeyId()!=0) { - xmppConnectionService.getPgpEngine().hasKey(conversation.getContact(), new UiCallback() { - - @Override - public void userInputRequried(PendingIntent pi) { - ConversationActivity.this.runIntent(pi, attachmentChoice); - } - - @Override - public void success() { - selectPresenceToAttachFile(attachmentChoice); - } - - @Override - public void error(int error) { - displayErrorDialog(error); - } - }); + if (conversation.getContact().getPgpKeyId() != 0) { + xmppConnectionService.getPgpEngine().hasKey( + conversation.getContact(), new UiCallback() { + + @Override + public void userInputRequried(PendingIntent pi) { + ConversationActivity.this.runIntent(pi, + attachmentChoice); + } + + @Override + public void success() { + selectPresenceToAttachFile(attachmentChoice); + } + + @Override + public void error(int error) { + displayErrorDialog(error); + } + }); } else { final ConversationFragment fragment = (ConversationFragment) getFragmentManager() .findFragmentByTag("conversation"); if (fragment != null) { - fragment.showNoPGPKeyDialog(false,new OnClickListener() { - - @Override - public void onClick(DialogInterface dialog, int which) { - conversation.setNextEncryption(Message.ENCRYPTION_NONE); - selectPresenceToAttachFile(attachmentChoice); - } - }); + fragment.showNoPGPKeyDialog(false, + new OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, + int which) { + conversation + .setNextEncryption(Message.ENCRYPTION_NONE); + selectPresenceToAttachFile(attachmentChoice); + } + }); } } } @@ -414,29 +442,36 @@ public class ConversationActivity extends XmppActivity { builder.setTitle(getString(R.string.otr_file_transfer)); builder.setMessage(getString(R.string.otr_file_transfer_msg)); builder.setNegativeButton(getString(R.string.cancel), null); - if (conversation.getContact().getPgpKeyId()==0) { - builder.setPositiveButton(getString(R.string.send_unencrypted), new OnClickListener() { - - @Override - public void onClick(DialogInterface dialog, int which) { - conversation.setNextEncryption(Message.ENCRYPTION_NONE); - attachFile(attachmentChoice); - } - }); + if (conversation.getContact().getPgpKeyId() == 0) { + builder.setPositiveButton(getString(R.string.send_unencrypted), + new OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, + int which) { + conversation + .setNextEncryption(Message.ENCRYPTION_NONE); + attachFile(attachmentChoice); + } + }); } else { - builder.setPositiveButton(getString(R.string.use_pgp_encryption), new OnClickListener() { - - @Override - public void onClick(DialogInterface dialog, int which) { - conversation.setNextEncryption(Message.ENCRYPTION_PGP); - attachFile(attachmentChoice); - } - }); + builder.setPositiveButton( + getString(R.string.use_pgp_encryption), + new OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, + int which) { + conversation + .setNextEncryption(Message.ENCRYPTION_PGP); + attachFile(attachmentChoice); + } + }); } builder.create().show(); } } - + @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { @@ -447,24 +482,25 @@ public class ConversationActivity extends XmppActivity { View menuAttachFile = findViewById(R.id.action_attach_file); PopupMenu attachFilePopup = new PopupMenu(this, menuAttachFile); attachFilePopup.inflate(R.menu.attachment_choices); - attachFilePopup.setOnMenuItemClickListener(new OnMenuItemClickListener() { - - @Override - public boolean onMenuItemClick(MenuItem item) { - switch (item.getItemId()) { - case R.id.attach_choose_picture: - attachFile(ATTACHMENT_CHOICE_CHOOSE_IMAGE); - break; - case R.id.attach_take_picture: - attachFile(ATTACHMENT_CHOICE_TAKE_PHOTO); - break; - case R.id.attach_record_voice: - attachFile(ATTACHMENT_CHOICE_RECORD_VOICE); - break; - } - return false; - } - }); + attachFilePopup + .setOnMenuItemClickListener(new OnMenuItemClickListener() { + + @Override + public boolean onMenuItemClick(MenuItem item) { + switch (item.getItemId()) { + case R.id.attach_choose_picture: + attachFile(ATTACHMENT_CHOICE_CHOOSE_IMAGE); + break; + case R.id.attach_take_picture: + attachFile(ATTACHMENT_CHOICE_TAKE_PHOTO); + break; + case R.id.attach_record_voice: + attachFile(ATTACHMENT_CHOICE_RECORD_VOICE); + break; + } + return false; + } + }); attachFilePopup.show(); break; case R.id.action_add: @@ -478,8 +514,9 @@ public class ConversationActivity extends XmppActivity { if (contact.showInRoster()) { Intent intent = new Intent(this, ContactDetailsActivity.class); intent.setAction(ContactDetailsActivity.ACTION_VIEW_CONTACT); - intent.putExtra("account", this.getSelectedConversation().getAccount().getJid()); - intent.putExtra("contact",contact.getJid()); + intent.putExtra("account", this.getSelectedConversation() + .getAccount().getJid()); + intent.putExtra("contact", contact.getJid()); startActivity(intent); } else { showAddToRosterDialog(getSelectedConversation()); @@ -511,25 +548,31 @@ public class ConversationActivity extends XmppActivity { public boolean onMenuItemClick(MenuItem item) { switch (item.getItemId()) { case R.id.encryption_choice_none: - conversation.setNextEncryption(Message.ENCRYPTION_NONE); + conversation + .setNextEncryption(Message.ENCRYPTION_NONE); item.setChecked(true); break; case R.id.encryption_choice_otr: - conversation.setNextEncryption(Message.ENCRYPTION_OTR); + conversation + .setNextEncryption(Message.ENCRYPTION_OTR); item.setChecked(true); break; case R.id.encryption_choice_pgp: if (hasPgp()) { - if (conversation.getAccount().getKeys().has("pgp_signature")) { - conversation.setNextEncryption(Message.ENCRYPTION_PGP); + if (conversation.getAccount().getKeys() + .has("pgp_signature")) { + conversation + .setNextEncryption(Message.ENCRYPTION_PGP); item.setChecked(true); } else { - announcePgp(conversation.getAccount(),conversation); + announcePgp(conversation.getAccount(), + conversation); } } break; default: - conversation.setNextEncryption(Message.ENCRYPTION_NONE); + conversation + .setNextEncryption(Message.ENCRYPTION_NONE); break; } fragment.updateChatMsgHint(); @@ -537,7 +580,8 @@ public class ConversationActivity extends XmppActivity { } }); popup.inflate(R.menu.encryption_choices); - MenuItem otr = popup.getMenu().findItem(R.id.encryption_choice_otr); + MenuItem otr = popup.getMenu().findItem( + R.id.encryption_choice_otr); if (conversation.getMode() == Conversation.MODE_MULTI) { otr.setEnabled(false); } @@ -570,7 +614,7 @@ public class ConversationActivity extends XmppActivity { } return super.onOptionsItemSelected(item); } - + private void endConversation(Conversation conversation) { conversation.setStatus(Conversation.STATUS_ARCHIVED); paneShouldBeOpen = true; @@ -586,20 +630,24 @@ public class ConversationActivity extends XmppActivity { protected void clearHistoryDialog(final Conversation conversation) { AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle(getString(R.string.clear_conversation_history)); - View dialogView = getLayoutInflater().inflate(R.layout.dialog_clear_history, null); - final CheckBox endConversationCheckBox = (CheckBox) dialogView.findViewById(R.id.end_conversation_checkbox); + View dialogView = getLayoutInflater().inflate( + R.layout.dialog_clear_history, null); + final CheckBox endConversationCheckBox = (CheckBox) dialogView + .findViewById(R.id.end_conversation_checkbox); builder.setView(dialogView); builder.setNegativeButton(getString(R.string.cancel), null); - builder.setPositiveButton(getString(R.string.delete_messages), new OnClickListener() { - - @Override - public void onClick(DialogInterface dialog, int which) { - activity.xmppConnectionService.clearConversationHistory(conversation); - if (endConversationCheckBox.isChecked()) { - endConversation(conversation); - } - } - }); + builder.setPositiveButton(getString(R.string.delete_messages), + new OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, int which) { + activity.xmppConnectionService + .clearConversationHistory(conversation); + if (endConversationCheckBox.isChecked()) { + endConversation(conversation); + } + } + }); builder.create().show(); } @@ -626,10 +674,10 @@ public class ConversationActivity extends XmppActivity { } @Override - protected void onNewIntent (Intent intent) { - if ((Intent.ACTION_VIEW.equals(intent.getAction())&&(VIEW_CONVERSATION.equals(intent.getType())))) { - String convToView = (String) intent.getExtras().get( - CONVERSATION); + protected void onNewIntent(Intent intent) { + if ((Intent.ACTION_VIEW.equals(intent.getAction()) && (VIEW_CONVERSATION + .equals(intent.getType())))) { + String convToView = (String) intent.getExtras().get(CONVERSATION); updateConversationList(); for (int i = 0; i < conversationList.size(); ++i) { if (conversationList.get(i).getUuid().equals(convToView)) { @@ -642,13 +690,14 @@ public class ConversationActivity extends XmppActivity { swapConversationFragment().setText(text); } } - + @Override public void onStart() { super.onStart(); SharedPreferences preferences = PreferenceManager .getDefaultSharedPreferences(this); this.useSubject = preferences.getBoolean("use_subject_in_muc", true); + this.showLastseen = preferences.getBoolean("show_last_seen", false); if (this.xmppConnectionServiceBound) { this.onBackendConnected(); } @@ -722,7 +771,8 @@ public class ConversationActivity extends XmppActivity { } @Override - protected void onActivityResult(int requestCode, int resultCode, final Intent data) { + protected void onActivityResult(int requestCode, int resultCode, + final Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode == RESULT_OK) { if (requestCode == REQUEST_DECRYPT_PGP) { @@ -732,62 +782,68 @@ public class ConversationActivity extends XmppActivity { selectedFragment.hidePgpPassphraseBox(); } } else if (requestCode == REQUEST_ATTACH_FILE_DIALOG) { - attachImageToConversation(getSelectedConversation(),data.getData()); + attachImageToConversation(getSelectedConversation(), + data.getData()); } else if (requestCode == REQUEST_SEND_PGP_IMAGE) { - + } else if (requestCode == ATTACHMENT_CHOICE_CHOOSE_IMAGE) { attachFile(ATTACHMENT_CHOICE_CHOOSE_IMAGE); } else if (requestCode == ATTACHMENT_CHOICE_TAKE_PHOTO) { attachFile(ATTACHMENT_CHOICE_TAKE_PHOTO); } else if (requestCode == REQUEST_ANNOUNCE_PGP) { - announcePgp(getSelectedConversation().getAccount(),getSelectedConversation()); + announcePgp(getSelectedConversation().getAccount(), + getSelectedConversation()); } else if (requestCode == REQUEST_ENCRYPT_MESSAGE) { encryptTextMessage(); } else if (requestCode == REQUEST_IMAGE_CAPTURE) { attachImageToConversation(getSelectedConversation(), null); } else if (requestCode == REQUEST_RECORD_AUDIO) { - Log.d("xmppService",data.getData().toString()); - attachAudioToConversation(getSelectedConversation(),data.getData()); + Log.d("xmppService", data.getData().toString()); + attachAudioToConversation(getSelectedConversation(), + data.getData()); } else { - Log.d(LOGTAG,"unknown result code:"+requestCode); + Log.d(LOGTAG, "unknown result code:" + requestCode); } } } - + private void attachAudioToConversation(Conversation conversation, Uri uri) { - + } private void attachImageToConversation(Conversation conversation, Uri uri) { - prepareImageToast = Toast.makeText(getApplicationContext(), getText(R.string.preparing_image), Toast.LENGTH_LONG); + prepareImageToast = Toast.makeText(getApplicationContext(), + getText(R.string.preparing_image), Toast.LENGTH_LONG); prepareImageToast.show(); - pendingMessage = xmppConnectionService.attachImageToConversation(conversation, uri, new UiCallback() { - - @Override - public void userInputRequried(PendingIntent pi) { - hidePrepareImageToast(); - ConversationActivity.this.runIntent(pi, ConversationActivity.REQUEST_SEND_PGP_IMAGE); - } - - @Override - public void success() { - sendPendingImageMessage(); - hidePrepareImageToast(); - } - - @Override - public void error(int error) { - hidePrepareImageToast(); - pendingMessage = null; - displayErrorDialog(error); - } - }); + pendingMessage = xmppConnectionService.attachImageToConversation( + conversation, uri, new UiCallback() { + + @Override + public void userInputRequried(PendingIntent pi) { + hidePrepareImageToast(); + ConversationActivity.this.runIntent(pi, + ConversationActivity.REQUEST_SEND_PGP_IMAGE); + } + + @Override + public void success() { + sendPendingImageMessage(); + hidePrepareImageToast(); + } + + @Override + public void error(int error) { + hidePrepareImageToast(); + pendingMessage = null; + displayErrorDialog(error); + } + }); } - + private void hidePrepareImageToast() { - if (prepareImageToast!=null) { + if (prepareImageToast != null) { runOnUiThread(new Runnable() { - + @Override public void run() { prepareImageToast.cancel(); @@ -803,41 +859,46 @@ public class ConversationActivity extends XmppActivity { xmppConnectionService.updateUi(pendingMessage.getConversation(), false); pendingMessage = null; } - + public void updateConversationList() { conversationList.clear(); conversationList.addAll(xmppConnectionService.getConversations()); listView.invalidateViews(); } - - public void selectPresence(final Conversation conversation, final OnPresenceSelected listener, String reason) { + + public void selectPresence(final Conversation conversation, + final OnPresenceSelected listener, String reason) { Account account = conversation.getAccount(); if (account.getStatus() != Account.STATUS_ONLINE) { AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle(getString(R.string.not_connected)); builder.setIconAttribute(android.R.attr.alertDialogIcon); if ("otr".equals(reason)) { - builder.setMessage(getString(R.string.you_are_offline,getString(R.string.otr_messages))); + builder.setMessage(getString(R.string.you_are_offline, + getString(R.string.otr_messages))); } else if ("file".equals(reason)) { - builder.setMessage(getString(R.string.you_are_offline,getString(R.string.files))); + builder.setMessage(getString(R.string.you_are_offline, + getString(R.string.files))); } else { builder.setMessage(getString(R.string.you_are_offline_blank)); } builder.setNegativeButton(getString(R.string.cancel), null); - builder.setPositiveButton(getString(R.string.manage_account), new OnClickListener() { - - @Override - public void onClick(DialogInterface dialog, int which) { - startActivity(new Intent(activity, ManageAccountActivity.class)); - } - }); + builder.setPositiveButton(getString(R.string.manage_account), + new OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, int which) { + startActivity(new Intent(activity, + ManageAccountActivity.class)); + } + }); builder.create().show(); listener.onPresenceSelected(false, null); } else { Contact contact = conversation.getContact(); - if (contact==null) { + if (contact == null) { showAddToRosterDialog(conversation); - listener.onPresenceSelected(false,null); + listener.onPresenceSelected(false, null); } else { Hashtable<String, Integer> presences = contact.getPresences(); if (presences.size() == 0) { @@ -845,13 +906,16 @@ public class ConversationActivity extends XmppActivity { builder.setTitle(getString(R.string.contact_offline)); if ("otr".equals(reason)) { builder.setMessage(getString(R.string.contact_offline_otr)); - builder.setPositiveButton(getString(R.string.send_unencrypted), new OnClickListener() { - - @Override - public void onClick(DialogInterface dialog, int which) { - listener.onSendPlainTextInstead(); - } - }); + builder.setPositiveButton( + getString(R.string.send_unencrypted), + new OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, + int which) { + listener.onSendPlainTextInstead(); + } + }); } else if ("file".equals(reason)) { builder.setMessage(getString(R.string.contact_offline_file)); } @@ -870,13 +934,13 @@ public class ConversationActivity extends XmppActivity { presences.keySet().toArray(presencesArray); builder.setItems(presencesArray, new DialogInterface.OnClickListener() { - + @Override public void onClick(DialogInterface dialog, int which) { String presence = presencesArray[which]; conversation.setNextPresence(presence); - listener.onPresenceSelected(true,presence); + listener.onPresenceSelected(true, presence); } }); builder.create().show(); @@ -884,137 +948,149 @@ public class ConversationActivity extends XmppActivity { } } } - + + public boolean showLastseen() { + if (getSelectedConversation() == null) { + return false; + } else { + return this.showLastseen + && getSelectedConversation().getMode() == Conversation.MODE_SINGLE; + } + } + private void showAddToRosterDialog(final Conversation conversation) { String jid = conversation.getContactJid(); AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle(jid); builder.setMessage(getString(R.string.not_in_roster)); builder.setNegativeButton(getString(R.string.cancel), null); - builder.setPositiveButton(getString(R.string.add_contact), new DialogInterface.OnClickListener() { + builder.setPositiveButton(getString(R.string.add_contact), + new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - String jid = conversation.getContactJid(); - Account account = getSelectedConversation().getAccount(); - Contact contact = account.getRoster().getContact(jid); - xmppConnectionService.createContact(contact); - } - }); + @Override + public void onClick(DialogInterface dialog, int which) { + String jid = conversation.getContactJid(); + Account account = getSelectedConversation() + .getAccount(); + Contact contact = account.getRoster().getContact(jid); + xmppConnectionService.createContact(contact); + } + }); builder.create().show(); } - + public void runIntent(PendingIntent pi, int requestCode) { try { - this.startIntentSenderForResult(pi.getIntentSender(),requestCode, null, 0, - 0, 0); + this.startIntentSenderForResult(pi.getIntentSender(), requestCode, + null, 0, 0, 0); } catch (SendIntentException e1) { - Log.d("xmppService","failed to start intent to send message"); + Log.d("xmppService", "failed to start intent to send message"); } } - - + class BitmapWorkerTask extends AsyncTask<Message, Void, Bitmap> { - private final WeakReference<ImageView> imageViewReference; - private Message message = null; - - public BitmapWorkerTask(ImageView imageView) { - imageViewReference = new WeakReference<ImageView>(imageView); - } - - @Override - protected Bitmap doInBackground(Message... params) { - message = params[0]; - try { - return xmppConnectionService.getFileBackend().getThumbnail(message, (int) (metrics.density * 288),false); + private final WeakReference<ImageView> imageViewReference; + private Message message = null; + + public BitmapWorkerTask(ImageView imageView) { + imageViewReference = new WeakReference<ImageView>(imageView); + } + + @Override + protected Bitmap doInBackground(Message... params) { + message = params[0]; + try { + return xmppConnectionService.getFileBackend().getThumbnail( + message, (int) (metrics.density * 288), false); } catch (FileNotFoundException e) { - Log.d("xmppService","file not found!"); + Log.d("xmppService", "file not found!"); return null; } - } - - @Override - protected void onPostExecute(Bitmap bitmap) { - if (imageViewReference != null && bitmap != null) { - final ImageView imageView = imageViewReference.get(); - if (imageView != null) { - imageView.setImageBitmap(bitmap); - imageView.setBackgroundColor(0x00000000); - } - } - } + } + + @Override + protected void onPostExecute(Bitmap bitmap) { + if (imageViewReference != null && bitmap != null) { + final ImageView imageView = imageViewReference.get(); + if (imageView != null) { + imageView.setImageBitmap(bitmap); + imageView.setBackgroundColor(0x00000000); + } + } + } } - + public void loadBitmap(Message message, ImageView imageView) { Bitmap bm; try { - bm = xmppConnectionService.getFileBackend().getThumbnail(message, (int) (metrics.density * 288), true); + bm = xmppConnectionService.getFileBackend().getThumbnail(message, + (int) (metrics.density * 288), true); } catch (FileNotFoundException e) { bm = null; } - if (bm!=null) { + if (bm != null) { imageView.setImageBitmap(bm); imageView.setBackgroundColor(0x00000000); } else { - if (cancelPotentialWork(message, imageView)) { - imageView.setBackgroundColor(0xff333333); - final BitmapWorkerTask task = new BitmapWorkerTask(imageView); - final AsyncDrawable asyncDrawable = - new AsyncDrawable(getResources(), null, task); - imageView.setImageDrawable(asyncDrawable); - task.execute(message); - } + if (cancelPotentialWork(message, imageView)) { + imageView.setBackgroundColor(0xff333333); + final BitmapWorkerTask task = new BitmapWorkerTask(imageView); + final AsyncDrawable asyncDrawable = new AsyncDrawable( + getResources(), null, task); + imageView.setImageDrawable(asyncDrawable); + task.execute(message); + } } } - - public static boolean cancelPotentialWork(Message message, ImageView imageView) { - final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView); - - if (bitmapWorkerTask != null) { - final Message oldMessage = bitmapWorkerTask.message; - if (oldMessage == null || message != oldMessage) { - bitmapWorkerTask.cancel(true); - } else { - return false; - } - } - return true; + + public static boolean cancelPotentialWork(Message message, + ImageView imageView) { + final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView); + + if (bitmapWorkerTask != null) { + final Message oldMessage = bitmapWorkerTask.message; + if (oldMessage == null || message != oldMessage) { + bitmapWorkerTask.cancel(true); + } else { + return false; + } + } + return true; } - + private static BitmapWorkerTask getBitmapWorkerTask(ImageView imageView) { - if (imageView != null) { - final Drawable drawable = imageView.getDrawable(); - if (drawable instanceof AsyncDrawable) { - final AsyncDrawable asyncDrawable = (AsyncDrawable) drawable; - return asyncDrawable.getBitmapWorkerTask(); - } - } - return null; + if (imageView != null) { + final Drawable drawable = imageView.getDrawable(); + if (drawable instanceof AsyncDrawable) { + final AsyncDrawable asyncDrawable = (AsyncDrawable) drawable; + return asyncDrawable.getBitmapWorkerTask(); + } + } + return null; } - + static class AsyncDrawable extends BitmapDrawable { - private final WeakReference<BitmapWorkerTask> bitmapWorkerTaskReference; - - public AsyncDrawable(Resources res, Bitmap bitmap, - BitmapWorkerTask bitmapWorkerTask) { - super(res, bitmap); - bitmapWorkerTaskReference = - new WeakReference<BitmapWorkerTask>(bitmapWorkerTask); - } - - public BitmapWorkerTask getBitmapWorkerTask() { - return bitmapWorkerTaskReference.get(); - } + private final WeakReference<BitmapWorkerTask> bitmapWorkerTaskReference; + + public AsyncDrawable(Resources res, Bitmap bitmap, + BitmapWorkerTask bitmapWorkerTask) { + super(res, bitmap); + bitmapWorkerTaskReference = new WeakReference<BitmapWorkerTask>( + bitmapWorkerTask); + } + + public BitmapWorkerTask getBitmapWorkerTask() { + return bitmapWorkerTaskReference.get(); + } } public void encryptTextMessage() { - xmppConnectionService.getPgpEngine().encrypt(this.pendingMessage, new UiCallback() { + xmppConnectionService.getPgpEngine().encrypt(this.pendingMessage, + new UiCallback() { @Override - public void userInputRequried( - PendingIntent pi) { - activity.runIntent( - pi, + public void userInputRequried(PendingIntent pi) { + activity.runIntent(pi, ConversationActivity.REQUEST_SEND_MESSAGE); } diff --git a/src/eu/siacs/conversations/ui/ConversationFragment.java b/src/eu/siacs/conversations/ui/ConversationFragment.java index 4a246492..6ca88008 100644 --- a/src/eu/siacs/conversations/ui/ConversationFragment.java +++ b/src/eu/siacs/conversations/ui/ConversationFragment.java @@ -107,7 +107,9 @@ public class ConversationFragment extends Fragment { private LinearLayout pgpInfo; private LinearLayout mucError; + public LinearLayout lastSeen; private TextView mucErrorText; + private TextView lastSeenText; private OnClickListener clickToMuc = new OnClickListener() { @Override @@ -161,6 +163,8 @@ public class ConversationFragment extends Fragment { mucError = (LinearLayout) view.findViewById(R.id.muc_error); mucError.setOnClickListener(clickToMuc); mucErrorText = (TextView) view.findViewById(R.id.muc_error_msg); + lastSeen = (LinearLayout) view.findViewById(R.id.last_seen); + lastSeenText = (TextView) view.findViewById(R.id.last_seen_text); messagesView = (ListView) view.findViewById(R.id.messages_view); @@ -181,7 +185,7 @@ public class ConversationFragment extends Fragment { public int getItemViewType(int position) { if (getItem(position).getType() == Message.TYPE_STATUS) { return STATUS; - } else if (getItem(position).getStatus() <= Message.STATUS_RECIEVED) { + } else if (getItem(position).getStatus() <= Message.STATUS_RECIEVED) { return RECIEVED; } else { return SENT; @@ -335,18 +339,21 @@ public class ConversationFragment extends Fragment { startActivity(intent); } }); - viewHolder.image.setOnLongClickListener(new OnLongClickListener() { - - @Override - public boolean onLongClick(View v) { - Intent shareIntent = new Intent(); - shareIntent.setAction(Intent.ACTION_SEND); - shareIntent.putExtra(Intent.EXTRA_STREAM, ImageProvider.getContentUri(message)); - shareIntent.setType("image/webp"); - startActivity(Intent.createChooser(shareIntent, getText(R.string.share_with))); - return true; - } - }); + viewHolder.image + .setOnLongClickListener(new OnLongClickListener() { + + @Override + public boolean onLongClick(View v) { + Intent shareIntent = new Intent(); + shareIntent.setAction(Intent.ACTION_SEND); + shareIntent.putExtra(Intent.EXTRA_STREAM, + ImageProvider.getContentUri(message)); + shareIntent.setType("image/webp"); + startActivity(Intent.createChooser(shareIntent, + getText(R.string.share_with))); + return true; + } + }); } @Override @@ -405,8 +412,8 @@ public class ConversationFragment extends Fragment { view.setTag(viewHolder); break; case STATUS: - view = (View) inflater.inflate( - R.layout.message_status, null); + view = (View) inflater.inflate(R.layout.message_status, + null); viewHolder.contact_picture = (ImageView) view .findViewById(R.id.message_photo); if (item.getConversation().getMode() == Conversation.MODE_SINGLE) { @@ -430,7 +437,7 @@ public class ConversationFragment extends Fragment { } else { viewHolder = (ViewHolder) view.getTag(); } - + if (type == STATUS) { return view; } @@ -577,7 +584,11 @@ public class ConversationFragment extends Fragment { activity.getActionBar().setTitle( conversation.getName(useSubject)); activity.invalidateOptionsMenu(); - + if (activity.showLastseen()) { + lastSeen.setVisibility(View.VISIBLE); + } + } else { + lastSeen.setVisibility(View.GONE); } } if (conversation.getMode() == Conversation.MODE_MULTI) { @@ -653,6 +664,16 @@ public class ConversationFragment extends Fragment { break; } } + if (activity.showLastseen()) { + Contact contact = conversation.getContact(); + if ((contact.lastseen.presence != null)&&(contact.lastseen.time != 0)) { + lastSeenText.setText(getString(R.string.last_seen, + UIHelper.lastseen(getActivity(), contact.lastseen.time), + contact.lastseen.presence)); + } else { + lastSeenText.setText(R.string.never_seen); + } + } this.messageList.clear(); this.messageList.addAll(this.conversation.getMessages()); updateStatusMessages(); @@ -685,15 +706,16 @@ public class ConversationFragment extends Fragment { } } } - + protected void updateStatusMessages() { if (conversation.getMode() == Conversation.MODE_SINGLE) { - for(int i = this.messageList.size() - 1; i >= 0; --i) { + for (int i = this.messageList.size() - 1; i >= 0; --i) { if (this.messageList.get(i).getStatus() == Message.STATUS_RECIEVED) { return; } else { if (this.messageList.get(i).getStatus() == Message.STATUS_SEND_DISPLAYED) { - this.messageList.add(i+1, Message.createStatusMessage(conversation)); + this.messageList.add(i + 1, + Message.createStatusMessage(conversation)); return; } } diff --git a/src/eu/siacs/conversations/utils/UIHelper.java b/src/eu/siacs/conversations/utils/UIHelper.java index 9737040b..15d98d85 100644 --- a/src/eu/siacs/conversations/utils/UIHelper.java +++ b/src/eu/siacs/conversations/utils/UIHelper.java @@ -70,6 +70,19 @@ public class UIHelper { return sdf.format(date); } } + + public static String lastseen(Context context, long time) { + long difference = (System.currentTimeMillis() - time) / 1000; + if (difference < 60) { + return context.getString(R.string.just_now); + } else if (difference < 60 * 60) { + return difference / 60 + " " + context.getString(R.string.mins); + } else if (difference < 60 * 60 * 24) { + return difference / (60 * 60)+ " " + context.getString(R.string.hours); + } else { + return "days"; + } + } public static int getRealPx(int dp, Context context) { final DisplayMetrics metrics = context.getResources().getDisplayMetrics(); |