| /* |
| * 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; |
| } |
| } |
| } |