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}