1 /*
2  * Copyright (C) 2017 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 package com.android.car.settings.wifi;
17 
18 import android.annotation.Nullable;
19 import android.content.Context;
20 import android.net.NetworkInfo;
21 import android.net.wifi.SoftApConfiguration;
22 import android.net.wifi.WifiManager;
23 
24 import androidx.annotation.UiThread;
25 
26 import com.android.settingslib.wifi.AccessPoint;
27 import com.android.settingslib.wifi.WifiTracker;
28 
29 import java.util.ArrayList;
30 import java.util.List;
31 
32 /**
33  * Manages Wifi configuration: e.g. monitors wifi states, change wifi setting etc.
34  */
35 public class CarWifiManager implements WifiTracker.WifiListener {
36     private final Context mContext;
37     private final List<Listener> mListeners = new ArrayList<>();
38     private boolean mStarted;
39 
40     private WifiTracker mWifiTracker;
41     private WifiManager mWifiManager;
42 
43     public interface Listener {
44         /**
45          * Something about wifi setting changed.
46          */
onAccessPointsChanged()47         void onAccessPointsChanged();
48 
49         /**
50          * Called when the state of Wifi has changed, the state will be one of
51          * the following.
52          *
53          * <li>{@link WifiManager#WIFI_STATE_DISABLED}</li>
54          * <li>{@link WifiManager#WIFI_STATE_ENABLED}</li>
55          * <li>{@link WifiManager#WIFI_STATE_DISABLING}</li>
56          * <li>{@link WifiManager#WIFI_STATE_ENABLING}</li>
57          * <li>{@link WifiManager#WIFI_STATE_UNKNOWN}</li>
58          * <p>
59          *
60          * @param state The new state of wifi.
61          */
onWifiStateChanged(int state)62         void onWifiStateChanged(int state);
63     }
64 
CarWifiManager(Context context)65     public CarWifiManager(Context context) {
66         mContext = context;
67         mWifiManager = mContext.getSystemService(WifiManager.class);
68         mWifiTracker = new WifiTracker(context, this, true, true);
69     }
70 
71     /**
72      * Adds {@link Listener}.
73      */
addListener(Listener listener)74     public boolean addListener(Listener listener) {
75         return mListeners.add(listener);
76     }
77 
78     /**
79      * Removes {@link Listener}.
80      */
removeListener(Listener listener)81     public boolean removeListener(Listener listener) {
82         return mListeners.remove(listener);
83     }
84 
85     /**
86      * Starts {@link CarWifiManager}.
87      * This should be called only from main thread.
88      */
89     @UiThread
start()90     public void start() {
91         if (!mStarted) {
92             mStarted = true;
93             mWifiTracker.onStart();
94         }
95     }
96 
97     /**
98      * Stops {@link CarWifiManager}.
99      * This should be called only from main thread.
100      */
101     @UiThread
stop()102     public void stop() {
103         if (mStarted) {
104             mStarted = false;
105             mWifiTracker.onStop();
106         }
107     }
108 
109     /**
110      * Destroys {@link CarWifiManager}
111      * This should only be called from main thread.
112      */
113     @UiThread
destroy()114     public void destroy() {
115         mWifiTracker.onDestroy();
116     }
117 
118     /**
119      * Returns a list of all reachable access points.
120      */
getAllAccessPoints()121     public List<AccessPoint> getAllAccessPoints() {
122         return getAccessPoints(false);
123     }
124 
125     /**
126      * Returns a list of saved access points.
127      */
getSavedAccessPoints()128     public List<AccessPoint> getSavedAccessPoints() {
129         return getAccessPoints(true);
130     }
131 
getAccessPoints(boolean saved)132     private List<AccessPoint> getAccessPoints(boolean saved) {
133         List<AccessPoint> accessPoints = new ArrayList<AccessPoint>();
134         if (mWifiManager.isWifiEnabled()) {
135             for (AccessPoint accessPoint : mWifiTracker.getAccessPoints()) {
136                 // ignore out of reach access points.
137                 if (shouldIncludeAp(accessPoint, saved)) {
138                     accessPoints.add(accessPoint);
139                 }
140             }
141         }
142         return accessPoints;
143     }
144 
shouldIncludeAp(AccessPoint accessPoint, boolean saved)145     private boolean shouldIncludeAp(AccessPoint accessPoint, boolean saved) {
146         return saved ? accessPoint.isReachable() && accessPoint.isSaved()
147                 : accessPoint.isReachable();
148     }
149 
150     @Nullable
getConnectedAccessPoint()151     public AccessPoint getConnectedAccessPoint() {
152         for (AccessPoint accessPoint : getAllAccessPoints()) {
153             if (accessPoint.getDetailedState() == NetworkInfo.DetailedState.CONNECTED) {
154                 return accessPoint;
155             }
156         }
157         return null;
158     }
159 
160     /**
161      * Returns {@code true} if Wifi is enabled
162      */
isWifiEnabled()163     public boolean isWifiEnabled() {
164         return mWifiManager.isWifiEnabled();
165     }
166 
167     /**
168      * Returns {@code true} if Wifi tethering is enabled
169      */
isWifiApEnabled()170     public boolean isWifiApEnabled() {
171         return mWifiManager.isWifiApEnabled();
172     }
173 
174     /**
175      * Gets {@link SoftApConfiguration} for tethering
176      */
getSoftApConfig()177     public SoftApConfiguration getSoftApConfig() {
178         return mWifiManager.getSoftApConfiguration();
179     }
180 
181     /**
182      * Sets {@link SoftApConfiguration} for tethering
183      */
setSoftApConfig(SoftApConfiguration config)184     public void setSoftApConfig(SoftApConfiguration config) {
185         mWifiManager.setSoftApConfiguration(config);
186     }
187 
188     /**
189      * Gets the country code in ISO 3166 format.
190      */
getCountryCode()191     public String getCountryCode() {
192         return mWifiManager.getCountryCode();
193     }
194 
195     /**
196      * Checks if the chipset supports 5GHz frequency band.
197      */
is5GhzBandSupported()198     public boolean is5GhzBandSupported() {
199         return mWifiManager.is5GHzBandSupported();
200     }
201 
202     /** Gets the wifi state from {@link WifiManager}. */
getWifiState()203     public int getWifiState() {
204         return mWifiManager.getWifiState();
205     }
206 
207     /** Sets whether wifi is enabled. */
setWifiEnabled(boolean enabled)208     public boolean setWifiEnabled(boolean enabled) {
209         return mWifiManager.setWifiEnabled(enabled);
210     }
211 
212     /** Connects to an public wifi access point. */
connectToPublicWifi(AccessPoint accessPoint, WifiManager.ActionListener listener)213     public void connectToPublicWifi(AccessPoint accessPoint, WifiManager.ActionListener listener) {
214         accessPoint.generateOpenNetworkConfig();
215         mWifiManager.connect(accessPoint.getConfig(), listener);
216     }
217 
218     /** Connects to a saved access point. */
connectToSavedWifi(AccessPoint accessPoint, WifiManager.ActionListener listener)219     public void connectToSavedWifi(AccessPoint accessPoint, WifiManager.ActionListener listener) {
220         if (accessPoint.isSaved()) {
221             mWifiManager.connect(accessPoint.getConfig(), listener);
222         }
223     }
224 
225     @Override
onWifiStateChanged(int state)226     public void onWifiStateChanged(int state) {
227         for (Listener listener : mListeners) {
228             listener.onWifiStateChanged(state);
229         }
230     }
231 
232     @Override
onConnectedChanged()233     public void onConnectedChanged() {
234     }
235 
236     @Override
onAccessPointsChanged()237     public void onAccessPointsChanged() {
238         for (Listener listener : mListeners) {
239             listener.onAccessPointsChanged();
240         }
241     }
242 }
243