XmppActivity.java

  1package eu.siacs.conversations.ui;
  2
  3import eu.siacs.conversations.R;
  4import eu.siacs.conversations.entities.Account;
  5import eu.siacs.conversations.entities.Contact;
  6import eu.siacs.conversations.entities.Conversation;
  7import eu.siacs.conversations.entities.Message;
  8import eu.siacs.conversations.entities.Presences;
  9import eu.siacs.conversations.services.XmppConnectionService;
 10import eu.siacs.conversations.services.XmppConnectionService.XmppConnectionBinder;
 11import eu.siacs.conversations.utils.ExceptionHelper;
 12import android.app.Activity;
 13import android.app.AlertDialog;
 14import android.app.PendingIntent;
 15import android.app.AlertDialog.Builder;
 16import android.content.ComponentName;
 17import android.content.Context;
 18import android.content.DialogInterface;
 19import android.content.DialogInterface.OnClickListener;
 20import android.content.IntentSender.SendIntentException;
 21import android.content.Intent;
 22import android.content.ServiceConnection;
 23import android.net.Uri;
 24import android.os.Bundle;
 25import android.os.IBinder;
 26import android.util.Log;
 27import android.view.MenuItem;
 28import android.view.View;
 29import android.view.inputmethod.InputMethodManager;
 30import android.widget.EditText;
 31
 32public abstract class XmppActivity extends Activity {
 33
 34	public static final int REQUEST_ANNOUNCE_PGP = 0x73731;
 35	protected static final int REQUEST_INVITE_TO_CONVERSATION = 0x341830;
 36
 37	protected final static String LOGTAG = "xmppService";
 38
 39	public XmppConnectionService xmppConnectionService;
 40	public boolean xmppConnectionServiceBound = false;
 41	protected boolean handledViewIntent = false;
 42	
 43	protected int mPrimaryTextColor;
 44	protected int mSecondaryTextColor;
 45	protected int mWarningTextColor;
 46	protected int mPrimaryColor;
 47	
 48	protected interface OnValueEdited {
 49		public void onValueEdited(String value);
 50	}
 51	
 52	public interface OnPresenceSelected {
 53		public void onPresenceSelected();
 54	}
 55
 56	protected ServiceConnection mConnection = new ServiceConnection() {
 57
 58		@Override
 59		public void onServiceConnected(ComponentName className, IBinder service) {
 60			XmppConnectionBinder binder = (XmppConnectionBinder) service;
 61			xmppConnectionService = binder.getService();
 62			xmppConnectionServiceBound = true;
 63			onBackendConnected();
 64		}
 65
 66		@Override
 67		public void onServiceDisconnected(ComponentName arg0) {
 68			xmppConnectionServiceBound = false;
 69		}
 70	};
 71
 72	@Override
 73	protected void onStart() {
 74		super.onStart();
 75		if (!xmppConnectionServiceBound) {
 76			connectToBackend();
 77		}
 78	}
 79
 80	public void connectToBackend() {
 81		Intent intent = new Intent(this, XmppConnectionService.class);
 82		intent.setAction("ui");
 83		startService(intent);
 84		bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
 85	}
 86
 87	@Override
 88	protected void onStop() {
 89		super.onStop();
 90		if (xmppConnectionServiceBound) {
 91			unbindService(mConnection);
 92			xmppConnectionServiceBound = false;
 93		}
 94	}
 95
 96	protected void hideKeyboard() {
 97		InputMethodManager inputManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
 98
 99		View focus = getCurrentFocus();
100
101		if (focus != null) {
102
103			inputManager.hideSoftInputFromWindow(focus.getWindowToken(),
104					InputMethodManager.HIDE_NOT_ALWAYS);
105		}
106	}
107
108	public boolean hasPgp() {
109		return xmppConnectionService.getPgpEngine() != null;
110	}
111
112	public void showInstallPgpDialog() {
113		Builder builder = new AlertDialog.Builder(this);
114		builder.setTitle(getString(R.string.openkeychain_required));
115		builder.setIconAttribute(android.R.attr.alertDialogIcon);
116		builder.setMessage(getText(R.string.openkeychain_required_long));
117		builder.setNegativeButton(getString(R.string.cancel), null);
118		builder.setNeutralButton(getString(R.string.restart),
119				new OnClickListener() {
120
121					@Override
122					public void onClick(DialogInterface dialog, int which) {
123						if (xmppConnectionServiceBound) {
124							unbindService(mConnection);
125							xmppConnectionServiceBound = false;
126						}
127						stopService(new Intent(XmppActivity.this,
128								XmppConnectionService.class));
129						finish();
130					}
131				});
132		builder.setPositiveButton(getString(R.string.install),
133				new OnClickListener() {
134
135					@Override
136					public void onClick(DialogInterface dialog, int which) {
137						Uri uri = Uri
138								.parse("market://details?id=org.sufficientlysecure.keychain");
139						Intent intent = new Intent(Intent.ACTION_VIEW, uri);
140						startActivity(intent);
141						finish();
142					}
143				});
144		builder.create().show();
145	}
146
147	abstract void onBackendConnected();
148
149	public boolean onOptionsItemSelected(MenuItem item) {
150		switch (item.getItemId()) {
151		case R.id.action_settings:
152			startActivity(new Intent(this, SettingsActivity.class));
153			break;
154		case R.id.action_accounts:
155			startActivity(new Intent(this, ManageAccountActivity.class));
156			break;
157		}
158		return super.onOptionsItemSelected(item);
159	}
160
161	@Override
162	protected void onCreate(Bundle savedInstanceState) {
163		super.onCreate(savedInstanceState);
164		ExceptionHelper.init(getApplicationContext());
165		mPrimaryTextColor = getResources().getColor(R.color.primarytext);
166		mSecondaryTextColor = getResources().getColor(R.color.secondarytext);
167		mWarningTextColor = getResources().getColor(R.color.warningtext);
168		mPrimaryColor = getResources().getColor(R.color.primary);
169	}
170
171	public void switchToConversation(Conversation conversation) {
172		switchToConversation(conversation, null, false);
173	}
174
175	public void switchToConversation(Conversation conversation, String text,
176			boolean newTask) {
177		Intent viewConversationIntent = new Intent(this,
178				ConversationActivity.class);
179		viewConversationIntent.setAction(Intent.ACTION_VIEW);
180		viewConversationIntent.putExtra(ConversationActivity.CONVERSATION,
181				conversation.getUuid());
182		if (text != null) {
183			viewConversationIntent.putExtra(ConversationActivity.TEXT, text);
184		}
185		viewConversationIntent.setType(ConversationActivity.VIEW_CONVERSATION);
186		if (newTask) {
187			viewConversationIntent.setFlags(viewConversationIntent.getFlags()
188					| Intent.FLAG_ACTIVITY_NEW_TASK
189					| Intent.FLAG_ACTIVITY_SINGLE_TOP);
190		} else {
191			viewConversationIntent.setFlags(viewConversationIntent.getFlags()
192					| Intent.FLAG_ACTIVITY_CLEAR_TOP);
193		}
194		startActivity(viewConversationIntent);
195	}
196
197	public void switchToContactDetails(Contact contact) {
198		Intent intent = new Intent(this, ContactDetailsActivity.class);
199		intent.setAction(ContactDetailsActivity.ACTION_VIEW_CONTACT);
200		intent.putExtra("account", contact.getAccount().getJid());
201		intent.putExtra("contact", contact.getJid());
202		startActivity(intent);
203	}
204
205	protected void inviteToConversation(Conversation conversation) {
206		Intent intent = new Intent(getApplicationContext(), ChooseContactActivity.class);
207		intent.putExtra("conversation",conversation.getUuid());
208		startActivityForResult(intent, REQUEST_INVITE_TO_CONVERSATION);
209	}
210	
211	protected void announcePgp(Account account, final Conversation conversation) {
212		xmppConnectionService.getPgpEngine().generateSignature(account,
213				"online", new UiCallback<Account>() {
214
215					@Override
216					public void userInputRequried(PendingIntent pi,
217							Account account) {
218						try {
219							startIntentSenderForResult(pi.getIntentSender(),
220									REQUEST_ANNOUNCE_PGP, null, 0, 0, 0);
221						} catch (SendIntentException e) {}
222					}
223
224					@Override
225					public void success(Account account) {
226						xmppConnectionService.databaseBackend
227								.updateAccount(account);
228						xmppConnectionService.sendPresencePacket(account,
229								xmppConnectionService.getPresenceGenerator()
230										.sendPresence(account));
231						if (conversation != null) {
232							conversation
233									.setNextEncryption(Message.ENCRYPTION_PGP);
234						}
235					}
236
237					@Override
238					public void error(int error, Account account) {
239						displayErrorDialog(error);
240					}
241				});
242	}
243
244	protected void displayErrorDialog(final int errorCode) {
245		runOnUiThread(new Runnable() {
246
247			@Override
248			public void run() {
249				AlertDialog.Builder builder = new AlertDialog.Builder(
250						XmppActivity.this);
251				builder.setIconAttribute(android.R.attr.alertDialogIcon);
252				builder.setTitle(getString(R.string.error));
253				builder.setMessage(errorCode);
254				builder.setNeutralButton(R.string.accept, null);
255				builder.create().show();
256			}
257		});
258
259	}
260
261	protected void showAddToRosterDialog(final Conversation conversation) {
262		String jid = conversation.getContactJid();
263		AlertDialog.Builder builder = new AlertDialog.Builder(this);
264		builder.setTitle(jid);
265		builder.setMessage(getString(R.string.not_in_roster));
266		builder.setNegativeButton(getString(R.string.cancel), null);
267		builder.setPositiveButton(getString(R.string.add_contact),
268				new DialogInterface.OnClickListener() {
269
270					@Override
271					public void onClick(DialogInterface dialog, int which) {
272						String jid = conversation.getContactJid();
273						Account account = conversation.getAccount();
274						Contact contact = account.getRoster().getContact(jid);
275						xmppConnectionService.createContact(contact);
276						switchToContactDetails(contact);
277					}
278				});
279		builder.create().show();
280	}
281
282	protected void quickEdit(final String previousValue, final OnValueEdited callback) {
283		AlertDialog.Builder builder = new AlertDialog.Builder(this);
284		View view = (View) getLayoutInflater().inflate(R.layout.quickedit, null);
285		final EditText editor = (EditText) view.findViewById(R.id.editor);
286		editor.setText(previousValue);
287		builder.setView(view);
288		builder.setNegativeButton(R.string.cancel, null);
289		builder.setPositiveButton(R.string.edit, new OnClickListener() {
290			
291			@Override
292			public void onClick(DialogInterface dialog, int which) {
293				String value = editor.getText().toString();
294				if (!previousValue.equals(value) && value.trim().length() > 0) {
295					callback.onValueEdited(value);
296				}
297			}
298		});
299		builder.create().show();
300	}
301	
302	public void selectPresence(final Conversation conversation,
303			final OnPresenceSelected listener) {
304		Contact contact = conversation.getContact();
305		if (!contact.showInRoster()) {
306			showAddToRosterDialog(conversation);
307		} else {
308			Presences presences = contact.getPresences();
309			if (presences.size() == 0) {
310				conversation.setNextPresence(null);
311				listener.onPresenceSelected();
312			} else if (presences.size() == 1) {
313				String presence = (String) presences.asStringArray()[0];
314				conversation.setNextPresence(presence);
315				listener.onPresenceSelected();
316			} else {
317				final StringBuilder presence = new StringBuilder();
318				AlertDialog.Builder builder = new AlertDialog.Builder(this);
319				builder.setTitle(getString(R.string.choose_presence));
320				final String[] presencesArray = presences.asStringArray();
321				int preselectedPresence = 0;
322				for (int i = 0; i < presencesArray.length; ++i) {
323					if (presencesArray[i].equals(contact.lastseen.presence)) {
324						preselectedPresence = i;
325						break;
326					}
327				}
328				presence.append(presencesArray[preselectedPresence]);
329				builder.setSingleChoiceItems(presencesArray,
330						preselectedPresence,
331						new DialogInterface.OnClickListener() {
332
333							@Override
334							public void onClick(DialogInterface dialog,
335									int which) {
336								presence.delete(0, presence.length());
337								presence.append(presencesArray[which]);
338							}
339						});
340				builder.setNegativeButton(R.string.cancel, null);
341				builder.setPositiveButton(R.string.ok, new OnClickListener() {
342
343					@Override
344					public void onClick(DialogInterface dialog, int which) {
345						conversation.setNextPresence(presence.toString());
346						listener.onPresenceSelected();
347					}
348				});
349				builder.create().show();
350			}
351		}
352	}
353	
354	protected void onActivityResult(int requestCode, int resultCode,
355			final Intent data) {
356		super.onActivityResult(requestCode, resultCode, data);
357		if (requestCode == REQUEST_INVITE_TO_CONVERSATION && resultCode == RESULT_OK) {
358			String contactJid = data.getStringExtra("contact");
359			String conversationUuid = data.getStringExtra("conversation");
360			Conversation conversation = xmppConnectionService.findConversationByUuid(conversationUuid);
361			if (conversation.getMode() == Conversation.MODE_MULTI) {
362				xmppConnectionService.invite(conversation, contactJid);
363			}
364			Log.d("xmppService","inviting "+contactJid+" to "+conversation.getName(true));
365		}
366	}
367	
368	public int getSecondaryTextColor() {
369		return this.mSecondaryTextColor;
370	}
371	
372	public int getPrimaryTextColor() {
373		return this.mPrimaryTextColor;
374	}
375	
376	public int getWarningTextColor() {
377		return this.mWarningTextColor;
378	}
379	
380	public int getPrimaryColor() {
381		return this.mPrimaryColor;
382	}
383}