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}