ConversationActivity.java

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