summaryrefslogtreecommitdiffstats
path: root/provider_src/com/android/email/EmailConnectivityManager.java
blob: 90a511f0679d6be87dc83bd2676c5a9c700e6298 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
/*
 * 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 com.android.mail.utils.LogUtils;

/**
 * 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 = "EmailConnectivityMgr";

    // 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 (DebugUtils.DEBUG) {
                            LogUtils.d(TAG, mName + ": Connectivity wait ended");
                        }
                    }
                    return;
                } else {
                    if (!waiting) {
                        if (DebugUtils.DEBUG) {
                            LogUtils.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;
        }
    }
}