13ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank/*
23ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank * Copyright (C) 2011 The Android Open Source Project
33ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank *
43ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank * Licensed under the Apache License, Version 2.0 (the "License");
53ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank * you may not use this file except in compliance with the License.
63ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank * You may obtain a copy of the License at
73ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank *
83ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank *      http://www.apache.org/licenses/LICENSE-2.0
93ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank *
103ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank * Unless required by applicable law or agreed to in writing, software
113ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank * distributed under the License is distributed on an "AS IS" BASIS,
123ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
133ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank * See the License for the specific language governing permissions and
143ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank * limitations under the License.
153ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank */
163ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank
173ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blankpackage com.android.email;
183ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank
193ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blankimport android.content.BroadcastReceiver;
20faf9ecc992c34de53969335f9fb403d2b17f3163Marc Blankimport android.content.ContentResolver;
213ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blankimport android.content.Context;
223ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blankimport android.content.Intent;
233ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blankimport android.content.IntentFilter;
243ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blankimport android.net.ConnectivityManager;
253ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blankimport android.net.NetworkInfo;
263ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blankimport android.net.NetworkInfo.State;
273ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blankimport android.os.Bundle;
283ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blankimport android.os.PowerManager;
293ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blankimport android.os.PowerManager.WakeLock;
303ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank
31560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedyimport com.android.mail.utils.LogUtils;
32f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank
333ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank/**
343ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank * Encapsulates functionality of ConnectivityManager for use in the Email application.  In
353ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank * particular, this class provides callbacks for connectivity lost, connectivity restored, and
363ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank * background setting changed, as well as providing a method that waits for connectivity
373ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank * to be available without holding a wake lock
383ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank *
393ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank * To use, EmailConnectivityManager mgr = new EmailConnectivityManager(context, "Name");
403ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank * When done, mgr.unregister() to unregister the internal receiver
413ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank *
423ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank * TODO: Use this class in ExchangeService
433ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank */
443ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blankpublic class EmailConnectivityManager extends BroadcastReceiver {
458a289cb07cd577d9124411bc0b3c260baf959b9aPaul Westbrook    private static final String TAG = "EmailConnectivityMgr";
463ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank
473ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank    // Loop time while waiting (stopgap in case we don't get a broadcast)
483ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank    private static final int CONNECTIVITY_WAIT_TIME = 10*60*1000;
493ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank
50973702b30e8c2fb2f622f4ef37b42b3bdbd3ef17Marc Blank    // Sentinel value for "no active network"
51973702b30e8c2fb2f622f4ef37b42b3bdbd3ef17Marc Blank    public static final int NO_ACTIVE_NETWORK = -1;
52973702b30e8c2fb2f622f4ef37b42b3bdbd3ef17Marc Blank
533ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank    // The name of this manager (used for logging)
543ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank    private final String mName;
553ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank    // The monitor lock we use while waiting for connectivity
563ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank    private final Object mLock = new Object();
573ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank    // The instantiator's context
583ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank    private final Context mContext;
593ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank    // The wake lock used while running (so we don't fall asleep during execution/callbacks)
603ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank    private final WakeLock mWakeLock;
613ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank    private final android.net.ConnectivityManager mConnectivityManager;
623ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank
633ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank    // Set when we abort waitForConnectivity() via stopWait
643ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank    private boolean mStop = false;
653ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank    // The thread waiting for connectivity
663ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank    private Thread mWaitThread;
673ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank    // Whether or not we're registered with the system connectivity manager
683ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank    private boolean mRegistered = true;
693ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank
703ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank    public EmailConnectivityManager(Context context, String name)  {
713ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank        mContext = context;
723ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank        mName = name;
733ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank        mConnectivityManager =
743ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank            (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
753ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank        PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
763ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank        mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, name);
773ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank        mContext.registerReceiver(this, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
783ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank    }
793ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank
80faf9ecc992c34de53969335f9fb403d2b17f3163Marc Blank    public boolean isAutoSyncAllowed() {
81faf9ecc992c34de53969335f9fb403d2b17f3163Marc Blank        return ContentResolver.getMasterSyncAutomatically();
823ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank    }
833ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank
843ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank    public void stopWait() {
853ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank        mStop = true;
863ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank        Thread thread= mWaitThread;
873ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank        if (thread != null) {
883ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank            thread.interrupt();
893ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank        }
903ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank    }
913ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank
923ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank    /**
933ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank     * Called when network connectivity has been restored; this method should be overridden by
943ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank     * subclasses as necessary. NOTE: CALLED ON UI THREAD
953ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank     * @param networkType as defined by ConnectivityManager
963ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank     */
973ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank    public void onConnectivityRestored(int networkType) {
983ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank    }
993ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank
1003ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank    /**
1013ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank     * Called when network connectivity has been lost; this method should be overridden by
1023ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank     * subclasses as necessary. NOTE: CALLED ON UI THREAD
1033ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank     * @param networkType as defined by ConnectivityManager
1043ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank     */
1053ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank    public void onConnectivityLost(int networkType) {
1063ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank    }
1073ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank
1083ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank    public void unregister() {
1093ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank        try {
1103ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank            mContext.unregisterReceiver(this);
1113ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank        } catch (RuntimeException e) {
1123ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank            // Don't crash if we didn't register
1133ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank        } finally {
1143ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank            mRegistered = false;
1153ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank        }
1163ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank    }
1173ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank
1183ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank    @Override
1193ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank    public void onReceive(Context context, Intent intent) {
1203ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank        if (intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
1213ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank            Bundle extras = intent.getExtras();
1223ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank            if (extras != null) {
1233ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank                NetworkInfo networkInfo =
1243ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank                    (NetworkInfo)extras.get(ConnectivityManager.EXTRA_NETWORK_INFO);
1253ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank                if (networkInfo == null) return;
1263ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank                State state = networkInfo.getState();
1273ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank                if (state == State.CONNECTED) {
1283ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank                    synchronized (mLock) {
1293ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank                        mLock.notifyAll();
1303ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank                    }
1313ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank                    onConnectivityRestored(networkInfo.getType());
1323ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank                } else if (state == State.DISCONNECTED) {
1333ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank                    onConnectivityLost(networkInfo.getType());
1343ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank                }
1353ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank            }
1363ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank        }
1373ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank    }
1383ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank
13981273dfcee3b075451860f60ee15f2aa06ba81ecMarc Blank    /**
14081273dfcee3b075451860f60ee15f2aa06ba81ecMarc Blank     * Request current connectivity status
14181273dfcee3b075451860f60ee15f2aa06ba81ecMarc Blank     * @return whether there is connectivity at this time
14281273dfcee3b075451860f60ee15f2aa06ba81ecMarc Blank     */
14381273dfcee3b075451860f60ee15f2aa06ba81ecMarc Blank    public boolean hasConnectivity() {
14481273dfcee3b075451860f60ee15f2aa06ba81ecMarc Blank        NetworkInfo info = mConnectivityManager.getActiveNetworkInfo();
14581273dfcee3b075451860f60ee15f2aa06ba81ecMarc Blank        return (info != null);
14681273dfcee3b075451860f60ee15f2aa06ba81ecMarc Blank    }
14781273dfcee3b075451860f60ee15f2aa06ba81ecMarc Blank
148973702b30e8c2fb2f622f4ef37b42b3bdbd3ef17Marc Blank    /**
149973702b30e8c2fb2f622f4ef37b42b3bdbd3ef17Marc Blank     * Get the type of the currently active data network
150973702b30e8c2fb2f622f4ef37b42b3bdbd3ef17Marc Blank     * @return the type of the active network (or NO_ACTIVE_NETWORK)
151973702b30e8c2fb2f622f4ef37b42b3bdbd3ef17Marc Blank     */
152973702b30e8c2fb2f622f4ef37b42b3bdbd3ef17Marc Blank    public int getActiveNetworkType() {
153973702b30e8c2fb2f622f4ef37b42b3bdbd3ef17Marc Blank        return getActiveNetworkType(mConnectivityManager);
154973702b30e8c2fb2f622f4ef37b42b3bdbd3ef17Marc Blank    }
155973702b30e8c2fb2f622f4ef37b42b3bdbd3ef17Marc Blank
156973702b30e8c2fb2f622f4ef37b42b3bdbd3ef17Marc Blank    static public int getActiveNetworkType(Context context) {
157973702b30e8c2fb2f622f4ef37b42b3bdbd3ef17Marc Blank        ConnectivityManager cm =
158973702b30e8c2fb2f622f4ef37b42b3bdbd3ef17Marc Blank            (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
159973702b30e8c2fb2f622f4ef37b42b3bdbd3ef17Marc Blank        return getActiveNetworkType(cm);
160973702b30e8c2fb2f622f4ef37b42b3bdbd3ef17Marc Blank    }
161973702b30e8c2fb2f622f4ef37b42b3bdbd3ef17Marc Blank
162973702b30e8c2fb2f622f4ef37b42b3bdbd3ef17Marc Blank    static public int getActiveNetworkType(ConnectivityManager cm) {
163973702b30e8c2fb2f622f4ef37b42b3bdbd3ef17Marc Blank        NetworkInfo info = cm.getActiveNetworkInfo();
164973702b30e8c2fb2f622f4ef37b42b3bdbd3ef17Marc Blank        if (info == null) return NO_ACTIVE_NETWORK;
165973702b30e8c2fb2f622f4ef37b42b3bdbd3ef17Marc Blank        return info.getType();
166973702b30e8c2fb2f622f4ef37b42b3bdbd3ef17Marc Blank    }
167973702b30e8c2fb2f622f4ef37b42b3bdbd3ef17Marc Blank
1683ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank    public void waitForConnectivity() {
1693ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank        // If we're unregistered, throw an exception
1703ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank        if (!mRegistered) {
1713ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank            throw new IllegalStateException("ConnectivityManager not registered");
1723ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank        }
1733ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank        boolean waiting = false;
1743ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank        mWaitThread = Thread.currentThread();
1753ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank        // Acquire the wait lock while we work
1763ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank        mWakeLock.acquire();
1773ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank        try {
1783ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank            while (!mStop) {
1793ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank                NetworkInfo info = mConnectivityManager.getActiveNetworkInfo();
1803ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank                if (info != null) {
1813ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank                    // We're done if there's an active network
1823ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank                    if (waiting) {
18351c653646d14d841fbe527aee9fab7a1886338f8Martin Hibdon                        if (DebugUtils.DEBUG) {
184560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy                            LogUtils.d(TAG, mName + ": Connectivity wait ended");
1853ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank                        }
1863ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank                    }
1873ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank                    return;
1883ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank                } else {
1893ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank                    if (!waiting) {
19051c653646d14d841fbe527aee9fab7a1886338f8Martin Hibdon                        if (DebugUtils.DEBUG) {
191560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy                            LogUtils.d(TAG, mName + ": Connectivity waiting...");
1923ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank                        }
1933ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank                        waiting = true;
1943ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank                    }
1953ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank                    // Wait until a network is connected (or 10 mins), but let the device sleep
1963ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank                    synchronized (mLock) {
1973ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank                        // Don't hold a lock during our wait
1983ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank                        mWakeLock.release();
1993ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank                        try {
2003ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank                            mLock.wait(CONNECTIVITY_WAIT_TIME);
2013ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank                        } catch (InterruptedException e) {
2023ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank                            // This is fine; we just go around the loop again
2033ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank                        }
2043ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank                        // Get the lock back and check again for connectivity
2053ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank                        mWakeLock.acquire();
2063ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank                    }
2073ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank                }
2083ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank            }
2093ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank        } finally {
2103ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank            // Make sure we always release the wait lock
2113ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank            if (mWakeLock.isHeld()) {
2123ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank                mWakeLock.release();
2133ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank            }
2143ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank            mWaitThread = null;
2153ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank        }
2163ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank    }
2173ef8f54bae6a3e02919cfd7add7ed6bf7fdda901Marc Blank}
218