1/* 2 * Copyright (C) 2018 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 static android.telephony.TelephonyManager.CALL_STATE_IDLE; 20import static android.telephony.TelephonyManager.CALL_STATE_OFFHOOK; 21import static android.telephony.TelephonyManager.CALL_STATE_RINGING; 22 23import android.content.BroadcastReceiver; 24import android.content.Context; 25import android.content.Intent; 26import android.content.IntentFilter; 27import android.net.wifi.WifiManager; 28import android.os.Looper; 29import android.telephony.PhoneStateListener; 30import android.telephony.TelephonyManager; 31import android.util.Log; 32 33import com.android.internal.R; 34 35import java.io.FileDescriptor; 36import java.io.PrintWriter; 37import java.util.List; 38 39/** 40 * This class provides the Support for SAR to control WiFi TX power limits. 41 * It deals with the following: 42 * - Tracking the STA state through calls from the ClientModeManager. 43 * - Tracking the state of the Cellular calls or data. 44 * - Based on above, selecting the SAR profile to use and programming it in wifi hal. 45 */ 46public class SarManager { 47 48 /* For Logging */ 49 private static final String TAG = "WifiSarManager"; 50 private boolean mVerboseLoggingEnabled = true; 51 52 /* Configuration for SAR */ 53 private boolean mEnableSarTxPowerLimit; 54 55 /* Current SAR Scenario */ 56 private int mCurrentSarScenario = WifiNative.TX_POWER_SCENARIO_NORMAL; 57 58 /* Booleans for Cell and wifi states */ 59 private boolean mCellOn = false; 60 private boolean mWifiStaEnabled = false; 61 /** 62 * Other parameters passed in or created in the constructor. 63 */ 64 private final Context mContext; 65 private final TelephonyManager mTelephonyManager; 66 private final WifiPhoneStateListener mPhoneStateListener; 67 private final WifiNative mWifiNative; 68 private final Looper mLooper; 69 70 /** 71 * Create new instance of SarManager. 72 */ 73 SarManager(Context context, 74 TelephonyManager telephonyManager, 75 Looper looper, 76 WifiNative wifiNative) { 77 mContext = context; 78 mTelephonyManager = telephonyManager; 79 mWifiNative = wifiNative; 80 mLooper = looper; 81 mPhoneStateListener = new WifiPhoneStateListener(looper); 82 83 registerListeners(); 84 } 85 86 /** 87 * Starts the SAR Manager by initializing the different listeners 88 */ 89 private void registerListeners() { 90 /* First read the configuration for SAR Support */ 91 mEnableSarTxPowerLimit = mContext.getResources().getBoolean( 92 R.bool.config_wifi_framework_enable_voice_call_sar_tx_power_limit); 93 94 /* Only Start listening for events if SAR is enabled */ 95 if (mEnableSarTxPowerLimit) { 96 Log.d(TAG, "Registering Listeners for the SAR Manager"); 97 98 /* Listen for Phone State changes */ 99 registerPhoneListener(); 100 } 101 } 102 103 /** 104 * Report Cell state event 105 */ 106 private void onCellStateChangeEvent(int state) { 107 boolean currentCellOn = mCellOn; 108 109 switch (state) { 110 case CALL_STATE_OFFHOOK: 111 case CALL_STATE_RINGING: 112 mCellOn = true; 113 break; 114 115 case CALL_STATE_IDLE: 116 mCellOn = false; 117 break; 118 119 default: 120 Log.e(TAG, "Invalid Cell State: " + state); 121 } 122 123 if (mCellOn != currentCellOn) { 124 updateSarScenario(); 125 } 126 } 127 128 /** 129 * Update Wifi Client State 130 */ 131 public void setClientWifiState(int state) { 132 /* No action is taken if SAR is not enabled */ 133 if (!mEnableSarTxPowerLimit) return; 134 135 if (state == WifiManager.WIFI_STATE_DISABLED && mWifiStaEnabled) { 136 mWifiStaEnabled = false; 137 } else if (state == WifiManager.WIFI_STATE_ENABLED && !mWifiStaEnabled) { 138 mWifiStaEnabled = true; 139 140 /* Since no wifi interface was up, 141 time for SAR scenario to take effect */ 142 sendTxPowerScenario(mCurrentSarScenario); 143 } 144 } 145 146 /** 147 * Enable/disable verbose logging. 148 */ 149 public void enableVerboseLogging(int verbose) { 150 Log.d(TAG, "Inside enableVerboseLogging: " + verbose); 151 if (verbose > 0) { 152 mVerboseLoggingEnabled = true; 153 } else { 154 mVerboseLoggingEnabled = false; 155 } 156 } 157 158 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 159 pw.println("*** WiFi SAR Manager Dump ***"); 160 pw.println("Current SAR Scenario is " + scenarioToString(mCurrentSarScenario)); 161 } 162 163 /** 164 * Register the phone listener. 165 */ 166 private void registerPhoneListener() { 167 Log.i(TAG, "Registering for telephony call state changes"); 168 mTelephonyManager.listen( 169 mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE); 170 } 171 172 /** 173 * Listen for phone call state events to set/reset TX power limits for SAR requirements. 174 */ 175 private class WifiPhoneStateListener extends PhoneStateListener { 176 WifiPhoneStateListener(Looper looper) { 177 super(looper); 178 } 179 180 @Override 181 public void onCallStateChanged(int state, String incomingNumber) { 182 Log.d(TAG, "Received Phone State Change: " + state); 183 184 /* In case of an unsolicited event */ 185 if (!mEnableSarTxPowerLimit) return; 186 187 onCellStateChangeEvent(state); 188 } 189 } 190 191 /** 192 * update the Current SAR Scenario based on factors including: 193 * - Do we have an ongoing cellular voice call. 194 */ 195 private void updateSarScenario() { 196 int newSarScenario; 197 198 if (mCellOn) { 199 newSarScenario = WifiNative.TX_POWER_SCENARIO_VOICE_CALL; 200 } else { 201 newSarScenario = WifiNative.TX_POWER_SCENARIO_NORMAL; 202 } 203 204 if (newSarScenario != mCurrentSarScenario) { 205 206 // Only update HAL with new scenario if WiFi interface is enabled 207 if (mWifiStaEnabled) { 208 Log.d(TAG, "Sending SAR Scenario #" + scenarioToString(newSarScenario)); 209 sendTxPowerScenario(newSarScenario); 210 } 211 212 mCurrentSarScenario = newSarScenario; 213 } 214 } 215 216 /** 217 * sendTxPowerScenario() 218 * Update HAL with the new power scenario. 219 */ 220 private void sendTxPowerScenario(int newSarScenario) { 221 if (!mWifiNative.selectTxPowerScenario(newSarScenario)) { 222 Log.e(TAG, "Failed to set TX power scenario"); 223 } 224 } 225 226 /** 227 * Convert SAR Scenario to string 228 */ 229 private String scenarioToString(int scenario) { 230 String str; 231 switch(scenario) { 232 case WifiNative.TX_POWER_SCENARIO_NORMAL: 233 str = "TX_POWER_SCENARIO_NORMAL"; 234 break; 235 case WifiNative.TX_POWER_SCENARIO_VOICE_CALL: 236 str = "TX_POWER_SCENARIO_VOICE_CALL"; 237 break; 238 default: 239 str = "Invalid Scenario"; 240 break; 241 } 242 243 return str; 244 } 245} 246