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 17 package com.android.car.settings.wifi; 18 19 import android.annotation.FlaggedApi; 20 import android.content.Context; 21 import android.net.wifi.SoftApConfiguration; 22 import android.net.wifi.WifiManager; 23 import android.os.Handler; 24 import android.os.HandlerThread; 25 import android.os.Looper; 26 27 import androidx.annotation.MainThread; 28 import androidx.lifecycle.Lifecycle; 29 import androidx.lifecycle.LifecycleObserver; 30 import androidx.lifecycle.OnLifecycleEvent; 31 32 import com.android.car.settings.Flags; 33 import com.android.wifitrackerlib.WifiEntry; 34 import com.android.wifitrackerlib.WifiPickerTracker; 35 36 import java.util.ArrayList; 37 import java.util.List; 38 import java.util.concurrent.Executor; 39 40 /** 41 * Manages Wifi configuration: e.g. monitors wifi states, change wifi setting etc. 42 */ 43 public class CarWifiManager implements WifiPickerTracker.WifiPickerTrackerCallback, 44 LifecycleObserver { 45 private static final String TAG = "CarWifiManager"; 46 47 private final Context mContext; 48 private final Lifecycle mLifecycle; 49 private final List<Listener> mListeners = new ArrayList<>(); 50 51 private HandlerThread mWorkerThread; 52 private WifiPickerTracker mWifiTracker; 53 private WifiManager mWifiManager; 54 55 public interface Listener { 56 /** 57 * Something about wifi setting changed. 58 */ onWifiEntriesChanged()59 void onWifiEntriesChanged(); 60 61 /** 62 * Called when the state of Wifi has changed, the state will be one of 63 * the following. 64 * 65 * <li>{@link WifiManager#WIFI_STATE_DISABLED}</li> 66 * <li>{@link WifiManager#WIFI_STATE_ENABLED}</li> 67 * <li>{@link WifiManager#WIFI_STATE_DISABLING}</li> 68 * <li>{@link WifiManager#WIFI_STATE_ENABLING}</li> 69 * <li>{@link WifiManager#WIFI_STATE_UNKNOWN}</li> 70 * <p> 71 * 72 * @param state The new state of wifi. 73 */ onWifiStateChanged(int state)74 void onWifiStateChanged(int state); 75 } 76 CarWifiManager(Context context, Lifecycle lifecycle)77 public CarWifiManager(Context context, Lifecycle lifecycle) { 78 mContext = context; 79 mLifecycle = lifecycle; 80 mLifecycle.addObserver(this); 81 mWifiManager = mContext.getSystemService(WifiManager.class); 82 mWorkerThread = new HandlerThread(TAG 83 + "{" + Integer.toHexString(System.identityHashCode(this)) + "}", 84 android.os.Process.THREAD_PRIORITY_BACKGROUND); 85 mWorkerThread.start(); 86 mWifiTracker = WifiUtil.createWifiPickerTracker(lifecycle, context, 87 new Handler(Looper.getMainLooper()), mWorkerThread.getThreadHandler(), 88 /* listener= */ this); 89 } 90 91 /** 92 * Lifecycle method to clean up worker thread on destroy. 93 */ 94 @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY) 95 @MainThread onDestroy()96 public void onDestroy() { 97 if (mWorkerThread != null) { 98 mWorkerThread.quit(); 99 } 100 mLifecycle.removeObserver(this); 101 } 102 103 /** 104 * Adds {@link Listener}. 105 */ addListener(Listener listener)106 public boolean addListener(Listener listener) { 107 return mListeners.add(listener); 108 } 109 110 /** 111 * Removes {@link Listener}. 112 */ removeListener(Listener listener)113 public boolean removeListener(Listener listener) { 114 return mListeners.remove(listener); 115 } 116 117 /** 118 * Returns the currently connected Wi-Fi entries or an empty list if there is no Wi-Fi 119 * network connected. 120 */ getConnectedWifiEntries()121 public List<WifiEntry> getConnectedWifiEntries() { 122 if (mWifiManager.isWifiEnabled()) { 123 return mWifiTracker.getActiveWifiEntries(); 124 } 125 return new ArrayList<>(); 126 } 127 128 /** 129 * Returns a list of all reachable Wi-Fi entries, not including the connected Wi-Fi entry. 130 */ getAllWifiEntries()131 public List<WifiEntry> getAllWifiEntries() { 132 return getWifiEntries(false); 133 } 134 135 /** 136 * Returns a list of saved Wi-Fi entries, not including the connected Wi-Fi entry. 137 */ getSavedWifiEntries()138 public List<WifiEntry> getSavedWifiEntries() { 139 return getWifiEntries(true); 140 } 141 getWifiEntries(boolean onlySaved)142 private List<WifiEntry> getWifiEntries(boolean onlySaved) { 143 List<WifiEntry> wifiEntries = new ArrayList<WifiEntry>(); 144 if (mWifiManager.isWifiEnabled()) { 145 for (WifiEntry wifiEntry : mWifiTracker.getWifiEntries()) { 146 // ignore out of reach Wi-Fi entries. 147 if (shouldIncludeWifiEntry(wifiEntry, onlySaved)) { 148 wifiEntries.add(wifiEntry); 149 } 150 } 151 } 152 return wifiEntries; 153 } 154 shouldIncludeWifiEntry(WifiEntry wifiEntry, boolean onlySaved)155 private boolean shouldIncludeWifiEntry(WifiEntry wifiEntry, boolean onlySaved) { 156 boolean reachable = wifiEntry.getLevel() != WifiEntry.WIFI_LEVEL_UNREACHABLE; 157 return onlySaved 158 ? reachable && wifiEntry.isSaved() 159 : reachable; 160 } 161 162 /** 163 * Returns {@code true} if Wifi is enabled 164 */ isWifiEnabled()165 public boolean isWifiEnabled() { 166 return mWifiManager.isWifiEnabled(); 167 } 168 169 /** 170 * Returns {@code true} if Wifi tethering is enabled 171 */ isWifiApEnabled()172 public boolean isWifiApEnabled() { 173 return mWifiManager.isWifiApEnabled(); 174 } 175 176 /** 177 * Gets {@link SoftApConfiguration} for tethering 178 */ getSoftApConfig()179 public SoftApConfiguration getSoftApConfig() { 180 return mWifiManager.getSoftApConfiguration(); 181 } 182 183 /** 184 * Sets {@link SoftApConfiguration} for tethering 185 */ setSoftApConfig(SoftApConfiguration config)186 public void setSoftApConfig(SoftApConfiguration config) { 187 mWifiManager.setSoftApConfiguration(config); 188 } 189 190 /** 191 * Gets the country code in ISO 3166 format. 192 */ getCountryCode()193 public String getCountryCode() { 194 return mWifiManager.getCountryCode(); 195 } 196 197 /** 198 * Checks if the chipset supports 5GHz frequency band. 199 */ is5GhzBandSupported()200 public boolean is5GhzBandSupported() { 201 return mWifiManager.is5GHzBandSupported(); 202 } 203 204 /** Gets the wifi state from {@link WifiManager}. */ getWifiState()205 public int getWifiState() { 206 return mWifiManager.getWifiState(); 207 } 208 209 /** Sets whether wifi is enabled. */ setWifiEnabled(boolean enabled)210 public boolean setWifiEnabled(boolean enabled) { 211 return mWifiManager.setWifiEnabled(enabled); 212 } 213 214 /** Adds callback for Soft AP */ registerSoftApCallback(Executor executor, WifiManager.SoftApCallback callback)215 public void registerSoftApCallback(Executor executor, WifiManager.SoftApCallback callback) { 216 mWifiManager.registerSoftApCallback(executor, callback); 217 } 218 219 /** Removes callback for Soft AP */ unregisterSoftApCallback(WifiManager.SoftApCallback callback)220 public void unregisterSoftApCallback(WifiManager.SoftApCallback callback) { 221 mWifiManager.unregisterSoftApCallback(callback); 222 } 223 224 /** 225 * Returns whether Wi-Fi Dual Band is supported or not. 226 */ 227 @FlaggedApi(Flags.FLAG_HOTSPOT_UI_SPEED_UPDATE) isDualBandSupported()228 public boolean isDualBandSupported() { 229 return mWifiManager.isBridgedApConcurrencySupported(); 230 } 231 232 @Override onWifiEntriesChanged()233 public void onWifiEntriesChanged() { 234 for (Listener listener : mListeners) { 235 listener.onWifiEntriesChanged(); 236 } 237 } 238 239 @Override onNumSavedNetworksChanged()240 public void onNumSavedNetworksChanged() { 241 } 242 243 @Override onNumSavedSubscriptionsChanged()244 public void onNumSavedSubscriptionsChanged() { 245 } 246 247 @Override onWifiStateChanged()248 public void onWifiStateChanged() { 249 int state = mWifiTracker.getWifiState(); 250 for (Listener listener : mListeners) { 251 listener.onWifiStateChanged(state); 252 } 253 } 254 } 255