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}