ConversationActivity.java

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