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	protected static final int REQUEST_ANNOUNCE_PGP = 0x0101;
 35	protected static final int REQUEST_INVITE_TO_CONVERSATION = 0x0102;
 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		case android.R.id.home:
158			finish();
159			break;
160		}
161		return super.onOptionsItemSelected(item);
162	}
163
164	@Override
165	protected void onCreate(Bundle savedInstanceState) {
166		super.onCreate(savedInstanceState);
167		ExceptionHelper.init(getApplicationContext());
168		mPrimaryTextColor = getResources().getColor(R.color.primarytext);
169		mSecondaryTextColor = getResources().getColor(R.color.secondarytext);
170		mWarningTextColor = getResources().getColor(R.color.warningtext);
171		mPrimaryColor = getResources().getColor(R.color.primary);
172	}
173
174	public void switchToConversation(Conversation conversation) {
175		switchToConversation(conversation, null, false);
176	}
177
178	public void switchToConversation(Conversation conversation, String text,
179			boolean newTask) {
180		Intent viewConversationIntent = new Intent(this,
181				ConversationActivity.class);
182		viewConversationIntent.setAction(Intent.ACTION_VIEW);
183		viewConversationIntent.putExtra(ConversationActivity.CONVERSATION,
184				conversation.getUuid());
185		if (text != null) {
186			viewConversationIntent.putExtra(ConversationActivity.TEXT, text);
187		}
188		viewConversationIntent.setType(ConversationActivity.VIEW_CONVERSATION);
189		if (newTask) {
190			viewConversationIntent.setFlags(viewConversationIntent.getFlags()
191					| Intent.FLAG_ACTIVITY_NEW_TASK
192					| Intent.FLAG_ACTIVITY_SINGLE_TOP);
193		} else {
194			viewConversationIntent.setFlags(viewConversationIntent.getFlags()
195					| Intent.FLAG_ACTIVITY_CLEAR_TOP);
196		}
197		startActivity(viewConversationIntent);
198	}
199
200	public void switchToContactDetails(Contact contact) {
201		Intent intent = new Intent(this, ContactDetailsActivity.class);
202		intent.setAction(ContactDetailsActivity.ACTION_VIEW_CONTACT);
203		intent.putExtra("account", contact.getAccount().getJid());
204		intent.putExtra("contact", contact.getJid());
205		startActivity(intent);
206	}
207
208	protected void inviteToConversation(Conversation conversation) {
209		Intent intent = new Intent(getApplicationContext(),
210				ChooseContactActivity.class);
211		intent.putExtra("conversation", conversation.getUuid());
212		startActivityForResult(intent, REQUEST_INVITE_TO_CONVERSATION);
213	}
214
215	protected void announcePgp(Account account, final Conversation conversation) {
216		xmppConnectionService.getPgpEngine().generateSignature(account,
217				"online", new UiCallback<Account>() {
218
219					@Override
220					public void userInputRequried(PendingIntent pi,
221							Account account) {
222						try {
223							startIntentSenderForResult(pi.getIntentSender(),
224									REQUEST_ANNOUNCE_PGP, null, 0, 0, 0);
225						} catch (SendIntentException e) {
226						}
227					}
228
229					@Override
230					public void success(Account account) {
231						xmppConnectionService.databaseBackend
232								.updateAccount(account);
233						xmppConnectionService.sendPresencePacket(account,
234								xmppConnectionService.getPresenceGenerator()
235										.sendPresence(account));
236						if (conversation != null) {
237							conversation
238									.setNextEncryption(Message.ENCRYPTION_PGP);
239						}
240					}
241
242					@Override
243					public void error(int error, Account account) {
244						displayErrorDialog(error);
245					}
246				});
247	}
248
249	protected void displayErrorDialog(final int errorCode) {
250		runOnUiThread(new Runnable() {
251
252			@Override
253			public void run() {
254				AlertDialog.Builder builder = new AlertDialog.Builder(
255						XmppActivity.this);
256				builder.setIconAttribute(android.R.attr.alertDialogIcon);
257				builder.setTitle(getString(R.string.error));
258				builder.setMessage(errorCode);
259				builder.setNeutralButton(R.string.accept, null);
260				builder.create().show();
261			}
262		});
263
264	}
265
266	protected void showAddToRosterDialog(final Conversation conversation) {
267		String jid = conversation.getContactJid();
268		AlertDialog.Builder builder = new AlertDialog.Builder(this);
269		builder.setTitle(jid);
270		builder.setMessage(getString(R.string.not_in_roster));
271		builder.setNegativeButton(getString(R.string.cancel), null);
272		builder.setPositiveButton(getString(R.string.add_contact),
273				new DialogInterface.OnClickListener() {
274
275					@Override
276					public void onClick(DialogInterface dialog, int which) {
277						String jid = conversation.getContactJid();
278						Account account = conversation.getAccount();
279						Contact contact = account.getRoster().getContact(jid);
280						xmppConnectionService.createContact(contact);
281						switchToContactDetails(contact);
282					}
283				});
284		builder.create().show();
285	}
286
287	protected void quickEdit(final String previousValue,
288			final OnValueEdited callback) {
289		AlertDialog.Builder builder = new AlertDialog.Builder(this);
290		View view = (View) getLayoutInflater()
291				.inflate(R.layout.quickedit, null);
292		final EditText editor = (EditText) view.findViewById(R.id.editor);
293		editor.setText(previousValue);
294		builder.setView(view);
295		builder.setNegativeButton(R.string.cancel, null);
296		builder.setPositiveButton(R.string.edit, new OnClickListener() {
297
298			@Override
299			public void onClick(DialogInterface dialog, int which) {
300				String value = editor.getText().toString();
301				if (!previousValue.equals(value) && value.trim().length() > 0) {
302					callback.onValueEdited(value);
303				}
304			}
305		});
306		builder.create().show();
307	}
308
309	public void selectPresence(final Conversation conversation,
310			final OnPresenceSelected listener) {
311		Contact contact = conversation.getContact();
312		if (!contact.showInRoster()) {
313			showAddToRosterDialog(conversation);
314		} else {
315			Presences presences = contact.getPresences();
316			if (presences.size() == 0) {
317				conversation.setNextPresence(null);
318				listener.onPresenceSelected();
319			} else if (presences.size() == 1) {
320				String presence = (String) presences.asStringArray()[0];
321				conversation.setNextPresence(presence);
322				listener.onPresenceSelected();
323			} else {
324				final StringBuilder presence = new StringBuilder();
325				AlertDialog.Builder builder = new AlertDialog.Builder(this);
326				builder.setTitle(getString(R.string.choose_presence));
327				final String[] presencesArray = presences.asStringArray();
328				int preselectedPresence = 0;
329				for (int i = 0; i < presencesArray.length; ++i) {
330					if (presencesArray[i].equals(contact.lastseen.presence)) {
331						preselectedPresence = i;
332						break;
333					}
334				}
335				presence.append(presencesArray[preselectedPresence]);
336				builder.setSingleChoiceItems(presencesArray,
337						preselectedPresence,
338						new DialogInterface.OnClickListener() {
339
340							@Override
341							public void onClick(DialogInterface dialog,
342									int which) {
343								presence.delete(0, presence.length());
344								presence.append(presencesArray[which]);
345							}
346						});
347				builder.setNegativeButton(R.string.cancel, null);
348				builder.setPositiveButton(R.string.ok, new OnClickListener() {
349
350					@Override
351					public void onClick(DialogInterface dialog, int which) {
352						conversation.setNextPresence(presence.toString());
353						listener.onPresenceSelected();
354					}
355				});
356				builder.create().show();
357			}
358		}
359	}
360
361	protected void onActivityResult(int requestCode, int resultCode,
362			final Intent data) {
363		super.onActivityResult(requestCode, resultCode, data);
364		if (requestCode == REQUEST_INVITE_TO_CONVERSATION
365				&& resultCode == RESULT_OK) {
366			String contactJid = data.getStringExtra("contact");
367			String conversationUuid = data.getStringExtra("conversation");
368			Conversation conversation = xmppConnectionService
369					.findConversationByUuid(conversationUuid);
370			if (conversation.getMode() == Conversation.MODE_MULTI) {
371				xmppConnectionService.invite(conversation, contactJid);
372			}
373			Log.d("xmppService", "inviting " + contactJid + " to "
374					+ conversation.getName(true));
375		}
376	}
377
378	public int getSecondaryTextColor() {
379		return this.mSecondaryTextColor;
380	}
381
382	public int getPrimaryTextColor() {
383		return this.mPrimaryTextColor;
384	}
385
386	public int getWarningTextColor() {
387		return this.mWarningTextColor;
388	}
389
390	public int getPrimaryColor() {
391		return this.mPrimaryColor;
392	}
393}