blob: c618c3870c5bb4f5bbe9c62cf276c340928324ed [file] [log] [blame]
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.email;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.NetworkInfo.State;
import android.os.Bundle;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.util.Log;
/**
* Encapsulates functionality of ConnectivityManager for use in the Email application. In
* particular, this class provides callbacks for connectivity lost, connectivity restored, and
* background setting changed, as well as providing a method that waits for connectivity
* to be available without holding a wake lock
*
* To use, EmailConnectivityManager mgr = new EmailConnectivityManager(context, "Name");
* When done, mgr.unregister() to unregister the internal receiver
*
* TODO: Use this class in ExchangeService
*/
public class EmailConnectivityManager extends BroadcastReceiver {
private static final String TAG = "EmailConnectivityManager";
// Loop time while waiting (stopgap in case we don't get a broadcast)
private static final int CONNECTIVITY_WAIT_TIME = 10*60*1000;
// Sentinel value for "no active network"
public static final int NO_ACTIVE_NETWORK = -1;
// The name of this manager (used for logging)
private final String mName;
// The monitor lock we use while waiting for connectivity
private final Object mLock = new Object();
// The instantiator's context
private final Context mContext;
// The wake lock used while running (so we don't fall asleep during execution/callbacks)
private final WakeLock mWakeLock;
private final android.net.ConnectivityManager mConnectivityManager;
// Set when we abort waitForConnectivity() via stopWait
private boolean mStop = false;
// The thread waiting for connectivity
private Thread mWaitThread;
// Whether or not we're registered with the system connectivity manager
private boolean mRegistered = true;
public EmailConnectivityManager(Context context, String name) {
mContext = context;
mName = name;
mConnectivityManager =
(ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, name);
mContext.registerReceiver(this, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
}
public boolean isAutoSyncAllowed() {
return ContentResolver.getMasterSyncAutomatically();
}
public void stopWait() {
mStop = true;
Thread thread= mWaitThread;
if (thread != null) {
thread.interrupt();
}
}
/**
* Called when network connectivity has been restored; this method should be overridden by
* subclasses as necessary. NOTE: CALLED ON UI THREAD
* @param networkType as defined by ConnectivityManager
*/
public void onConnectivityRestored(int networkType) {
}
/**
* Called when network connectivity has been lost; this method should be overridden by
* subclasses as necessary. NOTE: CALLED ON UI THREAD
* @param networkType as defined by ConnectivityManager
*/
public void onConnectivityLost(int networkType) {
}
public void unregister() {
try {
mContext.unregisterReceiver(this);
} catch (RuntimeException e) {
// Don't crash if we didn't register
} finally {
mRegistered = false;
}
}
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
Bundle extras = intent.getExtras();
if (extras != null) {
NetworkInfo networkInfo =
(NetworkInfo)extras.get(ConnectivityManager.EXTRA_NETWORK_INFO);
if (networkInfo == null) return;
State state = networkInfo.getState();
if (state == State.CONNECTED) {
synchronized (mLock) {
mLock.notifyAll();
}
onConnectivityRestored(networkInfo.getType());
} else if (state == State.DISCONNECTED) {
onConnectivityLost(networkInfo.getType());
}
}
}
}
/**
* Request current connectivity status
* @return whether there is connectivity at this time
*/
public boolean hasConnectivity() {
NetworkInfo info = mConnectivityManager.getActiveNetworkInfo();
return (info != null);
}
/**
* Get the type of the currently active data network
* @return the type of the active network (or NO_ACTIVE_NETWORK)
*/
public int getActiveNetworkType() {
return getActiveNetworkType(mConnectivityManager);
}
static public int getActiveNetworkType(Context context) {
ConnectivityManager cm =
(ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
return getActiveNetworkType(cm);
}
static public int getActiveNetworkType(ConnectivityManager cm) {
NetworkInfo info = cm.getActiveNetworkInfo();
if (info == null) return NO_ACTIVE_NETWORK;
return info.getType();
}
public void waitForConnectivity() {
// If we're unregistered, throw an exception
if (!mRegistered) {
throw new IllegalStateException("ConnectivityManager not registered");
}
boolean waiting = false;
mWaitThread = Thread.currentThread();
// Acquire the wait lock while we work
mWakeLock.acquire();
try {
while (!mStop) {
NetworkInfo info = mConnectivityManager.getActiveNetworkInfo();
if (info != null) {
// We're done if there's an active network
if (waiting) {
if (Email.DEBUG) {
Log.d(TAG, mName + ": Connectivity wait ended");
}
}
return;
} else {
if (!waiting) {
if (Email.DEBUG) {
Log.d(TAG, mName + ": Connectivity waiting...");
}
waiting = true;
}
// Wait until a network is connected (or 10 mins), but let the device sleep
synchronized (mLock) {
// Don't hold a lock during our wait
mWakeLock.release();
try {
mLock.wait(CONNECTIVITY_WAIT_TIME);
} catch (InterruptedException e) {
// This is fine; we just go around the loop again
}
// Get the lock back and check again for connectivity
mWakeLock.acquire();
}
}
}
} finally {
// Make sure we always release the wait lock
if (mWakeLock.isHeld()) {
mWakeLock.release();
}
mWaitThread = null;
}
}
}