user alarmmanager to reschedule wakeups instead of just sleeping

Daniel Gultsch created

Change summary

src/eu/siacs/conversations/entities/Account.java               |   9 
src/eu/siacs/conversations/services/EventReceiver.java         |  26 
src/eu/siacs/conversations/services/XmppConnectionService.java |  60 +
src/eu/siacs/conversations/ui/ManageAccountActivity.java       | 146 +--
src/eu/siacs/conversations/utils/DNSHelper.java                |   7 
src/eu/siacs/conversations/xmpp/XmppConnection.java            |  34 
6 files changed, 169 insertions(+), 113 deletions(-)

Detailed changes

src/eu/siacs/conversations/entities/Account.java 🔗

@@ -32,11 +32,12 @@ public class Account  extends AbstractEntity{
 	public static final int OPTION_USETLS = 0;
 	public static final int OPTION_DISABLED = 1;
 	
-	public static final int STATUS_DISABLED = -1;
-	public static final int STATUS_OFFLINE = 0;
+	public static final int STATUS_CONNECTING = 0;
+	public static final int STATUS_DISABLED = -2;
+	public static final int STATUS_OFFLINE = -1;
 	public static final int STATUS_ONLINE = 1;
 	public static final int STATUS_UNAUTHORIZED = 2;
-	public static final int STATUS_NOINTERNET = 3;
+	public static final int STATUS_NO_INTERNET = 3;
 	public static final int STATUS_TLS_ERROR = 4;
 	public static final int STATUS_SERVER_NOT_FOUND = 5;
 	
@@ -46,7 +47,7 @@ public class Account  extends AbstractEntity{
 	protected int options = 0;
 	protected String rosterVersion;
 	protected String resource;
-	protected int status = 0;
+	protected int status = -1;
 	protected JSONObject keys = new JSONObject();
 	
 	protected boolean online = false;

src/eu/siacs/conversations/services/EventReceiver.java 🔗

@@ -3,15 +3,27 @@ package eu.siacs.conversations.services;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
 
 public class EventReceiver extends BroadcastReceiver {
 	@Override
-    public void onReceive(Context context, Intent intent) {
-		Intent mIntentForService = new Intent(context, XmppConnectionService.class);
-		if (intent.getAction().equals("android.intent.action.BOOT_COMPLETED")) {
-        	
-        }
+	public void onReceive(Context context, Intent intent) {
+		Intent mIntentForService = new Intent(context,
+				XmppConnectionService.class);
+		if ((intent.getAction() != null)
+				&& (intent.getAction()
+						.equals("android.intent.action.BOOT_COMPLETED"))) {
+
+		}
+		ConnectivityManager cm = (ConnectivityManager) context
+				.getSystemService(Context.CONNECTIVITY_SERVICE);
+
+		NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
+		boolean isConnected = activeNetwork != null
+				&& activeNetwork.isConnected();
+		mIntentForService.putExtra("has_internet", isConnected);
 		context.startService(mIntentForService);
-    }
-	
+	}
+
 }

src/eu/siacs/conversations/services/XmppConnectionService.java 🔗

@@ -5,6 +5,7 @@ import java.text.SimpleDateFormat;
 import java.util.Date;
 import java.util.Hashtable;
 import java.util.List;
+import java.util.Random;
 
 import org.json.JSONException;
 import org.openintents.openpgp.util.OpenPgpApi;
@@ -42,7 +43,9 @@ import eu.siacs.conversations.xmpp.OnPresencePacketReceived;
 import eu.siacs.conversations.xmpp.OnStatusChanged;
 import eu.siacs.conversations.xmpp.PresencePacket;
 import eu.siacs.conversations.xmpp.XmppConnection;
+import android.app.AlarmManager;
 import android.app.NotificationManager;
+import android.app.PendingIntent;
 import android.app.Service;
 import android.content.Context;
 import android.content.Intent;
@@ -53,6 +56,7 @@ import android.os.Binder;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.PowerManager;
+import android.os.SystemClock;
 import android.preference.PreferenceManager;
 import android.provider.ContactsContract;
 import android.util.Log;
@@ -70,6 +74,8 @@ public class XmppConnectionService extends Service {
 
 	public OnConversationListChangedListener convChangedListener = null;
 	private OnAccountListChangedListener accountChangedListener = null;
+	
+	private Random mRandom = new Random(System.currentTimeMillis());
 
 	private ContentObserver contactObserver = new ContentObserver(null) {
 		@Override
@@ -183,6 +189,14 @@ public class XmppConnectionService extends Service {
 						//
 					}
 				}
+			} else if (account.getStatus() == Account.STATUS_OFFLINE) {
+				Log.d(LOGTAG,"onStatusChanged offline");
+				databaseBackend.clearPresences(account);
+				if (!account.isOptionSet(Account.OPTION_DISABLED)) {
+					int timeToReconnect = mRandom.nextInt(50)+10;
+					scheduleWakeupCall(timeToReconnect);
+				}
+
 			}
 		}
 	};
@@ -364,10 +378,39 @@ public class XmppConnectionService extends Service {
 
 	@Override
 	public int onStartCommand(Intent intent, int flags, int startId) {
+		boolean internet;
+		if ((intent!=null)&&(intent.hasExtra("has_internet"))) {
+			if (intent.getExtras().getBoolean("has_internet",true)) {
+				internet = true;
+			} else {
+				internet = false;
+			}
+		} else {
+			internet = true;
+		}
 		for (Account account : accounts) {
+			if (!internet) {
+				account.setStatus(Account.STATUS_NO_INTERNET);
+				break;
+			} else {
+				if (account.getStatus() == Account.STATUS_NO_INTERNET) {
+					account.setStatus(Account.STATUS_OFFLINE);
+				}
+			}
 			if (account.getXmppConnection() == null) {
-				if (!account.isOptionSet(Account.OPTION_DISABLED)) {
+				if ((!account.isOptionSet(Account.OPTION_DISABLED))&&(internet)) {
 					account.setXmppConnection(this.createConnection(account));
+					Thread thread = new Thread(account.getXmppConnection());
+					thread.start();
+				}
+			} else {
+				if ((!account.isOptionSet(Account.OPTION_DISABLED))&&(internet)) {
+					if (account.getStatus()==Account.STATUS_OFFLINE) {
+						Thread thread = new Thread(account.getXmppConnection());
+						thread.start();
+					}
+				} else {
+					disconnect(account);
 				}
 			}
 		}
@@ -384,6 +427,8 @@ public class XmppConnectionService extends Service {
 		this.pgpServiceConnection = new OpenPgpServiceConnection(
 				getApplicationContext(), "org.sufficientlysecure.keychain");
 		this.pgpServiceConnection.bindToService();
+		
+		
 	}
 
 	@Override
@@ -395,6 +440,17 @@ public class XmppConnectionService extends Service {
 			}
 		}
 	}
+	
+	protected void scheduleWakeupCall(int seconds) {
+		Context context = getApplicationContext();
+		AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
+		Intent intent = new Intent(context, EventReceiver.class);
+		PendingIntent alarmIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
+		alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+		        SystemClock.elapsedRealtime() +
+		        seconds * 1000, alarmIntent);
+		Log.d(LOGTAG,"wake up call scheduled in "+seconds+" seconds");
+	}
 
 	public XmppConnection createConnection(Account account) {
 		PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
@@ -404,8 +460,6 @@ public class XmppConnectionService extends Service {
 		connection.setOnPresencePacketReceivedListener(this.presenceListener);
 		connection
 				.setOnUnregisteredIqPacketReceivedListener(this.unknownIqListener);
-		Thread thread = new Thread(connection);
-		thread.start();
 		return connection;
 	}
 

src/eu/siacs/conversations/ui/ManageAccountActivity.java 🔗

@@ -32,7 +32,7 @@ import android.widget.ArrayAdapter;
 import android.widget.ListView;
 import android.widget.TextView;
 
-public class ManageAccountActivity extends XmppActivity implements ActionMode.Callback {
+public class ManageAccountActivity extends XmppActivity {
 
 	public static final int REQUEST_ANNOUNCE_PGP = 0x73731;
 	
@@ -54,10 +54,6 @@ public class ManageAccountActivity extends XmppActivity implements ActionMode.Ca
 
 				@Override
 				public void run() {
-					if (accountList.size() == 1) {
-						startActivity(new Intent(getApplicationContext(),
-								NewConversationActivity.class));
-					}
 					accountListViewAdapter.notifyDataSetChanged();
 				}
 			});
@@ -113,7 +109,7 @@ public class ManageAccountActivity extends XmppActivity implements ActionMode.Ca
 				return view;
 			}
 		};
-		final Activity activity = this;
+		final XmppActivity activity = this;
 		accountListView.setAdapter(this.accountListViewAdapter);
 		accountListView.setOnItemClickListener(new OnItemClickListener() {
 
@@ -146,7 +142,76 @@ public class ManageAccountActivity extends XmppActivity implements ActionMode.Ca
 					accountListView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
 					accountListView.setItemChecked(position,true);
 					selectedAccountForActionMode = accountList.get(position);
-					actionMode = activity.startActionMode((Callback) activity);
+					actionMode = activity.startActionMode((new ActionMode.Callback() {
+						
+						@Override
+						public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
+							if (selectedAccountForActionMode.isOptionSet(Account.OPTION_DISABLED)) {
+					        	menu.findItem(R.id.account_enable).setVisible(true);
+					        	menu.findItem(R.id.account_disable).setVisible(false);
+					        } else {
+					        	menu.findItem(R.id.account_disable).setVisible(true);
+					        	menu.findItem(R.id.account_enable).setVisible(false);
+					        }
+							return true;
+						}
+						
+						@Override
+						public void onDestroyActionMode(ActionMode mode) {
+							// TODO Auto-generated method stub
+							
+						}
+						
+						@Override
+						public boolean onCreateActionMode(ActionMode mode, Menu menu) {
+							MenuInflater inflater = mode.getMenuInflater();
+					        inflater.inflate(R.menu.manageaccounts_context, menu);
+							return true;
+						}
+						
+						@Override
+						public boolean onActionItemClicked(final ActionMode mode, MenuItem item) {
+							if (item.getItemId()==R.id.account_disable) {
+								selectedAccountForActionMode.setOption(Account.OPTION_DISABLED, true);
+								xmppConnectionService.updateAccount(selectedAccountForActionMode);
+								mode.finish();
+							} else if (item.getItemId()==R.id.account_enable) {
+								selectedAccountForActionMode.setOption(Account.OPTION_DISABLED, false);
+								xmppConnectionService.updateAccount(selectedAccountForActionMode);
+								mode.finish();
+							} else if (item.getItemId()==R.id.account_delete) {
+								AlertDialog.Builder builder = new AlertDialog.Builder(activity);
+								builder.setTitle("Are you sure?");
+								builder.setIconAttribute(android.R.attr.alertDialogIcon);
+								builder.setMessage("If you delete your account your entire conversation history will be lost");
+								builder.setPositiveButton("Delete", new OnClickListener() {
+									
+									@Override
+									public void onClick(DialogInterface dialog, int which) {
+										xmppConnectionService.deleteAccount(selectedAccountForActionMode);
+										selectedAccountForActionMode = null;
+										mode.finish();
+									}
+								});
+								builder.setNegativeButton("Cancel",null);
+								builder.create().show();
+							} else if (item.getItemId()==R.id.announce_pgp) {
+								if (activity.hasPgp()) {
+									mode.finish();
+									try {
+										xmppConnectionService.generatePgpAnnouncement(selectedAccountForActionMode);
+									} catch (PgpEngine.UserInputRequiredException e) {
+										try {
+											startIntentSenderForResult(e.getPendingIntent().getIntentSender(), REQUEST_ANNOUNCE_PGP, null, 0, 0, 0);
+										} catch (SendIntentException e1) {
+											Log.d("gultsch","sending intent failed");
+										}
+									}
+								}
+							}
+							return true;
+						}
+					}));
 					return true;
 				} else {
 					return false;
@@ -210,73 +275,6 @@ public class ManageAccountActivity extends XmppActivity implements ActionMode.Ca
 		dialog.show(getFragmentManager(), "add_account");
 	}
 
-	@Override
-	public boolean onActionItemClicked(final ActionMode mode, MenuItem item) {
-		if (item.getItemId()==R.id.account_disable) {
-			selectedAccountForActionMode.setOption(Account.OPTION_DISABLED, true);
-			xmppConnectionService.updateAccount(selectedAccountForActionMode);
-			mode.finish();
-		} else if (item.getItemId()==R.id.account_enable) {
-			selectedAccountForActionMode.setOption(Account.OPTION_DISABLED, false);
-			xmppConnectionService.updateAccount(selectedAccountForActionMode);
-			mode.finish();
-		} else if (item.getItemId()==R.id.account_delete) {
-			AlertDialog.Builder builder = new AlertDialog.Builder(this);
-			builder.setTitle("Are you sure?");
-			builder.setIconAttribute(android.R.attr.alertDialogIcon);
-			builder.setMessage("If you delete your account your entire conversation history will be lost");
-			builder.setPositiveButton("Delete", new OnClickListener() {
-				
-				@Override
-				public void onClick(DialogInterface dialog, int which) {
-					xmppConnectionService.deleteAccount(selectedAccountForActionMode);
-					selectedAccountForActionMode = null;
-					mode.finish();
-				}
-			});
-			builder.setNegativeButton("Cancel",null);
-			builder.create().show();
-		} else if (item.getItemId()==R.id.announce_pgp) {
-			if (this.hasPgp()) {
-				mode.finish();
-				try {
-					xmppConnectionService.generatePgpAnnouncement(selectedAccountForActionMode);
-				} catch (PgpEngine.UserInputRequiredException e) {
-					try {
-						startIntentSenderForResult(e.getPendingIntent().getIntentSender(), REQUEST_ANNOUNCE_PGP, null, 0, 0, 0);
-					} catch (SendIntentException e1) {
-						Log.d("gultsch","sending intent failed");
-					}
-				}
-			}
-		}
-		return true;
-	}
-
-	@Override
-	public boolean onCreateActionMode(ActionMode mode, Menu menu) {
-		MenuInflater inflater = mode.getMenuInflater();
-        inflater.inflate(R.menu.manageaccounts_context, menu);
-		return true;
-	}
-
-	@Override
-	public void onDestroyActionMode(ActionMode mode) {
-		// TODO Auto-generated method stub
-		
-	}
-
-	@Override
-	public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
-		if (selectedAccountForActionMode.isOptionSet(Account.OPTION_DISABLED)) {
-        	menu.findItem(R.id.account_enable).setVisible(true);
-        	menu.findItem(R.id.account_disable).setVisible(false);
-        } else {
-        	menu.findItem(R.id.account_disable).setVisible(true);
-        	menu.findItem(R.id.account_enable).setVisible(false);
-        }
-		return true;
-	}
 	
 	@Override
 	public void onActionModeStarted(ActionMode mode) {

src/eu/siacs/conversations/utils/DNSHelper.java 🔗

@@ -8,12 +8,10 @@ import java.net.InetAddress;
 import java.util.Random;
 
 import android.os.Bundle;
-import android.util.Log;
 
 public class DNSHelper {
-	public static Bundle getSRVRecord(String host) {
+	public static Bundle getSRVRecord(String host) throws IOException {
 		Bundle namePort = new Bundle();
-		try {
 			String[] hostParts = host.split("\\.");
 			byte[] transId = new byte[2];
 			Random random = new Random();
@@ -70,9 +68,6 @@ public class DNSHelper {
 			}
 			builder.replace(0, 1, "");
 			namePort.putString("name",builder.toString());
-		} catch (IOException e) {
-			Log.d("xmppService","gut" + e.getMessage());
-		}
 		return namePort;
 	}
 

src/eu/siacs/conversations/xmpp/XmppConnection.java 🔗

@@ -69,6 +69,7 @@ public class XmppConnection implements Runnable {
 
 	protected void connect() {
 		try {
+			account.setStatus(Account.STATUS_CONNECTING);
 			Bundle namePort = DNSHelper.getSRVRecord(account.getServer());
 			String srvRecordServer = namePort.getString("name");
 			int srvRecordPort = namePort.getInt("port");
@@ -103,18 +104,24 @@ public class XmppConnection implements Runnable {
 			if (statusListener != null) {
 				statusListener.onStatusChanged(account);
 			}
+			if (wakeLock.isHeld()) {
+				wakeLock.release();
+			}
 			return;
 		} catch (IOException e) {
-			Log.d(LOGTAG, "bla " + e.getMessage());
-			if (shouldConnect) {
-				Log.d(LOGTAG, account.getJid() + ": connection lost");
-				account.setStatus(Account.STATUS_OFFLINE);
-				if (statusListener != null) {
-					statusListener.onStatusChanged(account);
-				}
+			account.setStatus(Account.STATUS_OFFLINE);
+			if (statusListener != null) {
+				statusListener.onStatusChanged(account);
 			}
+			if (wakeLock.isHeld()) {
+				wakeLock.release();
+			}
+			return;
 		} catch (XmlPullParserException e) {
 			Log.d(LOGTAG, "xml exception " + e.getMessage());
+			if (wakeLock.isHeld()) {
+				wakeLock.release();
+			}
 			return;
 		}
 
@@ -122,18 +129,7 @@ public class XmppConnection implements Runnable {
 
 	@Override
 	public void run() {
-		shouldConnect = true;
-		while (shouldConnect) {
-			connect();
-			try {
-				if (shouldConnect) {
-					Thread.sleep(30000);
-				}
-			} catch (InterruptedException e) {
-				// TODO Auto-generated catch block
-				e.printStackTrace();
-			}
-		}
+		connect();
 		Log.d(LOGTAG, "end run");
 	}