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