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