From a7bc7d857295c645f5c1c1774f6dfb0bb9dfda63 Mon Sep 17 00:00:00 2001 From: Danny Baumann Date: Wed, 17 Jun 2015 09:13:38 +0200 Subject: [PATCH] Use AlarmManager to schedule an IDLE connection restart. We also want to restart it during sleep. Change-Id: Ib2c26e06fb923487b10d94edc1bbd743ebb39fb1 --- .../android/email/service/ImapService.java | 130 ++++++++++-------- 1 file changed, 70 insertions(+), 60 deletions(-) diff --git a/provider_src/com/android/email/service/ImapService.java b/provider_src/com/android/email/service/ImapService.java index fd65fd423..292a64218 100644 --- a/provider_src/com/android/email/service/ImapService.java +++ b/provider_src/com/android/email/service/ImapService.java @@ -113,6 +113,10 @@ public class ImapService extends Service { private static final int KICK_IDLE_CONNECTION_MAX_DELAY = 3 * 60 * 1000; private static final int ALARM_REQUEST_KICK_IDLE_CODE = 1000; + // Restart idle connection between 30 seconds and 1 minute after re-gaining connectivity + private static final int RESTART_IDLE_DELAY_MIN = 30 * 1000; + private static final int RESTART_IDLE_DELAY_MAX = 60 * 1000; + /** * Simple cache for last search result mailbox by account and serverId, since the most common * case will be repeated use of the same mailbox @@ -149,6 +153,8 @@ public class ImapService extends Service { private static final String EXTRA_MESSAGE_ID = "org.codeaurora.email.intent.extra.MESSAGE_ID"; private static final String EXTRA_MESSAGE_INFO = "org.codeaurora.email.intent.extra.MESSAGE_INFO"; + private static final String ACTION_RESTART_IDLE_CONNECTION = + "com.android.email.intent.action.RESTART_IDLE_CONNECTION"; private static final String ACTION_KICK_IDLE_CONNECTION = "com.android.email.intent.action.KICK_IDLE_CONNECTION"; private static final String EXTRA_MAILBOX = "com.android.email.intent.extra.MAILBOX"; @@ -539,85 +545,50 @@ public class ImapService extends Service { private static class ImapEmailConnectivityManager extends EmailConnectivityManager { private final Context mContext; - private final Handler mHandler; - private final IEmailService mService; - private final Runnable mRegisterIdledFolderRunnable = new Runnable() { - @Override - public void run() { - sExecutor.execute(new Runnable() { - @Override - public void run() { - // Initiate a sync for all IDLEd accounts, since there might have - // been changes while we lost connectivity. At the end of the sync - // the IDLE connection will be re-established. - ContentResolver cr = mContext.getContentResolver(); - Cursor c = cr.query(Account.CONTENT_URI, - Account.CONTENT_PROJECTION, null, null, null); - if (c != null) { - try { - while (c.moveToNext()) { - final Account account = new Account(); - account.restore(c); - - // Only imap push accounts - if (account.getSyncInterval() != Account.CHECK_INTERVAL_PUSH) { - continue; - } - if (!isLegacyImapProtocol(mContext, account)) { - continue; - } - - // Request a "recents" sync - ImapService.requestSync(mContext, - account, Mailbox.NO_MAILBOX, false); - LogUtils.d(LOG_TAG, "requestSync after restarting IDLE " - + "for account %s", account.toString()); - } - } finally { - c.close(); - } - } - } - }); - } - }; - - public ImapEmailConnectivityManager(Context context, IEmailService service) { + public ImapEmailConnectivityManager(Context context) { super(context, LOG_TAG); mContext = context; - mHandler = new Handler(); - mService = service; } @Override public void onConnectivityRestored(int networkType) { - // Restore idled folders. Execute in background if (Logging.LOGD) { LogUtils.d(Logging.LOG_TAG, "onConnectivityRestored (" + "networkType=" + networkType + ")"); } - // Hold the register a bit to trying to avoid unstable networking - mHandler.removeCallbacks(mRegisterIdledFolderRunnable); - mHandler.postDelayed(mRegisterIdledFolderRunnable, 10000); + scheduleIdleConnectionRestart(); } @Override public void onConnectivityLost(int networkType) { - // Unlink idled folders. Execute in background if (Logging.LOGD) { LogUtils.d(Logging.LOG_TAG, "onConnectivityLost (" + "networkType=" + networkType + ")"); } - sExecutor.execute(new Runnable() { - @Override - public void run() { - // Only remove references. We have no network to kill idled - // connections - ImapIdleFolderHolder.getInstance().unregisterAllIdledMailboxes(false); - } - }); + // Only remove references. We have no network to kill idled connections + ImapIdleFolderHolder.getInstance().unregisterAllIdledMailboxes(false); + cancelIdleConnectionRestart(); + } + + private void scheduleIdleConnectionRestart() { + PendingIntent pi = getIdleConnectionRestartIntent(); + long due = SystemClock.elapsedRealtime() + RESTART_IDLE_DELAY_MIN; + long windowLength = RESTART_IDLE_DELAY_MAX - RESTART_IDLE_DELAY_MIN; + AlarmManager am = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE); + am.setWindow(AlarmManager.ELAPSED_REALTIME_WAKEUP, due, windowLength, pi); + } + + private void cancelIdleConnectionRestart() { + AlarmManager am = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE); + am.cancel(getIdleConnectionRestartIntent()); + } + + private PendingIntent getIdleConnectionRestartIntent() { + Intent i = new Intent(mContext, ImapService.class); + i.setAction(ACTION_RESTART_IDLE_CONNECTION); + return PendingIntent.getService(mContext, 0, i, PendingIntent.FLAG_CANCEL_CURRENT); } } @@ -784,7 +755,7 @@ public class ImapService extends Service { // Initialize the email provider and the listeners/observers EmailContent.init(this); - mConnectivityManager = new ImapEmailConnectivityManager(this, mBinder); + mConnectivityManager = new ImapEmailConnectivityManager(this); mLocalChangesObserver = new LocalChangesContentObserver(this, mServiceHandler); // Initialize wake locks @@ -927,6 +898,45 @@ public class ImapService extends Service { } catch (Exception e) { LogUtils.e(Logging.LOG_TAG, "RemoteException " + e); } + } else if (ACTION_RESTART_IDLE_CONNECTION.equals(action)) { + // Initiate a sync for all IDLEd accounts, since there might have + // been changes while we lost connectivity. At the end of the sync + // the IDLE connection will be re-established. + + mIdleRefreshWakeLock.acquire(); + + sExecutor.execute(new Runnable() { + @Override + public void run() { + ContentResolver cr = context.getContentResolver(); + Cursor c = null; + try { + c = cr.query(Account.CONTENT_URI, Account.CONTENT_PROJECTION, + null, null, null); + if (c == null) { + return; + } + while (c.moveToNext()) { + final Account account = new Account(); + account.restore(c); + + // Only imap push accounts + if (account.getSyncInterval() == Account.CHECK_INTERVAL_PUSH + && isLegacyImapProtocol(context, account)) { + // Request a "recents" sync + requestSync(context, account, Mailbox.NO_MAILBOX, false); + LogUtils.d(LOG_TAG, "requestSync after restarting IDLE " + + "for account %s", account.toString()); + } + } + } finally { + if (c != null) { + c.close(); + } + mIdleRefreshWakeLock.release(); + } + } + }); } else if (ACTION_KICK_IDLE_CONNECTION.equals(action)) { if (Logging.LOGD) { LogUtils.d(Logging.LOG_TAG, "action: Send Pending Mail "+accountId);