Project

General

Profile

Feature #259 » reconnection-771.patch

Patch to apply on r771 - Frédéric Barthéléry, 06/11/2010 10:51 PM

View differences:

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
}
(9-9/14)