Use AlarmManager to schedule an IDLE connection restart.

We also want to restart it during sleep.

Change-Id: Ib2c26e06fb923487b10d94edc1bbd743ebb39fb1
This commit is contained in:
Danny Baumann 2015-06-17 09:13:38 +02:00 committed by Steve Kondik
parent 739281a727
commit a7bc7d8572
1 changed files with 70 additions and 60 deletions

View File

@ -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);