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