ConversationFragment.java

  1package de.gultsch.chat.ui;
  2
  3import java.util.ArrayList;
  4import java.util.Hashtable;
  5import java.util.List;
  6import java.util.Set;
  7
  8import net.java.otr4j.OtrException;
  9import net.java.otr4j.session.SessionStatus;
 10
 11import de.gultsch.chat.R;
 12import de.gultsch.chat.entities.Contact;
 13import de.gultsch.chat.entities.Conversation;
 14import de.gultsch.chat.entities.Message;
 15import de.gultsch.chat.services.XmppConnectionService;
 16import de.gultsch.chat.utils.PhoneHelper;
 17import de.gultsch.chat.utils.UIHelper;
 18import android.app.AlertDialog;
 19import android.app.Fragment;
 20import android.content.DialogInterface;
 21import android.content.SharedPreferences;
 22import android.graphics.Typeface;
 23import android.net.Uri;
 24import android.os.Bundle;
 25import android.preference.PreferenceManager;
 26import android.view.LayoutInflater;
 27import android.view.View;
 28import android.view.View.OnClickListener;
 29import android.view.ViewGroup;
 30import android.widget.ArrayAdapter;
 31import android.widget.EditText;
 32import android.widget.LinearLayout;
 33import android.widget.ListView;
 34import android.widget.ImageButton;
 35import android.widget.ImageView;
 36import android.widget.TextView;
 37
 38public class ConversationFragment extends Fragment {
 39
 40	protected Conversation conversation;
 41	protected ListView messagesView;
 42	protected LayoutInflater inflater;
 43	protected List<Message> messageList = new ArrayList<Message>();
 44	protected ArrayAdapter<Message> messageListAdapter;
 45	protected Contact contact;
 46
 47	private EditText chatMsg;
 48
 49	private OnClickListener sendMsgListener = new OnClickListener() {
 50
 51		@Override
 52		public void onClick(View v) {
 53			ConversationActivity activity = (ConversationActivity) getActivity();
 54			final XmppConnectionService xmppService = activity.xmppConnectionService;
 55			if (chatMsg.getText().length() < 1)
 56				return;
 57			Message message = new Message(conversation, chatMsg.getText()
 58					.toString(), conversation.nextMessageEncryption);
 59			if (conversation.nextMessageEncryption == Message.ENCRYPTION_OTR) {
 60				sendOtrMessage(message);
 61			} else {
 62				sendPlainTextMessage(message);
 63			}
 64		}
 65	};
 66
 67	public void updateChatMsgHint() {
 68		if (conversation.getMode() == Conversation.MODE_MULTI) {
 69			chatMsg.setHint("Send message to conference");
 70		} else {
 71			switch (conversation.nextMessageEncryption) {
 72			case Message.ENCRYPTION_NONE:
 73				chatMsg.setHint("Send plain text message");
 74				break;
 75			case Message.ENCRYPTION_OTR:
 76				chatMsg.setHint("Send OTR encrypted message");
 77				break;
 78			case Message.ENCRYPTION_PGP:
 79				chatMsg.setHint("Send openPGP encryted messeage");
 80			default:
 81				break;
 82			}
 83		}
 84	}
 85
 86	@Override
 87	public View onCreateView(final LayoutInflater inflater,
 88			ViewGroup container, Bundle savedInstanceState) {
 89
 90		this.inflater = inflater;
 91
 92		final View view = inflater.inflate(R.layout.fragment_conversation,
 93				container, false);
 94		chatMsg = (EditText) view.findViewById(R.id.textinput);
 95		ImageButton sendButton = (ImageButton) view
 96				.findViewById(R.id.textSendButton);
 97		sendButton.setOnClickListener(this.sendMsgListener);
 98
 99		messagesView = (ListView) view.findViewById(R.id.messages_view);
100
101		SharedPreferences sharedPref = PreferenceManager
102				.getDefaultSharedPreferences(getActivity()
103						.getApplicationContext());
104		boolean showPhoneSelfContactPicture = sharedPref.getBoolean(
105				"show_phone_selfcontact_picture", true);
106
107		final Uri selfiUri;
108		if (showPhoneSelfContactPicture) {
109			selfiUri = PhoneHelper.getSefliUri(getActivity());
110		} else {
111			selfiUri = null;
112		}
113
114		messageListAdapter = new ArrayAdapter<Message>(this.getActivity()
115				.getApplicationContext(), R.layout.message_sent,
116				this.messageList) {
117
118			private static final int SENT = 0;
119			private static final int RECIEVED = 1;
120
121			@Override
122			public int getViewTypeCount() {
123				return 2;
124			}
125
126			@Override
127			public int getItemViewType(int position) {
128				if (getItem(position).getStatus() == Message.STATUS_RECIEVED) {
129					return RECIEVED;
130				} else {
131					return SENT;
132				}
133			}
134
135			@Override
136			public View getView(int position, View view, ViewGroup parent) {
137				Message item = getItem(position);
138				int type = getItemViewType(position);
139				if (view == null) {
140					switch (type) {
141					case SENT:
142						view = (View) inflater.inflate(R.layout.message_sent,
143								null);
144						break;
145					case RECIEVED:
146						view = (View) inflater.inflate(
147								R.layout.message_recieved, null);
148						break;
149					}
150				}
151				ImageView imageView = (ImageView) view
152						.findViewById(R.id.message_photo);
153				if (type == RECIEVED) {
154					if (item.getConversation().getMode() == Conversation.MODE_SINGLE) {
155						Uri uri = item.getConversation().getProfilePhotoUri();
156						if (uri != null) {
157							imageView.setImageURI(uri);
158						} else {
159							imageView.setImageBitmap(UIHelper
160									.getUnknownContactPicture(item
161											.getConversation().getName(), 200));
162						}
163					} else if (item.getConversation().getMode() == Conversation.MODE_MULTI) {
164						if (item.getCounterpart() != null) {
165							imageView.setImageBitmap(UIHelper
166									.getUnknownContactPicture(
167											item.getCounterpart(), 200));
168						} else {
169							imageView.setImageBitmap(UIHelper
170									.getUnknownContactPicture(item
171											.getConversation().getName(), 200));
172						}
173					}
174				} else {
175					if (selfiUri != null) {
176						imageView.setImageURI(selfiUri);
177					} else {
178						imageView.setImageBitmap(UIHelper
179								.getUnknownContactPicture(conversation
180										.getAccount().getJid(), 200));
181					}
182				}
183				TextView messageBody = (TextView) view
184						.findViewById(R.id.message_body);
185				String body = item.getBody();
186				if (body != null) {
187					messageBody.setText(body.trim());
188				}
189				TextView time = (TextView) view.findViewById(R.id.message_time);
190				if (item.getStatus() == Message.STATUS_UNSEND) {
191					time.setTypeface(null, Typeface.ITALIC);
192					time.setText("sending\u2026");
193				} else {
194					time.setTypeface(null, Typeface.NORMAL);
195					if ((item.getConversation().getMode() == Conversation.MODE_SINGLE)
196							|| (type != RECIEVED)) {
197						time.setText(UIHelper.readableTimeDifference(item
198								.getTimeSent()));
199					} else {
200						time.setText(item.getCounterpart()
201								+ " \u00B7 "
202								+ UIHelper.readableTimeDifference(item
203										.getTimeSent()));
204					}
205				}
206				return view;
207			}
208		};
209		messagesView.setAdapter(messageListAdapter);
210
211		return view;
212	}
213
214	@Override
215	public void onStart() {
216		super.onStart();
217		final ConversationActivity activity = (ConversationActivity) getActivity();
218
219		if (activity.xmppConnectionServiceBound) {
220			this.conversation = activity.getSelectedConversation();
221			updateMessages();
222			// rendering complete. now go tell activity to close pane
223			if (!activity.shouldPaneBeOpen()) {
224				activity.getSlidingPaneLayout().closePane();
225				activity.getActionBar().setDisplayHomeAsUpEnabled(true);
226				activity.getActionBar().setTitle(conversation.getName());
227				activity.invalidateOptionsMenu();
228				if (!conversation.isRead()) {
229					conversation.markRead();
230					activity.updateConversationList();
231				}
232			}
233		}
234	}
235
236	public void onBackendConnected() {
237		final ConversationActivity activity = (ConversationActivity) getActivity();
238		this.conversation = activity.getSelectedConversation();
239		updateMessages();
240		// rendering complete. now go tell activity to close pane
241		if (!activity.shouldPaneBeOpen()) {
242			activity.getSlidingPaneLayout().closePane();
243			activity.getActionBar().setDisplayHomeAsUpEnabled(true);
244			activity.getActionBar().setTitle(conversation.getName());
245			activity.invalidateOptionsMenu();
246			if (!conversation.isRead()) {
247				conversation.markRead();
248				activity.updateConversationList();
249			}
250		}
251	}
252
253	public void updateMessages() {
254		ConversationActivity activity = (ConversationActivity) getActivity();
255		this.messageList.clear();
256		this.messageList.addAll(this.conversation.getMessages());
257		this.messageListAdapter.notifyDataSetChanged();
258		if (messageList.size() >= 1) {
259			int latestEncryption = this.conversation.getLatestMessage()
260					.getEncryption();
261			conversation.nextMessageEncryption = latestEncryption;
262			makeFingerprintWarning(latestEncryption);
263		}
264		getActivity().invalidateOptionsMenu();
265		updateChatMsgHint();
266		int size = this.messageList.size();
267		if (size >= 1)
268			messagesView.setSelection(size - 1);
269		if (!activity.shouldPaneBeOpen()) {
270			conversation.markRead();
271			activity.updateConversationList();
272		}
273	}
274
275	protected void makeFingerprintWarning(int latestEncryption) {
276		final LinearLayout fingerprintWarning = (LinearLayout) getView()
277				.findViewById(R.id.new_fingerprint);
278		Set<String> knownFingerprints = conversation.getContact()
279				.getOtrFingerprints();
280		if ((latestEncryption == Message.ENCRYPTION_OTR)
281				&& (conversation.hasValidOtrSession()
282						&& (conversation.getOtrSession().getSessionStatus() == SessionStatus.ENCRYPTED) && (!knownFingerprints
283							.contains(conversation.getOtrFingerprint())))) {
284			fingerprintWarning.setVisibility(View.VISIBLE);
285			TextView fingerprint = (TextView) getView().findViewById(
286					R.id.otr_fingerprint);
287			fingerprint.setText(conversation.getOtrFingerprint());
288			fingerprintWarning.setOnClickListener(new OnClickListener() {
289
290				@Override
291				public void onClick(View v) {
292					AlertDialog dialog = UIHelper.getVerifyFingerprintDialog((ConversationActivity) getActivity(),conversation,fingerprintWarning);
293					dialog.show();
294				}
295			});
296		} else {
297			fingerprintWarning.setVisibility(View.GONE);
298		}
299	}
300
301	protected void sendPlainTextMessage(Message message) {
302		ConversationActivity activity = (ConversationActivity) getActivity();
303		activity.xmppConnectionService.sendMessage(conversation.getAccount(), message,
304				null);
305		chatMsg.setText("");
306	}
307	
308	protected void sendOtrMessage(final Message message) {
309		ConversationActivity activity = (ConversationActivity) getActivity();
310		final XmppConnectionService xmppService = activity.xmppConnectionService;
311		if (conversation.hasValidOtrSession()) {
312			activity.xmppConnectionService.sendMessage(
313					conversation.getAccount(), message, null);
314			chatMsg.setText("");
315		} else {
316			Hashtable<String, Integer> presences = conversation
317					.getContact().getPresences();
318			if (presences.size() == 0) {
319				AlertDialog.Builder builder = new AlertDialog.Builder(
320						getActivity());
321				builder.setTitle("Contact is offline");
322				builder.setIconAttribute(android.R.attr.alertDialogIcon);
323				builder.setMessage("Sending OTR encrypted messages to an offline contact is impossible.");
324				builder.setPositiveButton("Send plain text",
325						new DialogInterface.OnClickListener() {
326
327							@Override
328							public void onClick(DialogInterface dialog,
329									int which) {
330								conversation.nextMessageEncryption = Message.ENCRYPTION_NONE;
331								message.setEncryption(Message.ENCRYPTION_NONE);
332								xmppService.sendMessage(
333										conversation.getAccount(),
334										message, null);
335								chatMsg.setText("");
336							}
337						});
338				builder.setNegativeButton("Cancel", null);
339				builder.create().show();
340			} else if (presences.size() == 1) {
341				xmppService.sendMessage(conversation.getAccount(),
342						message,
343						(String) presences.keySet().toArray()[0]);
344				chatMsg.setText("");
345			} else {
346				AlertDialog.Builder builder = new AlertDialog.Builder(
347						getActivity());
348				builder.setTitle("Choose Presence");
349				final String[] presencesArray = new String[presences.size()];
350				presences.keySet().toArray(presencesArray);
351				builder.setItems(presencesArray, new DialogInterface.OnClickListener() {
352					
353					@Override
354					public void onClick(DialogInterface dialog, int which) {
355						xmppService.sendMessage(conversation.getAccount(), message, presencesArray[which]);
356						chatMsg.setText("");
357					}
358				});
359				builder.create().show();
360			}
361		}
362	}
363}