1/* 2 * Copyright (C) 2016 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 com.android.server.wifi; 18 19import android.text.TextUtils; 20import android.util.Log; 21 22/** 23 * Provide functions for making changes to WiFi country code. 24 * This Country Code is from MCC or phone default setting. This class sends Country Code 25 * to driver through wpa_supplicant when WifiStateMachine marks current state as ready 26 * using setReadyForChange(true). 27 */ 28public class WifiCountryCode { 29 private static final String TAG = "WifiCountryCode"; 30 private final WifiNative mWifiNative; 31 private boolean DBG = false; 32 private boolean mReady = false; 33 34 /** config option that indicate whether or not to reset country code to default when 35 * cellular radio indicates country code loss 36 */ 37 private boolean mRevertCountryCodeOnCellularLoss; 38 private String mDefaultCountryCode = null; 39 private String mTelephonyCountryCode = null; 40 private String mCurrentCountryCode = null; 41 42 public WifiCountryCode( 43 WifiNative wifiNative, 44 String oemDefaultCountryCode, 45 String persistentCountryCode, 46 boolean revertCountryCodeOnCellularLoss) { 47 48 mWifiNative = wifiNative; 49 mRevertCountryCodeOnCellularLoss = revertCountryCodeOnCellularLoss; 50 51 if (!TextUtils.isEmpty(persistentCountryCode)) { 52 mDefaultCountryCode = persistentCountryCode.toUpperCase(); 53 } else if (!TextUtils.isEmpty(oemDefaultCountryCode)) { 54 mDefaultCountryCode = oemDefaultCountryCode.toUpperCase(); 55 } else { 56 if (mRevertCountryCodeOnCellularLoss) { 57 Log.w(TAG, "config_wifi_revert_country_code_on_cellular_loss is set, " 58 + "but there is no default country code."); 59 mRevertCountryCodeOnCellularLoss = false; 60 return; 61 } 62 } 63 64 if (mRevertCountryCodeOnCellularLoss) { 65 Log.d(TAG, "Country code will be reverted to " + mDefaultCountryCode 66 + " on MCC loss"); 67 } 68 } 69 70 /** 71 * Enable verbose logging for WifiCountryCode. 72 */ 73 public void enableVerboseLogging(int verbose) { 74 if (verbose > 0) { 75 DBG = true; 76 } else { 77 DBG = false; 78 } 79 } 80 81 /** 82 * This is called when sim card is removed. 83 * In this case we should invalid all other country codes except the 84 * phone default one. 85 */ 86 public synchronized void simCardRemoved() { 87 if (DBG) Log.d(TAG, "SIM Card Removed"); 88 // SIM card is removed, we need to reset the country code to phone default. 89 if (mRevertCountryCodeOnCellularLoss) { 90 mTelephonyCountryCode = null; 91 if (mReady) { 92 updateCountryCode(); 93 } 94 } 95 } 96 97 /** 98 * This is called when airplane mode is enabled. 99 * In this case we should invalidate all other country code except the 100 * phone default one. 101 */ 102 public synchronized void airplaneModeEnabled() { 103 if (DBG) Log.d(TAG, "Airplane Mode Enabled"); 104 mTelephonyCountryCode = null; 105 // Airplane mode is enabled, we need to reset the country code to phone default. 106 if (mRevertCountryCodeOnCellularLoss) { 107 mTelephonyCountryCode = null; 108 // Country code will be set upon when wpa_supplicant starts next time. 109 } 110 } 111 112 /** 113 * Change the state to indicates if wpa_supplicant is ready to handle country code changing 114 * request or not. 115 * We call native code to request country code changes only when wpa_supplicant is 116 * started but not yet L2 connected. 117 */ 118 public synchronized void setReadyForChange(boolean ready) { 119 if (DBG) Log.d(TAG, "Set ready: " + ready); 120 mReady = ready; 121 // We are ready to set country code now. 122 // We need to post pending country code request. 123 if (mReady) { 124 updateCountryCode(); 125 } 126 } 127 128 /** 129 * Handle country code change request. 130 * @param countryCode The country code intended to set. 131 * This is supposed to be from Telephony service. 132 * otherwise we think it is from other applications. 133 * @return Returns true if the country code passed in is acceptable. 134 */ 135 public synchronized boolean setCountryCode(String countryCode, boolean persist) { 136 if (DBG) Log.d(TAG, "Receive set country code request: " + countryCode); 137 // Ignore empty country code. 138 if (TextUtils.isEmpty(countryCode)) { 139 if (DBG) Log.d(TAG, "Ignore empty country code"); 140 return false; 141 } 142 if (persist) { 143 mDefaultCountryCode = countryCode; 144 } 145 mTelephonyCountryCode = countryCode.toUpperCase(); 146 // If wpa_supplicant is ready we set the country code now, otherwise it will be 147 // set once wpa_supplicant is ready. 148 if (mReady) { 149 updateCountryCode(); 150 } 151 return true; 152 } 153 154 /** 155 * Method to get the Country Code that was sent to wpa_supplicant. 156 * 157 * @return Returns the local copy of the Country Code that was sent to the driver upon 158 * setReadyForChange(true). 159 * If wpa_supplicant was never started, this may be null even if a SIM reported a valid 160 * country code. 161 * Returns null if no Country Code was sent to driver. 162 */ 163 public synchronized String getCountryCodeSentToDriver() { 164 return mCurrentCountryCode; 165 } 166 167 /** 168 * Method to return the currently reported Country Code from the SIM or phone default setting. 169 * 170 * @return The currently reported Country Code from the SIM. If there is no Country Code 171 * reported from SIM, a phone default Country Code will be returned. 172 * Returns null when there is no Country Code available. 173 */ 174 public synchronized String getCountryCode() { 175 return pickCountryCode(); 176 } 177 178 private void updateCountryCode() { 179 if (DBG) Log.d(TAG, "Update country code"); 180 String country = pickCountryCode(); 181 // We do not check if the country code equals the current one. 182 // There are two reasons: 183 // 1. Wpa supplicant may silently modify the country code. 184 // 2. If Wifi restarted therefoere wpa_supplicant also restarted, 185 // the country code counld be reset to '00' by wpa_supplicant. 186 if (country != null) { 187 setCountryCodeNative(country); 188 } 189 // We do not set country code if there is no candidate. This is reasonable 190 // because wpa_supplicant usually starts with an international safe country 191 // code setting: '00'. 192 } 193 194 private String pickCountryCode() { 195 if (mTelephonyCountryCode != null) { 196 return mTelephonyCountryCode; 197 } 198 if (mDefaultCountryCode != null) { 199 return mDefaultCountryCode; 200 } 201 // If there is no candidate country code we will return null. 202 return null; 203 } 204 205 private boolean setCountryCodeNative(String country) { 206 if (mWifiNative.setCountryCode(country)) { 207 Log.d(TAG, "Succeeded to set country code to: " + country); 208 mCurrentCountryCode = country; 209 return true; 210 } 211 Log.d(TAG, "Failed to set country code to: " + country); 212 return false; 213 } 214} 215 216