XmppActivity.java

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