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