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.Nullable; 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.wifitrackerlib.WifiEntry; 33 import com.android.wifitrackerlib.WifiPickerTracker; 34 35 import java.util.ArrayList; 36 import java.util.List; 37 import java.util.concurrent.Executor; 38 39 /** 40 * Manages Wifi configuration: e.g. monitors wifi states, change wifi setting etc. 41 */ 42 public class CarWifiManager implements WifiPickerTracker.WifiPickerTrackerCallback, 43 LifecycleObserver { 44 private static final String TAG = "CarWifiManager"; 45 46 private final Context mContext; 47 private final Lifecycle mLifecycle; 48 private final List<Listener> mListeners = new ArrayList<>(); 49 50 private HandlerThread mWorkerThread; 51 private WifiPickerTracker mWifiTracker; 52 private WifiManager mWifiManager; 53 54 public interface Listener { 55 /** 56 * Something about wifi setting changed. 57 */ onWifiEntriesChanged()58 void onWifiEntriesChanged(); 59 60 /** 61 * Called when the state of Wifi has changed, the state will be one of 62 * the following. 63 * 64 * <li>{@link WifiManager#WIFI_STATE_DISABLED}</li> 65 * <li>{@link WifiManager#WIFI_STATE_ENABLED}</li> 66 * <li>{@link WifiManager#WIFI_STATE_DISABLING}</li> 67 * <li>{@link WifiManager#WIFI_STATE_ENABLING}</li> 68 * <li>{@link WifiManager#WIFI_STATE_UNKNOWN}</li> 69 * <p> 70 * 71 * @param state The new state of wifi. 72 */ onWifiStateChanged(int state)73 void onWifiStateChanged(int state); 74 } 75 CarWifiManager(Context context, Lifecycle lifecycle)76 public CarWifiManager(Context context, Lifecycle lifecycle) { 77 mContext = context; 78 mLifecycle = lifecycle; 79 mLifecycle.addObserver(this); 80 mWifiManager = mContext.getSystemService(WifiManager.class); 81 mWorkerThread = new HandlerThread(TAG 82 + "{" + Integer.toHexString(System.identityHashCode(this)) + "}", 83 android.os.Process.THREAD_PRIORITY_BACKGROUND); 84 mWorkerThread.start(); 85 mWifiTracker = WifiUtil.createWifiPickerTracker(lifecycle, context, 86 new Handler(Looper.getMainLooper()), mWorkerThread.getThreadHandler(), 87 /* listener= */ this); 88 } 89 90 /** 91 * Lifecycle method to clean up worker thread on destroy. 92 */ 93 @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY) 94 @MainThread onDestroy()95 public void onDestroy() { 96 if (mWorkerThread != null) { 97 mWorkerThread.quit(); 98 } 99 mLifecycle.removeObserver(this); 100 } 101 102 /** 103 * Adds {@link Listener}. 104 */ addListener(Listener listener)105 public boolean addListener(Listener listener) { 106 return mListeners.add(listener); 107 } 108 109 /** 110 * Removes {@link Listener}. 111 */ removeListener(Listener listener)112 public boolean removeListener(Listener listener) { 113 return mListeners.remove(listener); 114 } 115 116 /** 117 * Returns the currently connected Wi-Fi entry or {@code null} if there is no Wi-Fi 118 * network connected. 119 */ 120 @Nullable getConnectedWifiEntry()121 public WifiEntry getConnectedWifiEntry() { 122 if (mWifiManager.isWifiEnabled()) { 123 return mWifiTracker.getConnectedWifiEntry(); 124 } 125 return null; 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 @Override onWifiEntriesChanged()225 public void onWifiEntriesChanged() { 226 for (Listener listener : mListeners) { 227 listener.onWifiEntriesChanged(); 228 } 229 } 230 231 @Override onNumSavedNetworksChanged()232 public void onNumSavedNetworksChanged() { 233 } 234 235 @Override onNumSavedSubscriptionsChanged()236 public void onNumSavedSubscriptionsChanged() { 237 } 238 239 @Override onWifiStateChanged()240 public void onWifiStateChanged() { 241 int state = mWifiTracker.getWifiState(); 242 for (Listener listener : mListeners) { 243 listener.onWifiStateChanged(state); 244 } 245 } 246 } 247