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}