Feature #259 » reconnection-771.patch
res/layout/preferences.xml Thu Jun 10 20:08:03 2010 +0200 → res/layout/preferences.xml Fri Jun 11 22:34:32 2010 +0200 | ||
---|---|---|
91 | 91 |
<EditTextPreference android:singleLine="true" |
92 | 92 |
android:title="@string/settings_reco_delay" android:name="Reconnect delay" |
93 | 93 |
android:summary="@string/SettingsAdvancedRecoDelay" android:key="settings_key_reco_delay" |
94 |
android:defaultValue="10" /> |
|
94 |
android:numeric="integer" |
|
95 |
android:defaultValue="2" /> |
|
95 | 96 |
</PreferenceCategory> |
96 | 97 |
<CheckBoxPreference android:title="@string/SettingsAdvancedOptions" |
97 | 98 |
android:defaultValue="false" android:summary="@string/SettingsAdvancedSpecOpt" |
src/com/beem/project/beem/BeemService.java Thu Jun 10 20:08:03 2010 +0200 → src/com/beem/project/beem/BeemService.java Fri Jun 11 22:34:32 2010 +0200 | ||
---|---|---|
54 | 54 |
import org.jivesoftware.smack.proxy.ProxyInfo.ProxyType; |
55 | 55 |
import org.jivesoftware.smack.util.StringUtils; |
56 | 56 | |
57 |
import android.app.AlarmManager; |
|
57 | 58 |
import android.app.Notification; |
58 | 59 |
import android.app.NotificationManager; |
60 |
import android.app.PendingIntent; |
|
59 | 61 |
import android.app.Service; |
60 | 62 |
import android.content.BroadcastReceiver; |
61 | 63 |
import android.content.Context; |
... | ... | |
67 | 69 |
import android.net.Uri; |
68 | 70 |
import android.os.IBinder; |
69 | 71 |
import android.os.RemoteException; |
72 |
import android.os.SystemClock; |
|
70 | 73 |
import android.preference.PreferenceManager; |
71 | 74 |
import android.util.Log; |
75 |
import android.widget.Toast; |
|
72 | 76 | |
73 | 77 |
import com.beem.project.beem.service.XmppConnectionAdapter; |
74 | 78 |
import com.beem.project.beem.service.XmppFacade; |
... | ... | |
93 | 97 |
private static final int DEFAULT_XMPP_PORT = 5222; |
94 | 98 |
//private static final String COMMAND_NAMESPACE = "http://jabber.org/protocol/commands"; |
95 | 99 | |
100 |
private AlarmManager mAlarmManager; |
|
96 | 101 |
private NotificationManager mNotificationManager; |
97 | 102 |
private XmppConnectionAdapter mConnection; |
98 | 103 |
private SharedPreferences mSettings; |
... | ... | |
106 | 111 |
private boolean mUseProxy; |
107 | 112 |
private IXmppFacade.Stub mBind; |
108 | 113 | |
109 |
private BeemBroadcastReceiver mReceiver = new BeemBroadcastReceiver();
|
|
114 |
private final ConnectivityReceiver mConnectivityReceiver = new ConnectivityReceiver();
|
|
110 | 115 |
private BeemServiceBroadcastReceiver mOnOffReceiver = new BeemServiceBroadcastReceiver(); |
111 | 116 |
private BeemServicePreferenceListener mPreferenceListener = new BeemServicePreferenceListener(); |
112 | 117 | |
113 | 118 |
private boolean mOnOffReceiverIsRegistered; |
119 |
private boolean mReconnecting; |
|
114 | 120 | |
115 | 121 |
/** |
116 | 122 |
* Constructor. |
... | ... | |
148 | 154 |
// maybe not the universal path, but it works on most devices (Samsung Galaxy, Google Nexus One) |
149 | 155 |
mConnectionConfiguration.setTruststoreType("BKS"); |
150 | 156 |
mConnectionConfiguration.setTruststorePath("/system/etc/security/cacerts.bks"); |
157 |
mConnectionConfiguration.setReconnectionAllowed(false); |
|
151 | 158 |
} |
152 | 159 | |
153 | 160 |
/** |
... | ... | |
175 | 182 |
@Override |
176 | 183 |
public void onCreate() { |
177 | 184 |
super.onCreate(); |
178 |
registerReceiver(mReceiver, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)); |
|
185 |
registerReceiver(mConnectivityReceiver, new IntentFilter(BeemBroadcastReceiver.BEEM_CONNECTION_CLOSED)); |
|
186 |
registerReceiver(mConnectivityReceiver, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)); |
|
179 | 187 |
mSettings = PreferenceManager.getDefaultSharedPreferences(this); |
180 | 188 |
mSettings.registerOnSharedPreferenceChangeListener(mPreferenceListener); |
181 | 189 |
if (mSettings.getBoolean("settings_away_chk", false)) { |
... | ... | |
205 | 213 |
configure(ProviderManager.getInstance()); |
206 | 214 | |
207 | 215 |
mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); |
216 |
mAlarmManager = (AlarmManager) getSystemService(ALARM_SERVICE); |
|
208 | 217 |
mConnection = new XmppConnectionAdapter(mConnectionConfiguration, mLogin, mPassword, this); |
209 | 218 | |
210 | 219 |
Roster.setDefaultSubscriptionMode(SubscriptionMode.manual); |
... | ... | |
220 | 229 |
super.onDestroy(); |
221 | 230 |
resetStatus(); |
222 | 231 |
mNotificationManager.cancelAll(); |
223 |
unregisterReceiver(mReceiver); |
|
232 |
unregisterReceiver(mConnectivityReceiver);
|
|
224 | 233 |
mSettings.unregisterOnSharedPreferenceChangeListener(mPreferenceListener); |
225 | 234 |
if (mOnOffReceiverIsRegistered) |
226 | 235 |
unregisterReceiver(mOnOffReceiver); |
... | ... | |
236 | 245 |
public void onStart(Intent intent, int startId) { |
237 | 246 |
super.onStart(intent, startId); |
238 | 247 |
Log.d(TAG, "onStart"); |
239 |
try { |
|
240 |
mConnection.connectAsync(); |
|
241 |
} catch (RemoteException e) { |
|
242 |
e.printStackTrace(); |
|
243 |
} |
|
248 |
if (!BeemConnectivity.isConnected(this)) |
|
249 |
return; |
|
250 |
launchConnection(intent.getBooleanExtra("Reconnecting", false)); |
|
244 | 251 |
} |
245 | 252 | |
246 | 253 |
/** |
... | ... | |
307 | 314 |
} |
308 | 315 | |
309 | 316 |
/** |
317 |
* Enable automatic reconnection. |
|
318 |
*/ |
|
319 |
public void enableReconnection() { |
|
320 |
mReconnecting = true; |
|
321 |
// let the broadcast receiver launch it if not connected |
|
322 |
if (BeemConnectivity.isConnected(this)) |
|
323 |
setReconnectionProcess(true); |
|
324 |
} |
|
325 | ||
326 |
/** |
|
327 |
* Disable automatic reconnection. |
|
328 |
* This should be done if there is a connection. |
|
329 |
*/ |
|
330 |
public void disableReconnection() { |
|
331 |
mReconnecting = false; |
|
332 |
setReconnectionProcess(false); |
|
333 |
} |
|
334 | ||
335 |
/** |
|
336 |
* Set an repeating alarm to launch an automatic reconnection. |
|
337 |
* |
|
338 |
* @param enable if false the alarm will be canceled |
|
339 |
*/ |
|
340 |
private void setReconnectionProcess(boolean enable) { |
|
341 |
Intent intent = new Intent(this, BeemService.class); |
|
342 |
intent.putExtra("Reconnecting", true); |
|
343 |
PendingIntent pintent = PendingIntent.getService(this, 0, intent, 0); |
|
344 |
if (enable) { |
|
345 |
Log.d(TAG, "Enable reconnection"); |
|
346 |
int nbsec = 2; |
|
347 |
try { |
|
348 |
nbsec = Integer.parseInt(mSettings.getString("settings_key_reco_delay", "1")); |
|
349 |
} catch (NumberFormatException ex) { |
|
350 |
Log.w(TAG, "Bad reconnection delay. Use default", ex); |
|
351 |
} |
|
352 |
int msec = nbsec * 1000; |
|
353 |
long time = SystemClock.elapsedRealtime() + msec; |
|
354 | ||
355 |
mAlarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME, time, msec, pintent); |
|
356 |
} else { |
|
357 |
Log.d(TAG, "Disable reconnection"); |
|
358 |
mAlarmManager.cancel(pintent); |
|
359 |
} |
|
360 |
} |
|
361 | ||
362 |
/** |
|
363 |
* Launch an asynchronous connection. |
|
364 |
* |
|
365 |
* @param isReconnecting true if it is a reconnection triggered by the auto reconnection process. |
|
366 |
*/ |
|
367 |
private void launchConnection(final boolean isReconnecting) { |
|
368 |
disableReconnection(); |
|
369 |
Thread t = new Thread(new Runnable() { |
|
370 | ||
371 |
@Override |
|
372 |
public void run() { |
|
373 |
try { |
|
374 |
if (!mConnection.connectSync() && isReconnecting) |
|
375 |
enableReconnection(); |
|
376 |
} catch (RemoteException e) { |
|
377 |
Log.e(TAG, "Error while connecting asynchronously", e); |
|
378 |
} |
|
379 |
} |
|
380 |
}); |
|
381 |
t.start(); |
|
382 |
} |
|
383 | ||
384 |
/** |
|
310 | 385 |
* A sort of patch from this thread: http://www.igniterealtime.org/community/thread/31118. Avoid ClassCastException |
311 | 386 |
* by bypassing the classloading shit of Smack. |
312 | 387 |
* @param pm The ProviderManager. |
... | ... | |
452 | 527 |
} |
453 | 528 |
} |
454 | 529 |
} |
530 | ||
531 |
/** |
|
532 |
* ConnectivityReceiver which deals with the reconnection system. |
|
533 |
* |
|
534 |
* @author Da Risk <da_risk@beem-project.com> |
|
535 |
*/ |
|
536 |
private class ConnectivityReceiver extends BroadcastReceiver { |
|
537 |
/** |
|
538 |
* Constructor. |
|
539 |
*/ |
|
540 |
public ConnectivityReceiver() { |
|
541 |
} |
|
542 | ||
543 |
@Override |
|
544 |
public void onReceive(final Context context, final Intent intent) { |
|
545 |
String intentAction = intent.getAction(); |
|
546 |
if (intentAction.equals(BeemBroadcastReceiver.BEEM_CONNECTION_CLOSED)) { |
|
547 |
CharSequence message = intent.getCharSequenceExtra("message"); |
|
548 |
Toast.makeText(context, message, Toast.LENGTH_SHORT).show(); |
|
549 |
} else if (intentAction.equals(ConnectivityManager.CONNECTIVITY_ACTION)) { |
|
550 |
boolean connectivity = !intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false); |
|
551 |
Log.d(TAG, "connectivity change " + connectivity); |
|
552 |
if (!connectivity) { |
|
553 |
setReconnectionProcess(false); |
|
554 |
} else if (mReconnecting) { |
|
555 |
setReconnectionProcess(true); |
|
556 |
} |
|
557 |
} |
|
558 |
} |
|
559 |
} |
|
560 | ||
455 | 561 |
} |
456 | 562 |
src/com/beem/project/beem/service/XmppConnectionAdapter.java Thu Jun 10 20:08:03 2010 +0200 → src/com/beem/project/beem/service/XmppConnectionAdapter.java Fri Jun 11 22:34:32 2010 +0200 | ||
---|---|---|
171 | 171 |
} |
172 | 172 | |
173 | 173 |
@Override |
174 |
public boolean connect() throws RemoteException { |
|
174 |
public synchronized boolean connect() throws RemoteException {
|
|
175 | 175 |
if (mAdaptee.isConnected()) |
176 | 176 |
return true; |
177 | 177 |
else { |
178 | 178 |
try { |
179 |
Log.d(TAG, "connect"); |
|
179 | 180 |
mAdaptee.connect(); |
180 | 181 |
mAdaptee.addConnectionListener(mConListener); |
181 | 182 |
return true; |
... | ... | |
199 | 200 |
} |
200 | 201 | |
201 | 202 |
@Override |
202 |
public boolean login() throws RemoteException { |
|
203 |
if (mAdaptee.isAuthenticated()) |
|
204 |
return true; |
|
203 |
public synchronized boolean login() throws RemoteException { |
|
205 | 204 |
if (!mAdaptee.isConnected()) |
206 | 205 |
return false; |
207 | 206 |
try { |
208 |
mAdaptee.login(mLogin, mPassword, mResource); |
|
209 |
mChatManager = new BeemChatManager(mAdaptee.getChatManager(), mService); |
|
210 |
mPrivacyListManager = new PrivacyListManagerAdapter(PrivacyListManager.getInstanceFor(mAdaptee)); |
|
211 | ||
212 |
this.initFeatures(); // pour declarer les features xmpp qu'on |
|
213 |
// supporte |
|
214 | ||
215 |
PacketFilter filter = new PacketFilter() { |
|
216 | ||
217 |
@Override |
|
218 |
public boolean accept(Packet packet) { |
|
219 |
if (packet instanceof Presence) { |
|
220 |
Presence pres = (Presence) packet; |
|
221 |
if (pres.getType() == Presence.Type.subscribe) |
|
222 |
return true; |
|
223 |
} |
|
224 |
return false; |
|
225 |
} |
|
226 |
}; |
|
227 | ||
228 |
mAdaptee.addPacketListener(mSubscribePacketListener, filter); |
|
229 | ||
207 |
Log.d(TAG, "login"); |
|
208 |
if (!mAdaptee.isAuthenticated()) { |
|
209 |
mAdaptee.login(mLogin, mPassword, mResource); |
|
210 |
initConnection(); |
|
211 |
} |
|
230 | 212 |
mService.resetStatus(); |
231 |
mService.initJingle(mAdaptee); |
|
232 | ||
213 |
mService.disableReconnection(); |
|
233 | 214 |
mApplication.setConnected(true); |
234 | 215 |
changeStatus(Status.CONTACT_STATUS_AVAILABLE, mService.getServicePreference().getString("status_text", "")); |
235 | 216 |
return true; |
... | ... | |
347 | 328 |
* {@inheritDoc} |
348 | 329 |
*/ |
349 | 330 |
@Override |
350 |
public boolean disconnect() { |
|
331 |
public synchronized boolean disconnect() {
|
|
351 | 332 |
if (mAdaptee != null && mAdaptee.isConnected()) |
352 | 333 |
mAdaptee.disconnect(); |
353 | 334 |
return true; |
... | ... | |
437 | 418 |
} |
438 | 419 | |
439 | 420 |
/** |
421 |
* Initialize after the first connection. |
|
422 |
*/ |
|
423 |
private void initConnection() { |
|
424 |
mChatManager = new BeemChatManager(mAdaptee.getChatManager(), mService); |
|
425 |
mPrivacyListManager = new PrivacyListManagerAdapter(PrivacyListManager.getInstanceFor(mAdaptee)); |
|
426 | ||
427 |
this.initFeatures(); // pour declarer les features xmpp qu'on |
|
428 |
// supporte |
|
429 | ||
430 |
PacketFilter filter = new PacketFilter() { |
|
431 | ||
432 |
@Override |
|
433 |
public boolean accept(Packet packet) { |
|
434 |
if (packet instanceof Presence) { |
|
435 |
Presence pres = (Presence) packet; |
|
436 |
if (pres.getType() == Presence.Type.subscribe) |
|
437 |
return true; |
|
438 |
} |
|
439 |
return false; |
|
440 |
} |
|
441 |
}; |
|
442 | ||
443 |
mAdaptee.addPacketListener(mSubscribePacketListener, filter); |
|
444 |
mService.initJingle(mAdaptee); |
|
445 |
} |
|
446 | ||
447 |
/** |
|
440 | 448 |
* Listener for XMPP connection events. It will calls the remote listeners for connection events. |
441 | 449 |
* @author darisk |
442 | 450 |
*/ |
... | ... | |
461 | 469 |
mService.sendBroadcast(intent); |
462 | 470 |
mService.stopSelf(); |
463 | 471 |
mApplication.setConnected(false); |
472 |
mService.disableReconnection(); |
|
464 | 473 |
} |
465 | 474 | |
466 | 475 |
/** |
... | ... | |
473 | 482 |
Intent intent = new Intent(BeemBroadcastReceiver.BEEM_CONNECTION_CLOSED); |
474 | 483 |
intent.putExtra("message", exception.getMessage()); |
475 | 484 |
mService.sendBroadcast(intent); |
476 |
mService.stopSelf();
|
|
485 |
mService.enableReconnection();
|
|
477 | 486 |
mApplication.setConnected(false); |
478 | 487 |
} |
479 | 488 | |
... | ... | |
550 | 559 |
*/ |
551 | 560 |
@Override |
552 | 561 |
public void reconnectionSuccessful() { |
553 |
Log.d(TAG, "reconnectionSuccessful"); |
|
554 |
mApplication.setConnected(true); |
|
555 |
PacketFilter filter = new PacketFilter() { |
|
556 | ||
557 |
@Override |
|
558 |
public boolean accept(Packet packet) { |
|
559 |
if (packet instanceof Presence) { |
|
560 |
Presence pres = (Presence) packet; |
|
561 |
if (pres.getType() == Presence.Type.subscribe) |
|
562 |
return true; |
|
563 |
} |
|
564 |
return false; |
|
565 |
} |
|
566 |
}; |
|
567 | ||
568 |
mAdaptee.addPacketListener(new PacketListener() { |
|
569 | ||
570 |
@Override |
|
571 |
public void processPacket(Packet packet) { |
|
572 |
String from = packet.getFrom(); |
|
573 |
Notification notif = new Notification(android.R.drawable.stat_notify_more, mService.getString( |
|
574 |
R.string.AcceptContactRequest, from), System.currentTimeMillis()); |
|
575 |
notif.flags = Notification.FLAG_AUTO_CANCEL; |
|
576 |
Intent intent = new Intent(mService, Subscription.class); |
|
577 |
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) |
|
578 |
.putExtra("from", from); |
|
579 |
notif.setLatestEventInfo(mService, from, mService |
|
580 |
.getString(R.string.AcceptContactRequestFrom, from), PendingIntent.getActivity(mService, 0, |
|
581 |
intent, PendingIntent.FLAG_ONE_SHOT)); |
|
582 |
int id = packet.hashCode(); |
|
583 |
mService.sendNotification(id, notif); |
|
584 |
} |
|
585 |
}, filter); |
|
586 | ||
562 |
Log.v(TAG, "reconnectionSuccessful"); |
|
587 | 563 |
final int n = mRemoteConnListeners.beginBroadcast(); |
588 | 564 | |
589 | 565 |
for (int i = 0; i < n; i++) { |
src/com/beem/project/beem/utils/BeemBroadcastReceiver.java Thu Jun 10 20:08:03 2010 +0200 → src/com/beem/project/beem/utils/BeemBroadcastReceiver.java Fri Jun 11 22:34:32 2010 +0200 | ||
---|---|---|
47 | 47 |
import android.content.BroadcastReceiver; |
48 | 48 |
import android.content.Context; |
49 | 49 |
import android.content.Intent; |
50 |
import android.net.ConnectivityManager; |
|
51 |
import android.widget.Toast; |
|
52 | 50 | |
53 |
import com.beem.project.beem.BeemService; |
|
54 |
import com.beem.project.beem.R; |
|
55 | 51 | |
56 | 52 |
/** |
57 | 53 |
* Manage broadcast disconnect intent. |
... | ... | |
75 | 71 |
public void onReceive(final Context context, final Intent intent) { |
76 | 72 |
String intentAction = intent.getAction(); |
77 | 73 |
if (intentAction.equals(BEEM_CONNECTION_CLOSED)) { |
78 |
CharSequence message = intent.getCharSequenceExtra("message"); |
|
79 |
Toast.makeText(context, message, Toast.LENGTH_SHORT).show(); |
|
80 | 74 |
if (context instanceof Activity) { |
81 | 75 |
Activity act = (Activity) context; |
82 | 76 |
act.finish(); |
83 | 77 |
// The service will be unbinded in the destroy of the activity. |
84 | 78 |
} |
85 |
} else if (intentAction.equals(ConnectivityManager.CONNECTIVITY_ACTION)) { |
|
86 |
if (intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false)) { |
|
87 |
Toast.makeText(context, context.getString(R.string.BeemBroadcastReceiverDisconnect), |
|
88 |
Toast.LENGTH_SHORT).show(); |
|
89 |
context.stopService(new Intent(context, BeemService.class)); |
|
90 |
} |
|
91 | 79 |
} |
92 | 80 |
} |
93 | 81 |
} |