ConversationActivity.java

  1package eu.siacs.conversations.ui;
  2
  3import java.util.ArrayList;
  4import java.util.Collections;
  5import java.util.Comparator;
  6import java.util.List;
  7
  8import eu.siacs.conversations.R;
  9import eu.siacs.conversations.entities.Account;
 10import eu.siacs.conversations.entities.Contact;
 11import eu.siacs.conversations.entities.Conversation;
 12import eu.siacs.conversations.entities.Message;
 13import eu.siacs.conversations.utils.UIHelper;
 14import android.net.Uri;
 15import android.os.Bundle;
 16import android.app.AlertDialog;
 17import android.app.FragmentTransaction;
 18import android.content.Context;
 19import android.content.DialogInterface;
 20import android.content.Intent;
 21import android.graphics.Color;
 22import android.graphics.Typeface;
 23import android.support.v4.widget.SlidingPaneLayout;
 24import android.support.v4.widget.SlidingPaneLayout.PanelSlideListener;
 25import android.util.Log;
 26import android.view.KeyEvent;
 27import android.view.LayoutInflater;
 28import android.view.Menu;
 29import android.view.MenuItem;
 30import android.view.View;
 31import android.view.ViewGroup;
 32import android.widget.AdapterView;
 33import android.widget.AdapterView.OnItemClickListener;
 34import android.widget.ArrayAdapter;
 35import android.widget.ListView;
 36import android.widget.PopupMenu;
 37import android.widget.PopupMenu.OnMenuItemClickListener;
 38import android.widget.TextView;
 39import android.widget.ImageView;
 40
 41public class ConversationActivity extends XmppActivity {
 42
 43	public static final String VIEW_CONVERSATION = "viewConversation";
 44	public static final String CONVERSATION = "conversationUuid";
 45	
 46	public static final int REQUEST_SEND_MESSAGE = 0x75441;
 47	public static final int REQUEST_DECRYPT_PGP = 0x76783;
 48
 49	protected SlidingPaneLayout spl;
 50
 51	private List<Conversation> conversationList = new ArrayList<Conversation>();
 52	private Conversation selectedConversation = null;
 53	private ListView listView;
 54	
 55	private boolean paneShouldBeOpen = true;
 56	private ArrayAdapter<Conversation> listAdapter;
 57	
 58	private OnConversationListChangedListener onConvChanged = new OnConversationListChangedListener() {
 59		
 60		@Override
 61		public void onConversationListChanged() {
 62			conversationList.clear();
 63			conversationList.addAll(xmppConnectionService
 64					.getConversations());
 65			runOnUiThread(new Runnable() {
 66				
 67				@Override
 68				public void run() {	
 69					updateConversationList();
 70					if(paneShouldBeOpen) {
 71						if (conversationList.size() >= 1) {
 72							swapConversationFragment();
 73						} else {
 74							startActivity(new Intent(getApplicationContext(), NewConversationActivity.class));
 75							finish();
 76						}
 77					}
 78					ConversationFragment selectedFragment = (ConversationFragment) getFragmentManager().findFragmentByTag("conversation");
 79					if (selectedFragment!=null) {
 80						selectedFragment.updateMessages();
 81					}
 82				}
 83			});
 84		}
 85	};
 86	
 87	private DialogInterface.OnClickListener addToRoster = new DialogInterface.OnClickListener() {
 88		
 89		@Override
 90		public void onClick(DialogInterface dialog, int which) {
 91			String jid = getSelectedConversation().getContactJid();
 92			Account account = getSelectedConversation().getAccount();
 93			String name = jid.split("@")[0];
 94			Contact contact = new Contact(account, name, jid, null);
 95			xmppConnectionService.createContact(contact);
 96		}
 97	};
 98	
 99	public List<Conversation> getConversationList() {
100		return this.conversationList;
101	}
102
103	public Conversation getSelectedConversation() {
104		return this.selectedConversation;
105	}
106	
107	public ListView getConversationListView() {
108		return this.listView;
109	}
110	
111	public SlidingPaneLayout getSlidingPaneLayout() {
112		return this.spl;
113	}
114	
115	public boolean shouldPaneBeOpen() {
116		return paneShouldBeOpen;
117	}
118	
119	public void updateConversationList() {
120		if (conversationList.size() >= 1) {
121			Collections.sort(this.conversationList, new Comparator<Conversation>() {
122				@Override
123				public int compare(Conversation lhs, Conversation rhs) {
124					return (int) (rhs.getLatestMessage().getTimeSent() - lhs.getLatestMessage().getTimeSent());
125				}
126			});
127		}
128		this.listView.invalidateViews();
129	}
130	
131	@Override
132	protected void onCreate(Bundle savedInstanceState) {
133
134		super.onCreate(savedInstanceState);
135
136		setContentView(R.layout.fragment_conversations_overview);
137
138		listView = (ListView) findViewById(R.id.list);
139
140		this.listAdapter = new ArrayAdapter<Conversation>(this,
141				R.layout.conversation_list_row, conversationList) {
142			@Override
143			public View getView(int position, View view, ViewGroup parent) {
144				if (view == null) {
145					LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
146					view = (View) inflater.inflate(
147							R.layout.conversation_list_row, null);
148				}
149				Conversation conv;
150				if (conversationList.size() > position) {
151					conv = getItem(position);
152				} else {
153					return view;
154				}
155				if (!spl.isSlideable()) {
156					if (conv==getSelectedConversation()) {
157						view.setBackgroundColor(0xffdddddd);
158					} else {
159						view.setBackgroundColor(Color.TRANSPARENT);
160					}
161				} else {
162					view.setBackgroundColor(Color.TRANSPARENT);
163				}
164				TextView convName = (TextView) view.findViewById(R.id.conversation_name);
165				convName.setText(conv.getName());
166				TextView convLastMsg = (TextView) view.findViewById(R.id.conversation_lastmsg);
167				convLastMsg.setText(conv.getLatestMessage().getBody());
168				
169				if(!conv.isRead()) {
170					convName.setTypeface(null,Typeface.BOLD);
171					convLastMsg.setTypeface(null,Typeface.BOLD);
172				} else {
173					convName.setTypeface(null,Typeface.NORMAL);
174					convLastMsg.setTypeface(null,Typeface.NORMAL);
175				}
176				
177				((TextView) view.findViewById(R.id.conversation_lastupdate))
178				.setText(UIHelper.readableTimeDifference(conv.getLatestMessage().getTimeSent()));
179				
180				Uri profilePhoto = conv.getProfilePhotoUri();
181				ImageView imageView = (ImageView) view.findViewById(R.id.conversation_image);
182				if (profilePhoto!=null) {
183					imageView.setImageURI(profilePhoto);
184				} else {
185					imageView.setImageBitmap(UIHelper.getUnknownContactPicture(getItem(position).getName(),200));
186				}
187				
188				
189				((ImageView) view.findViewById(R.id.conversation_image))
190						.setImageURI(conv.getProfilePhotoUri());
191				return view;
192			}
193
194		};
195		
196		listView.setAdapter(this.listAdapter);
197
198		listView.setOnItemClickListener(new OnItemClickListener() {
199
200			@Override
201			public void onItemClick(AdapterView<?> arg0, View clickedView,
202					int position, long arg3) {
203				paneShouldBeOpen = false;
204				if (selectedConversation != conversationList.get(position)) {
205					selectedConversation = conversationList.get(position);
206					swapConversationFragment(); //.onBackendConnected(conversationList.get(position));
207				} else {
208					spl.closePane();
209				}
210			}
211		});
212		spl = (SlidingPaneLayout) findViewById(R.id.slidingpanelayout);
213		spl.setParallaxDistance(150);
214		spl.setShadowResource(R.drawable.es_slidingpane_shadow);
215		spl.setSliderFadeColor(0);
216		spl.setPanelSlideListener(new PanelSlideListener() {
217
218			@Override
219			public void onPanelOpened(View arg0) {
220				paneShouldBeOpen = true;
221				getActionBar().setDisplayHomeAsUpEnabled(false);
222				getActionBar().setTitle(R.string.app_name);
223				invalidateOptionsMenu();
224				hideKeyboard();
225			}
226
227			@Override
228			public void onPanelClosed(View arg0) {
229				paneShouldBeOpen = false;
230				if (conversationList.size() > 0) {
231					getActionBar().setDisplayHomeAsUpEnabled(true);
232					getActionBar().setTitle(getSelectedConversation().getName());
233					invalidateOptionsMenu();
234					if (!getSelectedConversation().isRead()) {
235						getSelectedConversation().markRead();
236						UIHelper.updateNotification(getApplicationContext(), getConversationList(), null, false);
237						updateConversationList();
238					}
239				}
240			}
241
242			@Override
243			public void onPanelSlide(View arg0, float arg1) {
244				// TODO Auto-generated method stub
245
246			}
247		});
248	}
249
250	@Override
251	public boolean onCreateOptionsMenu(Menu menu) {
252		getMenuInflater().inflate(R.menu.conversations, menu);
253		MenuItem menuSecure = (MenuItem) menu.findItem(R.id.action_security);
254		MenuItem menuArchive = (MenuItem) menu.findItem(R.id.action_archive);
255		MenuItem menuMucDetails = (MenuItem) menu.findItem(R.id.action_muc_details);
256		MenuItem menuContactDetails = (MenuItem) menu.findItem(R.id.action_contact_details);
257		
258		if ((spl.isOpen()&&(spl.isSlideable()))) {
259			menuArchive.setVisible(false);
260			menuMucDetails.setVisible(false);
261			menuContactDetails.setVisible(false);
262			menuSecure.setVisible(false);
263		} else {
264			((MenuItem) menu.findItem(R.id.action_add)).setVisible(!spl.isSlideable());
265			if (this.getSelectedConversation()!=null) {
266				if (this.getSelectedConversation().getMode() == Conversation.MODE_MULTI) {
267					menuMucDetails.setVisible(true);
268					menuContactDetails.setVisible(false);
269					menuSecure.setVisible(false);
270					menuArchive.setTitle("Leave conference");
271				} else {
272					menuContactDetails.setVisible(true);
273					menuMucDetails.setVisible(false);
274					if (this.getSelectedConversation().getLatestMessage().getEncryption() != Message.ENCRYPTION_NONE) {
275						menuSecure.setIcon(R.drawable.ic_action_secure);
276					}
277				}
278			}
279		}
280		return true;
281	}
282
283	@Override
284	public boolean onOptionsItemSelected(MenuItem item) {
285		switch (item.getItemId()) {
286		case android.R.id.home:
287			spl.openPane();
288			break;
289		case R.id.action_add:
290			startActivity(new Intent(this, NewConversationActivity.class));
291			break;
292		case R.id.action_archive:
293			Conversation conv = getSelectedConversation();
294			conv.setStatus(Conversation.STATUS_ARCHIVED);
295			paneShouldBeOpen = true;
296			spl.openPane();
297			xmppConnectionService.archiveConversation(conv);
298			if (conversationList.size() > 0) {
299				selectedConversation = conversationList.get(0);
300			} else {
301				selectedConversation = null;
302			}
303			break;
304		case R.id.action_contact_details:
305			Contact contact = this.getSelectedConversation().getContact();
306			if (contact != null) {
307				Intent intent = new Intent(this,ContactDetailsActivity.class);
308				intent.setAction(ContactDetailsActivity.ACTION_VIEW_CONTACT);
309				intent.putExtra("uuid", contact.getUuid());
310				startActivity(intent);
311			} else {
312				String jid = getSelectedConversation().getContactJid();
313				AlertDialog.Builder builder = new AlertDialog.Builder(this);
314				builder.setTitle(jid);
315				builder.setMessage("The contact is not in your roster. Would you like to add it.");
316				builder.setNegativeButton("Cancel", null);
317				builder.setPositiveButton("Add",addToRoster);
318				builder.create().show();
319			}
320			break;
321		case R.id.action_muc_details:
322			Intent intent = new Intent(this,MucDetailsActivity.class);
323			intent.setAction(MucDetailsActivity.ACTION_VIEW_MUC);
324			intent.putExtra("uuid", getSelectedConversation().getUuid());
325			startActivity(intent);
326			break;
327		case R.id.action_security:
328			final Conversation selConv = getSelectedConversation();
329			View menuItemView = findViewById(R.id.action_security);
330			PopupMenu popup = new PopupMenu(this, menuItemView);
331			final ConversationFragment fragment = (ConversationFragment) getFragmentManager().findFragmentByTag("conversation");
332		    if (fragment!=null) {
333				popup.setOnMenuItemClickListener(new OnMenuItemClickListener() {
334					
335					@Override
336					public boolean onMenuItemClick(MenuItem item) {
337						switch (item.getItemId()) {
338						case R.id.encryption_choice_none:
339							selConv.nextMessageEncryption = Message.ENCRYPTION_NONE;
340							item.setChecked(true);
341							break;
342						case R.id.encryption_choice_otr:
343							selConv.nextMessageEncryption = Message.ENCRYPTION_OTR;
344							item.setChecked(true);
345							break;
346						case R.id.encryption_choice_pgp:
347							selConv.nextMessageEncryption = Message.ENCRYPTION_PGP;
348							item.setChecked(true);
349							break;
350						default:
351							selConv.nextMessageEncryption = Message.ENCRYPTION_NONE;
352							break;
353						}
354						fragment.updateChatMsgHint();
355						return true;
356					}
357				});
358			    popup.inflate(R.menu.encryption_choices);
359			    switch (selConv.nextMessageEncryption) {
360				case Message.ENCRYPTION_NONE:
361					popup.getMenu().findItem(R.id.encryption_choice_none).setChecked(true);
362					break;
363				case Message.ENCRYPTION_OTR:
364					popup.getMenu().findItem(R.id.encryption_choice_otr).setChecked(true);
365					break;
366				case Message.ENCRYPTION_PGP:
367					popup.getMenu().findItem(R.id.encryption_choice_pgp).setChecked(true);
368					break;
369				case Message.ENCRYPTION_DECRYPTED:
370					popup.getMenu().findItem(R.id.encryption_choice_pgp).setChecked(true);
371					break;
372				default:
373					popup.getMenu().findItem(R.id.encryption_choice_none).setChecked(true);
374					break;
375				}
376			    popup.show();
377		    }
378
379			break;
380		default:
381			break;
382		}
383		return super.onOptionsItemSelected(item);
384	}
385
386	protected ConversationFragment swapConversationFragment() {
387		ConversationFragment selectedFragment = new ConversationFragment();
388		
389		FragmentTransaction transaction = getFragmentManager()
390				.beginTransaction();
391		transaction.replace(R.id.selected_conversation, selectedFragment,"conversation");
392		transaction.commit();
393		return selectedFragment;
394	}
395
396	@Override
397	public boolean onKeyDown(int keyCode, KeyEvent event) {
398		if (keyCode == KeyEvent.KEYCODE_BACK) {
399			if (!spl.isOpen()) {
400				spl.openPane();
401				return false;
402			}
403		}
404		return super.onKeyDown(keyCode, event);
405	}
406	
407	public void onStart() {
408		super.onStart();
409		this.registerListener();
410		if (conversationList.size()>=1) {
411			onConvChanged.onConversationListChanged();
412		}
413	}
414	
415	@Override
416	protected void onStop() {
417		Log.d("gultsch","called on stop in conversation activity");
418		if (xmppConnectionServiceBound) {
419        	xmppConnectionService.removeOnConversationListChangedListener();
420		}
421		super.onStop();
422	}
423
424	@Override
425	void onBackendConnected() {
426		
427		this.registerListener();
428		if (conversationList.size()==0) {
429			conversationList.addAll(xmppConnectionService
430					.getConversations());
431			
432			this.updateConversationList();
433		}
434
435		if ((getIntent().getAction()!=null)&&(getIntent().getAction().equals(Intent.ACTION_VIEW) && (!handledViewIntent))) {
436			if (getIntent().getType().equals(
437					ConversationActivity.VIEW_CONVERSATION)) {
438				handledViewIntent = true;
439
440				String convToView = (String) getIntent().getExtras().get(CONVERSATION);
441
442				for(int i = 0; i < conversationList.size(); ++i) {
443					if (conversationList.get(i).getUuid().equals(convToView)) {
444						selectedConversation = conversationList.get(i);
445					}
446				}
447				paneShouldBeOpen = false;
448				swapConversationFragment();
449			}
450		} else {
451			if (xmppConnectionService.getAccounts().size() == 0) {
452				startActivity(new Intent(this, ManageAccountActivity.class));
453				finish();
454			} else if (conversationList.size() <= 0) {
455				//add no history
456				startActivity(new Intent(this, NewConversationActivity.class));
457				finish();
458			} else {
459				spl.openPane();
460				//find currently loaded fragment
461				ConversationFragment selectedFragment = (ConversationFragment) getFragmentManager().findFragmentByTag("conversation");
462				if (selectedFragment!=null) {
463					selectedFragment.onBackendConnected();
464				} else {
465					selectedConversation = conversationList.get(0);
466					swapConversationFragment();
467				}
468			}
469		}
470	}
471	public void registerListener() {
472		 if (xmppConnectionServiceBound) {
473			 xmppConnectionService.setOnConversationListChangedListener(this.onConvChanged);
474		 }
475	}
476
477	@Override
478	 protected void onActivityResult(int requestCode, int resultCode, Intent data) {
479		 super.onActivityResult(requestCode, resultCode, data);
480		 if (resultCode == RESULT_OK) {
481			if (requestCode == REQUEST_DECRYPT_PGP) {
482				ConversationFragment selectedFragment = (ConversationFragment) getFragmentManager().findFragmentByTag("conversation");
483				if (selectedFragment!=null) {
484					selectedFragment.hidePgpPassphraseBox();
485				}
486			}
487		 }
488	 }
489}