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.NetworkStateTracker;
27import android.net.wifi.p2p.WifiP2pManager;
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        filter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
91
92        mWifiStateReceiver = new WifiStateReceiver();
93        mContext.registerReceiver(mWifiStateReceiver, filter);
94    }
95
96    /**
97     * Disable connectivity to a network
98     * TODO: do away with return value after making MobileDataStateTracker async
99     */
100    public boolean teardown() {
101        mTeardownRequested.set(true);
102        mWifiManager.stopWifi();
103        return true;
104    }
105
106    /**
107     * Re-enable connectivity to a network after a {@link #teardown()}.
108     */
109    public boolean reconnect() {
110        mTeardownRequested.set(false);
111        mWifiManager.startWifi();
112        return true;
113    }
114
115    /**
116     * Turn the wireless radio off for a network.
117     * @param turnOn {@code true} to turn the radio on, {@code false}
118     */
119    public boolean setRadio(boolean turnOn) {
120        mWifiManager.setWifiEnabled(turnOn);
121        return true;
122    }
123
124    /**
125     * Wi-Fi is considered available as long as we have a connection to the
126     * supplicant daemon and there is at least one enabled network. If a teardown
127     * was explicitly requested, then Wi-Fi can be restarted with a reconnect
128     * request, so it is considered available. If the driver has been stopped
129     * for any reason other than a teardown request, Wi-Fi is considered
130     * unavailable.
131     * @return {@code true} if Wi-Fi connections are possible
132     */
133    public boolean isAvailable() {
134        return mNetworkInfo.isAvailable();
135    }
136
137    @Override
138    public void setUserDataEnable(boolean enabled) {
139        Slog.w(TAG, "ignoring setUserDataEnable(" + enabled + ")");
140    }
141
142    @Override
143    public void setPolicyDataEnable(boolean enabled) {
144        Slog.w(TAG, "ignoring setPolicyDataEnable(" + enabled + ")");
145    }
146
147    /**
148     * Check if private DNS route is set for the network
149     */
150    public boolean isPrivateDnsRouteSet() {
151        return mPrivateDnsRouteSet.get();
152    }
153
154    /**
155     * Set a flag indicating private DNS route is set
156     */
157    public void privateDnsRouteSet(boolean enabled) {
158        mPrivateDnsRouteSet.set(enabled);
159    }
160
161    /**
162     * Fetch NetworkInfo for the network
163     */
164    public NetworkInfo getNetworkInfo() {
165        return new NetworkInfo(mNetworkInfo);
166    }
167
168    /**
169     * Fetch LinkProperties for the network
170     */
171    public LinkProperties getLinkProperties() {
172        return new LinkProperties(mLinkProperties);
173    }
174
175    /**
176     * A capability is an Integer/String pair, the capabilities
177     * are defined in the class LinkSocket#Key.
178     *
179     * @return a copy of this connections capabilities, may be empty but never null.
180     */
181    public LinkCapabilities getLinkCapabilities() {
182        return new LinkCapabilities(mLinkCapabilities);
183    }
184
185    /**
186     * Check if default route is set
187     */
188    public boolean isDefaultRouteSet() {
189        return mDefaultRouteSet.get();
190    }
191
192    /**
193     * Set a flag indicating default route is set for the network
194     */
195    public void defaultRouteSet(boolean enabled) {
196        mDefaultRouteSet.set(enabled);
197    }
198
199    /**
200     * Return the system properties name associated with the tcp buffer sizes
201     * for this network.
202     */
203    public String getTcpBufferSizesPropName() {
204        return "net.tcp.buffersize.wifi";
205    }
206
207    private class WifiStateReceiver extends BroadcastReceiver {
208        @Override
209        public void onReceive(Context context, Intent intent) {
210
211            if (intent.getAction().equals(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION)) {
212                    mNetworkInfo = (NetworkInfo) intent.getParcelableExtra(
213                            WifiP2pManager.EXTRA_NETWORK_INFO);
214                    mLinkProperties = intent.getParcelableExtra(
215                            WifiP2pManager.EXTRA_LINK_PROPERTIES);
216                    if (mLinkProperties == null) {
217                        mLinkProperties = new LinkProperties();
218                    }
219                    mLinkCapabilities = intent.getParcelableExtra(
220                        WifiP2pManager.EXTRA_LINK_CAPABILITIES);
221                    if (mLinkCapabilities == null) {
222                        mLinkCapabilities = new LinkCapabilities();
223                    }
224             } else if (intent.getAction().equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
225                mNetworkInfo = (NetworkInfo) intent.getParcelableExtra(
226                        WifiManager.EXTRA_NETWORK_INFO);
227                mLinkProperties = intent.getParcelableExtra(
228                        WifiManager.EXTRA_LINK_PROPERTIES);
229                if (mLinkProperties == null) {
230                    mLinkProperties = new LinkProperties();
231                }
232                mLinkCapabilities = intent.getParcelableExtra(
233                        WifiManager.EXTRA_LINK_CAPABILITIES);
234                if (mLinkCapabilities == null) {
235                    mLinkCapabilities = new LinkCapabilities();
236                }
237                // don't want to send redundent state messages
238                // TODO can this be fixed in WifiStateMachine?
239                NetworkInfo.State state = mNetworkInfo.getState();
240                if (mLastState == state) {
241                    return;
242                } else {
243                    mLastState = state;
244                }
245                Message msg = mCsHandler.obtainMessage(EVENT_STATE_CHANGED,
246                        new NetworkInfo(mNetworkInfo));
247                msg.sendToTarget();
248            } else if (intent.getAction().equals(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION)) {
249                mLinkProperties = (LinkProperties) intent.getParcelableExtra(
250                        WifiManager.EXTRA_LINK_PROPERTIES);
251                Message msg = mCsHandler.obtainMessage(EVENT_CONFIGURATION_CHANGED, mNetworkInfo);
252                msg.sendToTarget();
253            }
254        }
255    }
256
257    public void setDependencyMet(boolean met) {
258        // not supported on this network
259    }
260}
261