1
0
mirror of https://github.com/moparisthebest/Yaaic synced 2024-11-29 04:12:18 -05:00

Fix auto-reconnect

The current auto-reconnection implementation will only try reconnecting
once, immediately after the server is disconnected.  This will of course
almost always fail if the network is down or otherwise unavailable, so
as it stands, enabling auto-reconnect isn't particularly useful.

This patch implements multiple retries for auto-reconnect, with the
frequency of retries controlled by a preference.  The Android alarm
infrastructure is used to schedule reconnection attempts; if the phone
misses a scheduled attempt while it's asleep, the reconnection will be
attempted the next time the phone wakes up.
This commit is contained in:
Steven Luo 2011-06-29 01:20:02 -07:00 committed by Sebastian Kaspari
parent e7651315df
commit bce2523f98
8 changed files with 187 additions and 5 deletions

View File

@ -30,4 +30,20 @@
<item>19</item> <item>19</item>
<item>20</item> <item>20</item>
</string-array> </string-array>
<string-array name="reconnect_interval_labels">
<item>1 minute</item>
<item>5 minutes</item>
<item>10 minutes</item>
<item>15 minutes</item>
<item>20 minutes</item>
<item>30 minutes</item>
</string-array>
<string-array name="reconnect_interval_values">
<item>1</item>
<item>5</item>
<item>10</item>
<item>15</item>
<item>20</item>
<item>30</item>
</string-array>
</resources> </resources>

View File

@ -18,6 +18,9 @@
<string name="key_reconnect">reconnect</string> <string name="key_reconnect">reconnect</string>
<string name="default_reconnect">false</string> <string name="default_reconnect">false</string>
<string name="key_reconnect_interval">reconnect_interval</string>
<string name="default_reconnect_interval">5</string>
<string name="key_quitmessage">quitmessage</string> <string name="key_quitmessage">quitmessage</string>
<string name="default_quitmessage">Yaaic - Yet another Android IRC client - http://www.yaaic.org</string> <string name="default_quitmessage">Yaaic - Yet another Android IRC client - http://www.yaaic.org</string>

View File

@ -176,6 +176,9 @@
<string name="settings_connection">Connection</string> <string name="settings_connection">Connection</string>
<string name="settings_reconnect_title">Reconnect</string> <string name="settings_reconnect_title">Reconnect</string>
<string name="settings_reconnect_desc">Automatically reconnect on disconnect</string> <string name="settings_reconnect_desc">Automatically reconnect on disconnect</string>
<string name="settings_reconnect_interval_title">Reconnect interval</string>
<string name="settings_reconnect_interval_desc">Number of minutes between reconnection tries</string>
<string name="settings_reconnect_interval_dialog_title">Reconnect interval</string>
<string name="settings_chat">Chat</string> <string name="settings_chat">Chat</string>
<string name="settings_icons_title">Show icons</string> <string name="settings_icons_title">Show icons</string>

View File

@ -28,6 +28,15 @@ along with Yaaic. If not, see <http://www.gnu.org/licenses/>.
android:summary="@string/settings_reconnect_desc" android:summary="@string/settings_reconnect_desc"
android:key="@string/key_reconnect" android:key="@string/key_reconnect"
android:defaultValue="@string/default_reconnect" /> android:defaultValue="@string/default_reconnect" />
<ListPreference
android:title="@string/settings_reconnect_interval_title"
android:summary="@string/settings_reconnect_interval_desc"
android:dialogTitle="@string/settings_reconnect_interval_dialog_title"
android:dependency="@string/key_reconnect"
android:entries="@array/reconnect_interval_labels"
android:entryValues="@array/reconnect_interval_values"
android:key="@string/key_reconnect_interval"
android:defaultValue="@string/default_reconnect_interval" />
</PreferenceCategory> </PreferenceCategory>
<PreferenceCategory <PreferenceCategory
android:title="@string/settings_chat"> android:title="@string/settings_chat">

View File

@ -39,12 +39,16 @@ import org.yaaic.model.Server;
import org.yaaic.model.ServerInfo; import org.yaaic.model.ServerInfo;
import org.yaaic.model.Settings; import org.yaaic.model.Settings;
import org.yaaic.model.Status; import org.yaaic.model.Status;
import org.yaaic.receiver.ReconnectReceiver;
import android.app.AlarmManager;
import android.app.Notification; import android.app.Notification;
import android.app.NotificationManager; import android.app.NotificationManager;
import android.app.PendingIntent; import android.app.PendingIntent;
import android.app.Service; import android.app.Service;
import android.content.Intent; import android.content.Intent;
import android.content.IntentFilter;
import android.os.SystemClock;
/** /**
* The background service for managing the irc connections * The background service for managing the irc connections
@ -81,6 +85,10 @@ public class IRCService extends Service
private Notification notification; private Notification notification;
private Settings settings; private Settings settings;
private HashMap<Integer, PendingIntent> alarmIntents;
private HashMap<Integer, ReconnectReceiver> alarmReceivers;
private Object alarmIntentsLock;
/** /**
* Create new service * Create new service
*/ */
@ -92,6 +100,9 @@ public class IRCService extends Service
this.binder = new IRCBinder(this); this.binder = new IRCBinder(this);
this.connectedServerTitles = new ArrayList<String>(); this.connectedServerTitles = new ArrayList<String>();
this.mentions = new LinkedHashMap<String, Conversation>(); this.mentions = new LinkedHashMap<String, Conversation>();
this.alarmIntents = new HashMap<Integer, PendingIntent>();
this.alarmReceivers = new HashMap<Integer, ReconnectReceiver>();
this.alarmIntentsLock = new Object();
} }
/** /**
@ -383,11 +394,31 @@ public class IRCService extends Service
*/ */
public void connect(final Server server) public void connect(final Server server)
{ {
new Thread() { final int serverId = server.getId();
final int reconnectInterval = settings.getReconnectInterval()*60000;
final IRCService service = this;
if (settings.isReconnectEnabled()) {
server.setMayReconnect(true);
}
new Thread("Connect thread for " + server.getTitle()) {
@Override @Override
public void run() { public void run() {
synchronized(alarmIntentsLock) {
alarmIntents.remove(serverId);
ReconnectReceiver lastReceiver = alarmReceivers.remove(serverId);
if (lastReceiver != null) {
unregisterReceiver(lastReceiver);
}
}
if (settings.isReconnectEnabled() && !server.mayReconnect()) {
return;
}
try { try {
IRCConnection connection = getConnection(server.getId()); IRCConnection connection = getConnection(serverId);
connection.setNickname(server.getIdentity().getNickname()); connection.setNickname(server.getIdentity().getNickname());
connection.setAliases(server.getIdentity().getAliases()); connection.setAliases(server.getIdentity().getAliases());
@ -415,19 +446,33 @@ public class IRCService extends Service
catch (Exception e) { catch (Exception e) {
server.setStatus(Status.DISCONNECTED); server.setStatus(Status.DISCONNECTED);
Intent sIntent = Broadcast.createServerIntent(Broadcast.SERVER_UPDATE, server.getId()); Intent sIntent = Broadcast.createServerIntent(Broadcast.SERVER_UPDATE, serverId);
sendBroadcast(sIntent); sendBroadcast(sIntent);
IRCConnection connection = getConnection(server.getId()); IRCConnection connection = getConnection(serverId);
Message message; Message message;
if (e instanceof NickAlreadyInUseException) { if (e instanceof NickAlreadyInUseException) {
message = new Message(getString(R.string.nickname_in_use, connection.getNick())); message = new Message(getString(R.string.nickname_in_use, connection.getNick()));
server.setMayReconnect(false);
} else if (e instanceof IrcException) { } else if (e instanceof IrcException) {
message = new Message(getString(R.string.irc_login_error, server.getHost(), server.getPort())); message = new Message(getString(R.string.irc_login_error, server.getHost(), server.getPort()));
server.setMayReconnect(false);
} else { } else {
message = new Message(getString(R.string.could_not_connect, server.getHost(), server.getPort())); message = new Message(getString(R.string.could_not_connect, server.getHost(), server.getPort()));
if (settings.isReconnectEnabled()) {
Intent rIntent = new Intent(Broadcast.SERVER_RECONNECT + serverId);
PendingIntent pendingRIntent = PendingIntent.getBroadcast(service, 0, rIntent, 0);
AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
ReconnectReceiver receiver = new ReconnectReceiver(service, server);
synchronized(alarmIntentsLock) {
alarmReceivers.put(serverId, receiver);
registerReceiver(receiver, new IntentFilter(Broadcast.SERVER_RECONNECT + serverId));
am.set(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime() + reconnectInterval, pendingRIntent);
alarmIntents.put(serverId, pendingRIntent);
}
}
} }
message.setColor(Message.COLOR_RED); message.setColor(Message.COLOR_RED);
@ -436,7 +481,7 @@ public class IRCService extends Service
Intent cIntent = Broadcast.createConversationIntent( Intent cIntent = Broadcast.createConversationIntent(
Broadcast.CONVERSATION_MESSAGE, Broadcast.CONVERSATION_MESSAGE,
server.getId(), serverId,
ServerInfo.DEFAULT_NAME ServerInfo.DEFAULT_NAME
); );
sendBroadcast(cIntent); sendBroadcast(cIntent);
@ -494,6 +539,20 @@ public class IRCService extends Service
} }
connections.remove(serverId); connections.remove(serverId);
} }
synchronized(alarmIntentsLock) {
PendingIntent pendingRIntent = alarmIntents.get(serverId);
if (pendingRIntent != null) {
AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
am.cancel(pendingRIntent);
alarmIntents.remove(serverId);
}
ReconnectReceiver receiver = alarmReceivers.get(serverId);
if (receiver != null) {
unregisterReceiver(receiver);
alarmReceivers.remove(serverId);
}
}
} else { } else {
shutDown = false; shutDown = false;
} }
@ -516,6 +575,20 @@ public class IRCService extends Service
if (foreground) { if (foreground) {
stopForegroundCompat(R.string.app_name); stopForegroundCompat(R.string.app_name);
} }
AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
synchronized(alarmIntentsLock) {
for (PendingIntent pendingRIntent : alarmIntents.values()) {
am.cancel(pendingRIntent);
}
for (ReconnectReceiver receiver : alarmReceivers.values()) {
unregisterReceiver(receiver);
}
alarmIntents.clear();
alarmIntents = null;
alarmReceivers.clear();
alarmReceivers = null;
}
} }
/** /**

View File

@ -30,6 +30,7 @@ import android.content.Intent;
public abstract class Broadcast public abstract class Broadcast
{ {
public static final String SERVER_UPDATE = "org.yaaic.server.status"; public static final String SERVER_UPDATE = "org.yaaic.server.status";
public static final String SERVER_RECONNECT = "org.yaaic.server.reconnect.";
public static final String CONVERSATION_MESSAGE = "org.yaaic.conversation.message"; public static final String CONVERSATION_MESSAGE = "org.yaaic.conversation.message";
public static final String CONVERSATION_NEW = "org.yaaic.conversation.new"; public static final String CONVERSATION_NEW = "org.yaaic.conversation.new";

View File

@ -131,6 +131,19 @@ public class Settings
); );
} }
/**
* Get the reconnect interval
*
* @return The reconnect interval in minutes
*/
public int getReconnectInterval()
{
return Integer.parseInt(preferences.getString(
resources.getString(R.string.key_reconnect_interval),
resources.getString(R.string.default_reconnect_interval)
));
}
/** /**
* Get the quit message * Get the quit message
* *

View File

@ -0,0 +1,64 @@
/*
Yaaic - Yet Another Android IRC Client
Copyright 2009-2011 Sebastian Kaspari
Copyright 2011 Steven Luo
This file is part of Yaaic.
Yaaic is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Yaaic is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Yaaic. If not, see <http://www.gnu.org/licenses/>.
*/
package org.yaaic.receiver;
import org.yaaic.irc.IRCService;
import org.yaaic.model.Broadcast;
import org.yaaic.model.Server;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
/**
* A receiver to listen for alarms and start a reconnect attempt
*
* @author Steven Luo <steven+android@steven676.net>
*/
public class ReconnectReceiver extends BroadcastReceiver
{
private IRCService service;
private Server server;
/**
* Create a new reconnect receiver
*
* @param server The server to reconnect to
*/
public ReconnectReceiver(IRCService service, Server server)
{
this.service = service;
this.server = server;
}
/**
* On receive broadcast
*/
@Override
public void onReceive(Context context, Intent intent)
{
if (!intent.getAction().equals(Broadcast.SERVER_RECONNECT + server.getId())) {
return;
}
service.connect(server);
}
}