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