1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.net.wifi;
18
19import android.content.BroadcastReceiver;
20import android.content.Context;
21import android.content.Intent;
22import android.content.IntentFilter;
23import android.net.LinkCapabilities;
24import android.net.LinkProperties;
25import android.net.NetworkInfo;
26import android.net.NetworkInfo.DetailedState;
27import android.net.NetworkStateTracker;
28import android.os.Handler;
29import android.os.Message;
30import android.util.Slog;
31
32import java.util.concurrent.atomic.AtomicBoolean;
33
34/**
35 * Track the state of wifi for connectivity service.
36 *
37 * @hide
38 */
39public class WifiStateTracker implements NetworkStateTracker {
40
41    private static final String NETWORKTYPE = "WIFI";
42    private static final String TAG = "WifiStateTracker";
43
44    private static final boolean LOGV = true;
45
46    private AtomicBoolean mTeardownRequested = new AtomicBoolean(false);
47    private AtomicBoolean mPrivateDnsRouteSet = new AtomicBoolean(false);
48    private AtomicBoolean mDefaultRouteSet = new AtomicBoolean(false);
49
50    private LinkProperties mLinkProperties;
51    private LinkCapabilities mLinkCapabilities;
52    private NetworkInfo mNetworkInfo;
53    private NetworkInfo.State mLastState = NetworkInfo.State.UNKNOWN;
54
55    /* For sending events to connectivity service handler */
56    private Handler mCsHandler;
57    private Context mContext;
58    private BroadcastReceiver mWifiStateReceiver;
59    private WifiManager mWifiManager;
60
61    public WifiStateTracker(int netType, String networkName) {
62        mNetworkInfo = new NetworkInfo(netType, 0, networkName, "");
63        mLinkProperties = new LinkProperties();
64        mLinkCapabilities = new LinkCapabilities();
65
66        mNetworkInfo.setIsAvailable(false);
67        setTeardownRequested(false);
68    }
69
70
71    public void setTeardownRequested(boolean isRequested) {
72        mTeardownRequested.set(isRequested);
73    }
74
75    public boolean isTeardownRequested() {
76        return mTeardownRequested.get();
77    }
78
79    /**
80     * Begin monitoring wifi connectivity
81     */
82    public void startMonitoring(Context context, Handler target) {
83        mCsHandler = target;
84        mContext = context;
85
86        mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
87        IntentFilter filter = new IntentFilter();
88        filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
89        filter.addAction(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION);
90
91        mWifiStateReceiver = new WifiStateReceiver();
92        mContext.registerReceiver(mWifiStateReceiver, filter);
93    }
94
95    /**
96     * Disable connectivity to a network
97     * TODO: do away with return value after making MobileDataStateTracker async
98     */
99    public boolean teardown() {
100        mTeardownRequested.set(true);
101        mWifiManager.stopWifi();
102        return true;
103    }
104
105    /**
106     * Re-enable connectivity to a network after a {@link #teardown()}.
107     */
108    public boolean reconnect() {
109        mTeardownRequested.set(false);
110        mWifiManager.startWifi();
111        return true;
112    }
113
114    /**
115     * Captive check is complete, switch to network
116     */
117    @Override
118    public void captivePortalCheckComplete() {
119        mWifiManager.captivePortalCheckComplete();
120    }
121
122    /**
123     * Turn the wireless radio off for a network.
124     * @param turnOn {@code true} to turn the radio on, {@code false}
125     */
126    public boolean setRadio(boolean turnOn) {
127        mWifiManager.setWifiEnabled(turnOn);
128        return true;
129    }
130
131    /**
132     * Wi-Fi is considered available as long as we have a connection to the
133     * supplicant daemon and there is at least one enabled network. If a teardown
134     * was explicitly requested, then Wi-Fi can be restarted with a reconnect
135     * request, so it is considered available. If the driver has been stopped
136     * for any reason other than a teardown request, Wi-Fi is considered
137     * unavailable.
138     * @return {@code true} if Wi-Fi connections are possible
139     */
140    public boolean isAvailable() {
141        return mNetworkInfo.isAvailable();
142    }
143
144    @Override
145    public void setUserDataEnable(boolean enabled) {
146        Slog.w(TAG, "ignoring setUserDataEnable(" + enabled + ")");
147    }
148
149    @Override
150    public void setPolicyDataEnable(boolean enabled) {
151        // ignored
152    }
153
154    /**
155     * Check if private DNS route is set for the network
156     */
157    public boolean isPrivateDnsRouteSet() {
158        return mPrivateDnsRouteSet.get();
159    }
160
161    /**
162     * Set a flag indicating private DNS route is set
163     */
164    public void privateDnsRouteSet(boolean enabled) {
165        mPrivateDnsRouteSet.set(enabled);
166    }
167
168    /**
169     * Fetch NetworkInfo for the network
170     */
171    public NetworkInfo getNetworkInfo() {
172        return new NetworkInfo(mNetworkInfo);
173    }
174
175    /**
176     * Fetch LinkProperties for the network
177     */
178    public LinkProperties getLinkProperties() {
179        return new LinkProperties(mLinkProperties);
180    }
181
182    /**
183     * A capability is an Integer/String pair, the capabilities
184     * are defined in the class LinkSocket#Key.
185     *
186     * @return a copy of this connections capabilities, may be empty but never null.
187     */
188    public LinkCapabilities getLinkCapabilities() {
189        return new LinkCapabilities(mLinkCapabilities);
190    }
191
192    /**
193     * Check if default route is set
194     */
195    public boolean isDefaultRouteSet() {
196        return mDefaultRouteSet.get();
197    }
198
199    /**
200     * Set a flag indicating default route is set for the network
201     */
202    public void defaultRouteSet(boolean enabled) {
203        mDefaultRouteSet.set(enabled);
204    }
205
206    /**
207     * Return the system properties name associated with the tcp buffer sizes
208     * for this network.
209     */
210    public String getTcpBufferSizesPropName() {
211        return "net.tcp.buffersize.wifi";
212    }
213
214    private class WifiStateReceiver extends BroadcastReceiver {
215        @Override
216        public void onReceive(Context context, Intent intent) {
217
218            if (intent.getAction().equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
219                mNetworkInfo = (NetworkInfo) intent.getParcelableExtra(
220                        WifiManager.EXTRA_NETWORK_INFO);
221                mLinkProperties = intent.getParcelableExtra(
222                        WifiManager.EXTRA_LINK_PROPERTIES);
223                if (mLinkProperties == null) {
224                    mLinkProperties = new LinkProperties();
225                }
226                mLinkCapabilities = intent.getParcelableExtra(
227                        WifiManager.EXTRA_LINK_CAPABILITIES);
228                if (mLinkCapabilities == null) {
229                    mLinkCapabilities = new LinkCapabilities();
230                }
231                // don't want to send redundent state messages
232                // but send portal check detailed state notice
233                NetworkInfo.State state = mNetworkInfo.getState();
234                if (mLastState == state &&
235                        mNetworkInfo.getDetailedState() != DetailedState.CAPTIVE_PORTAL_CHECK) {
236                    return;
237                } else {
238                    mLastState = state;
239                }
240                Message msg = mCsHandler.obtainMessage(EVENT_STATE_CHANGED,
241                        new NetworkInfo(mNetworkInfo));
242                msg.sendToTarget();
243            } else if (intent.getAction().equals(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION)) {
244                mLinkProperties = (LinkProperties) intent.getParcelableExtra(
245                        WifiManager.EXTRA_LINK_PROPERTIES);
246                Message msg = mCsHandler.obtainMessage(EVENT_CONFIGURATION_CHANGED, mNetworkInfo);
247                msg.sendToTarget();
248            }
249        }
250    }
251
252    public void setDependencyMet(boolean met) {
253        // not supported on this network
254    }
255}
256