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