summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAhmed ElArabawy <arabawy@google.com>2018-03-09 10:30:50 -0800
committerAhmed ElArabawy <arabawy@google.com>2018-05-02 16:47:03 -0700
commitd55d1c65e5f4569652492828e4ab3eb201921ae8 (patch)
treeb1aedba7810af11c51f59900aba9fb3ae27b9a97
parent6b9f7ba3c20a01689c1027043b6e6eb5b253348e (diff)
WiFi: Move SAR implementation to SarManager
This commit is the first stage of extending SAR Support in WiFi. This stage include removing SAR handling from the WifiStateMachine and putting it in a separate SarManager. No new functionality is added yet in this stage. Note that unit test cases for SAR related functionality in WifiStateMachine are removed and added to SarManager Bug: 65174506 Test: Run Wifi unit test suite Test: ./frameworks/opt/net/wifi/tests/wifitests/runtests.sh Change-Id: I0a08180cfff22002f75a6966009e62b9c66044c3 Signed-off-by: Ahmed ElArabawy <arabawy@google.com>
-rw-r--r--service/java/com/android/server/wifi/SarManager.java245
-rw-r--r--service/java/com/android/server/wifi/WifiInjector.java10
-rw-r--r--service/java/com/android/server/wifi/WifiStateMachine.java72
-rw-r--r--tests/wifitests/src/com/android/server/wifi/SarManagerTest.java256
-rw-r--r--tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java161
5 files changed, 524 insertions, 220 deletions
diff --git a/service/java/com/android/server/wifi/SarManager.java b/service/java/com/android/server/wifi/SarManager.java
new file mode 100644
index 000000000..da48a8537
--- /dev/null
+++ b/service/java/com/android/server/wifi/SarManager.java
@@ -0,0 +1,245 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wifi;
+
+import static android.telephony.TelephonyManager.CALL_STATE_IDLE;
+import static android.telephony.TelephonyManager.CALL_STATE_OFFHOOK;
+import static android.telephony.TelephonyManager.CALL_STATE_RINGING;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.wifi.WifiManager;
+import android.os.Looper;
+import android.telephony.PhoneStateListener;
+import android.telephony.TelephonyManager;
+import android.util.Log;
+
+import com.android.internal.R;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.List;
+
+/**
+ * This class provides the Support for SAR to control WiFi TX power limits.
+ * It deals with the following:
+ * - Tracking the STA state through calls from the ClientModeManager.
+ * - Tracking the state of the Cellular calls or data.
+ * - Based on above, selecting the SAR profile to use and programming it in wifi hal.
+ */
+public class SarManager {
+
+ /* For Logging */
+ private static final String TAG = "WifiSarManager";
+ private boolean mVerboseLoggingEnabled = true;
+
+ /* Configuration for SAR */
+ private boolean mEnableSarTxPowerLimit;
+
+ /* Current SAR Scenario */
+ private int mCurrentSarScenario = WifiNative.TX_POWER_SCENARIO_NORMAL;
+
+ /* Booleans for Cell and wifi states */
+ private boolean mCellOn = false;
+ private boolean mWifiStaEnabled = false;
+ /**
+ * Other parameters passed in or created in the constructor.
+ */
+ private final Context mContext;
+ private final TelephonyManager mTelephonyManager;
+ private final WifiPhoneStateListener mPhoneStateListener;
+ private final WifiNative mWifiNative;
+ private final Looper mLooper;
+
+ /**
+ * Create new instance of SarManager.
+ */
+ SarManager(Context context,
+ TelephonyManager telephonyManager,
+ Looper looper,
+ WifiNative wifiNative) {
+ mContext = context;
+ mTelephonyManager = telephonyManager;
+ mWifiNative = wifiNative;
+ mLooper = looper;
+ mPhoneStateListener = new WifiPhoneStateListener(looper);
+
+ registerListeners();
+ }
+
+ /**
+ * Starts the SAR Manager by initializing the different listeners
+ */
+ private void registerListeners() {
+ /* First read the configuration for SAR Support */
+ mEnableSarTxPowerLimit = mContext.getResources().getBoolean(
+ R.bool.config_wifi_framework_enable_voice_call_sar_tx_power_limit);
+
+ /* Only Start listening for events if SAR is enabled */
+ if (mEnableSarTxPowerLimit) {
+ Log.d(TAG, "Registering Listeners for the SAR Manager");
+
+ /* Listen for Phone State changes */
+ registerPhoneListener();
+ }
+ }
+
+ /**
+ * Report Cell state event
+ */
+ private void onCellStateChangeEvent(int state) {
+ boolean currentCellOn = mCellOn;
+
+ switch (state) {
+ case CALL_STATE_OFFHOOK:
+ case CALL_STATE_RINGING:
+ mCellOn = true;
+ break;
+
+ case CALL_STATE_IDLE:
+ mCellOn = false;
+ break;
+
+ default:
+ Log.e(TAG, "Invalid Cell State: " + state);
+ }
+
+ if (mCellOn != currentCellOn) {
+ updateSarScenario();
+ }
+ }
+
+ /**
+ * Update Wifi Client State
+ */
+ public void setClientWifiState(int state) {
+ /* No action is taken if SAR is not enabled */
+ if (!mEnableSarTxPowerLimit) return;
+
+ if (state == WifiManager.WIFI_STATE_DISABLED && mWifiStaEnabled) {
+ mWifiStaEnabled = false;
+ } else if (state == WifiManager.WIFI_STATE_ENABLED && !mWifiStaEnabled) {
+ mWifiStaEnabled = true;
+
+ /* Since no wifi interface was up,
+ time for SAR scenario to take effect */
+ sendTxPowerScenario(mCurrentSarScenario);
+ }
+ }
+
+ /**
+ * Enable/disable verbose logging.
+ */
+ public void enableVerboseLogging(int verbose) {
+ Log.d(TAG, "Inside enableVerboseLogging: " + verbose);
+ if (verbose > 0) {
+ mVerboseLoggingEnabled = true;
+ } else {
+ mVerboseLoggingEnabled = false;
+ }
+ }
+
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ pw.println("*** WiFi SAR Manager Dump ***");
+ pw.println("Current SAR Scenario is " + scenarioToString(mCurrentSarScenario));
+ }
+
+ /**
+ * Register the phone listener.
+ */
+ private void registerPhoneListener() {
+ Log.i(TAG, "Registering for telephony call state changes");
+ mTelephonyManager.listen(
+ mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
+ }
+
+ /**
+ * Listen for phone call state events to set/reset TX power limits for SAR requirements.
+ */
+ private class WifiPhoneStateListener extends PhoneStateListener {
+ WifiPhoneStateListener(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void onCallStateChanged(int state, String incomingNumber) {
+ Log.d(TAG, "Received Phone State Change: " + state);
+
+ /* In case of an unsolicited event */
+ if (!mEnableSarTxPowerLimit) return;
+
+ onCellStateChangeEvent(state);
+ }
+ }
+
+ /**
+ * update the Current SAR Scenario based on factors including:
+ * - Do we have an ongoing cellular voice call.
+ */
+ private void updateSarScenario() {
+ int newSarScenario;
+
+ if (mCellOn) {
+ newSarScenario = WifiNative.TX_POWER_SCENARIO_VOICE_CALL;
+ } else {
+ newSarScenario = WifiNative.TX_POWER_SCENARIO_NORMAL;
+ }
+
+ if (newSarScenario != mCurrentSarScenario) {
+
+ // Only update HAL with new scenario if WiFi interface is enabled
+ if (mWifiStaEnabled) {
+ Log.d(TAG, "Sending SAR Scenario #" + scenarioToString(newSarScenario));
+ sendTxPowerScenario(newSarScenario);
+ }
+
+ mCurrentSarScenario = newSarScenario;
+ }
+ }
+
+ /**
+ * sendTxPowerScenario()
+ * Update HAL with the new power scenario.
+ */
+ private void sendTxPowerScenario(int newSarScenario) {
+ if (!mWifiNative.selectTxPowerScenario(newSarScenario)) {
+ Log.e(TAG, "Failed to set TX power scenario");
+ }
+ }
+
+ /**
+ * Convert SAR Scenario to string
+ */
+ private String scenarioToString(int scenario) {
+ String str;
+ switch(scenario) {
+ case WifiNative.TX_POWER_SCENARIO_NORMAL:
+ str = "TX_POWER_SCENARIO_NORMAL";
+ break;
+ case WifiNative.TX_POWER_SCENARIO_VOICE_CALL:
+ str = "TX_POWER_SCENARIO_VOICE_CALL";
+ break;
+ default:
+ str = "Invalid Scenario";
+ break;
+ }
+
+ return str;
+ }
+}
diff --git a/service/java/com/android/server/wifi/WifiInjector.java b/service/java/com/android/server/wifi/WifiInjector.java
index a64075006..7fc49ece2 100644
--- a/service/java/com/android/server/wifi/WifiInjector.java
+++ b/service/java/com/android/server/wifi/WifiInjector.java
@@ -137,6 +137,7 @@ public class WifiInjector {
private final WakeupController mWakeupController;
private final INetworkManagementService mNwManagementService;
private final ScanRequestProxy mScanRequestProxy;
+ private final SarManager mSarManager;
private final boolean mUseRealLogger;
@@ -252,10 +253,13 @@ public class WifiInjector {
mWifiPermissionsUtil, mWifiMetrics, mClock);
// mWifiStateMachine has an implicit dependency on mJavaRuntime due to WifiDiagnostics.
mJavaRuntime = Runtime.getRuntime();
+ mSarManager = new SarManager(mContext, makeTelephonyManager(), wifiStateMachineLooper,
+ mWifiNative);
mWifiStateMachine = new WifiStateMachine(mContext, mFrameworkFacade,
wifiStateMachineLooper, UserManager.get(mContext),
this, mBackupManagerProxy, mCountryCode, mWifiNative,
- new WrongPasswordNotifier(mContext, mFrameworkFacade));
+ new WrongPasswordNotifier(mContext, mFrameworkFacade),
+ mSarManager);
IBinder b = mFrameworkFacade.getService(Context.NETWORKMANAGEMENT_SERVICE);
mWifiStateMachinePrime = new WifiStateMachinePrime(this, mContext, wifiStateMachineLooper,
mWifiNative, new DefaultModeManager(mContext, wifiStateMachineLooper),
@@ -358,6 +362,10 @@ public class WifiInjector {
return mWifiApConfigStore;
}
+ public SarManager getSarManager() {
+ return mSarManager;
+ }
+
public WifiStateMachine getWifiStateMachine() {
return mWifiStateMachine;
}
diff --git a/service/java/com/android/server/wifi/WifiStateMachine.java b/service/java/com/android/server/wifi/WifiStateMachine.java
index af0b8c257..6b0bec244 100644
--- a/service/java/com/android/server/wifi/WifiStateMachine.java
+++ b/service/java/com/android/server/wifi/WifiStateMachine.java
@@ -21,8 +21,6 @@ import static android.net.wifi.WifiManager.WIFI_STATE_DISABLING;
import static android.net.wifi.WifiManager.WIFI_STATE_ENABLED;
import static android.net.wifi.WifiManager.WIFI_STATE_ENABLING;
import static android.net.wifi.WifiManager.WIFI_STATE_UNKNOWN;
-import static android.telephony.TelephonyManager.CALL_STATE_IDLE;
-import static android.telephony.TelephonyManager.CALL_STATE_OFFHOOK;
import android.app.ActivityManager;
import android.app.PendingIntent;
@@ -81,7 +79,6 @@ import android.os.UserManager;
import android.os.WorkSource;
import android.provider.Settings;
import android.system.OsConstants;
-import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Log;
@@ -199,6 +196,7 @@ public class WifiStateMachine extends StateMachine {
private final WifiCountryCode mCountryCode;
// Object holding most recent wifi score report and bad Linkspeed count
private final WifiScoreReport mWifiScoreReport;
+ private final SarManager mSarManager;
public WifiScoreReport getWifiScoreReport() {
return mWifiScoreReport;
}
@@ -643,9 +641,6 @@ public class WifiStateMachine extends StateMachine {
/* Indicates that diagnostics should time out a connection start event. */
private static final int CMD_DIAGS_CONNECT_TIMEOUT = BASE + 252;
- /* Used to set the tx power limit for SAR during the start of a phone call. */
- private static final int CMD_SELECT_TX_POWER_SCENARIO = BASE + 253;
-
// Start subscription provisioning with a given provider
private static final int CMD_START_SUBSCRIPTION_PROVISIONING = BASE + 254;
@@ -709,7 +704,6 @@ public class WifiStateMachine extends StateMachine {
private final int mThresholdMinimumRssi24;
private final boolean mEnableChipWakeUpWhenAssociated;
private final boolean mEnableRssiPollWhenAssociated;
- private final boolean mEnableVoiceCallSarTxPowerLimit;
int mRunningBeaconCount = 0;
@@ -771,7 +765,6 @@ public class WifiStateMachine extends StateMachine {
}
return mTelephonyManager;
}
- private final WifiPhoneStateListener mPhoneStateListener;
private final IBatteryStats mBatteryStats;
@@ -789,7 +782,8 @@ public class WifiStateMachine extends StateMachine {
UserManager userManager, WifiInjector wifiInjector,
BackupManagerProxy backupManagerProxy, WifiCountryCode countryCode,
WifiNative wifiNative,
- WrongPasswordNotifier wrongPasswordNotifier) {
+ WrongPasswordNotifier wrongPasswordNotifier,
+ SarManager sarManager) {
super("WifiStateMachine", looper);
mWifiInjector = wifiInjector;
mWifiMetrics = mWifiInjector.getWifiMetrics();
@@ -801,6 +795,7 @@ public class WifiStateMachine extends StateMachine {
mWifiNative = wifiNative;
mBackupManagerProxy = backupManagerProxy;
mWrongPasswordNotifier = wrongPasswordNotifier;
+ mSarManager = sarManager;
// TODO refactor WifiNative use of context out into it's own class
mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0, NETWORKTYPE, "");
@@ -827,7 +822,6 @@ public class WifiStateMachine extends StateMachine {
mFacade.makeSupplicantStateTracker(context, mWifiConfigManager, getHandler());
mLinkProperties = new LinkProperties();
- mPhoneStateListener = new WifiPhoneStateListener(looper);
mMcastLockManagerFilterController = new McastLockManagerFilterController();
mNetworkInfo.setIsAvailable(false);
@@ -922,8 +916,6 @@ public class WifiStateMachine extends StateMachine {
R.integer.config_wifi_framework_wifi_score_bad_rssi_threshold_5GHz);
mThresholdMinimumRssi24 = context.getResources().getInteger(
R.integer.config_wifi_framework_wifi_score_bad_rssi_threshold_24GHz);
- mEnableVoiceCallSarTxPowerLimit = mContext.getResources().getBoolean(
- R.bool.config_wifi_framework_enable_voice_call_sar_tx_power_limit);
mEnableChipWakeUpWhenAssociated = true;
mEnableRssiPollWhenAssociated = true;
@@ -3216,40 +3208,6 @@ public class WifiStateMachine extends StateMachine {
}
}
- /**
- * Register the phone listener if we need to set/reset the power limits during voice call for
- * this device.
- */
- private void maybeRegisterPhoneListener() {
- if (mEnableVoiceCallSarTxPowerLimit) {
- logd("Registering for telephony call state changes");
- getTelephonyManager().listen(
- mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
- }
- }
-
- /**
- * Listen for phone call state events to set/reset TX power limits for SAR requirements.
- */
- private class WifiPhoneStateListener extends PhoneStateListener {
- WifiPhoneStateListener(Looper looper) {
- super(looper);
- }
-
- @Override
- public void onCallStateChanged(int state, String incomingNumber) {
- if (mEnableVoiceCallSarTxPowerLimit) {
- if (state == CALL_STATE_OFFHOOK) {
- sendMessage(CMD_SELECT_TX_POWER_SCENARIO,
- WifiNative.TX_POWER_SCENARIO_VOICE_CALL);
- } else if (state == CALL_STATE_IDLE) {
- sendMessage(CMD_SELECT_TX_POWER_SCENARIO,
- WifiNative.TX_POWER_SCENARIO_NORMAL);
- }
- }
- }
- }
-
/**
* Dynamically change the MAC address to use the locally randomized
* MAC address generated for each network.
@@ -3416,7 +3374,6 @@ public class WifiStateMachine extends StateMachine {
Log.e(TAG, "Failed to load from config store");
}
maybeRegisterNetworkFactory();
- maybeRegisterPhoneListener();
break;
case CMD_SCREEN_STATE_CHANGED:
handleScreenStateChanged(message.arg1 != 0);
@@ -3448,7 +3405,6 @@ public class WifiStateMachine extends StateMachine {
case CMD_ROAM_WATCHDOG_TIMER:
case CMD_DISABLE_P2P_WATCHDOG_TIMER:
case CMD_DISABLE_EPHEMERAL_NETWORK:
- case CMD_SELECT_TX_POWER_SCENARIO:
messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
break;
case CMD_SET_OPERATIONAL_MODE:
@@ -3762,14 +3718,6 @@ public class WifiStateMachine extends StateMachine {
* driver are changed to reduce interference with bluetooth
*/
mWifiNative.setBluetoothCoexistenceScanMode(mInterfaceName, mBluetoothConnectionActive);
- // Check if there is a voice call on-going and set/reset the tx power limit appropriately.
- if (mEnableVoiceCallSarTxPowerLimit) {
- if (getTelephonyManager().isOffhook()) {
- sendMessage(CMD_SELECT_TX_POWER_SCENARIO, WifiNative.TX_POWER_SCENARIO_VOICE_CALL);
- } else {
- sendMessage(CMD_SELECT_TX_POWER_SCENARIO, WifiNative.TX_POWER_SCENARIO_NORMAL);
- }
- }
// initialize network state
setNetworkDetailedState(DetailedState.DISCONNECTED);
@@ -3903,6 +3851,8 @@ public class WifiStateMachine extends StateMachine {
mWifiMetrics.setWifiState(WifiMetricsProto.WifiLog.WIFI_DISCONNECTED);
// Inform p2p service that wifi is up and ready when applicable
p2pSendMessage(WifiStateMachine.CMD_ENABLE_P2P);
+ // Inform sar manager that wifi is Enabled
+ mSarManager.setClientWifiState(WifiManager.WIFI_STATE_ENABLED);
}
@Override
@@ -3916,6 +3866,8 @@ public class WifiStateMachine extends StateMachine {
mWifiConnectivityManager.setWifiEnabled(false);
// Inform metrics that Wifi is being disabled (Toggled, airplane enabled, etc)
mWifiMetrics.setWifiState(WifiMetricsProto.WifiLog.WIFI_DISABLED);
+ // Inform sar manager that wifi is being disabled
+ mSarManager.setClientWifiState(WifiManager.WIFI_STATE_DISABLED);
if (!mWifiNative.removeAllNetworks(mInterfaceName)) {
loge("Failed to remove networks on exiting connect mode");
@@ -4530,14 +4482,6 @@ public class WifiStateMachine extends StateMachine {
case CMD_ENABLE_WIFI_CONNECTIVITY_MANAGER:
mWifiConnectivityManager.enable(message.arg1 == 1 ? true : false);
break;
- case CMD_SELECT_TX_POWER_SCENARIO:
- int txPowerScenario = message.arg1;
- logd("Setting Tx power scenario to " + txPowerScenario);
- if (!mWifiNative.selectTxPowerScenario(txPowerScenario)) {
- loge("Failed to set TX power scenario");
- }
- break;
-
default:
return NOT_HANDLED;
}
diff --git a/tests/wifitests/src/com/android/server/wifi/SarManagerTest.java b/tests/wifitests/src/com/android/server/wifi/SarManagerTest.java
new file mode 100644
index 000000000..163280a39
--- /dev/null
+++ b/tests/wifitests/src/com/android/server/wifi/SarManagerTest.java
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wifi;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.Mockito.*;
+
+import static android.telephony.TelephonyManager.CALL_STATE_IDLE;
+import static android.telephony.TelephonyManager.CALL_STATE_OFFHOOK;
+
+import android.app.test.MockAnswerUtil.AnswerWithArguments;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
+import android.hardware.SensorEvent;
+import android.net.wifi.WifiManager;
+import android.os.Build;
+import android.os.test.TestLooper;
+import android.support.test.filters.SmallTest;
+import android.telephony.PhoneStateListener;
+import android.telephony.TelephonyManager;
+import android.util.Log;
+
+import com.android.internal.R;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.ArgumentCaptor;
+import org.mockito.InOrder;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * unit tests for {@link com.android.server.wifi.SarManager}.
+ */
+@SmallTest
+public class SarManagerTest {
+ private static final String TAG = "WifiSarManagerTest";
+ private static final String OP_PACKAGE_NAME = "com.xxx";
+
+ private void enableDebugLogs() {
+ mSarMgr.enableVerboseLogging(1);
+ }
+
+ private MockResources getMockResources() {
+ MockResources resources = new MockResources();
+ return resources;
+ }
+
+ private SarManager mSarMgr;
+ private TestLooper mLooper;
+ private MockResources mResources;
+ private PhoneStateListener mPhoneStateListener;
+
+ @Mock private Context mContext;
+ @Mock TelephonyManager mTelephonyManager;
+ @Mock private ApplicationInfo mMockApplInfo;
+ @Mock WifiNative mWifiNative;
+
+ @Before
+ public void setUp() throws Exception {
+ Log.e(TAG, "Setting Up ...");
+
+ // Ensure Looper exists
+ mLooper = new TestLooper();
+
+ MockitoAnnotations.initMocks(this);
+
+ /* Default behavior is to return with success */
+ when(mWifiNative.selectTxPowerScenario(anyInt())).thenReturn(true);
+
+ mResources = getMockResources();
+
+ when(mContext.getResources()).thenReturn(mResources);
+ mMockApplInfo.targetSdkVersion = Build.VERSION_CODES.P;
+ when(mContext.getApplicationInfo()).thenReturn(mMockApplInfo);
+ when(mContext.getOpPackageName()).thenReturn(OP_PACKAGE_NAME);
+ }
+
+ @After
+ public void cleanUp() throws Exception {
+ mSarMgr = null;
+ mLooper = null;
+ mContext = null;
+ mResources = null;
+ }
+
+ /**
+ * Helper function to set configuration for SAR and create the SAR Manager
+ *
+ */
+ private void createSarManager(boolean isSarEnabled) {
+ mResources.setBoolean(
+ R.bool.config_wifi_framework_enable_voice_call_sar_tx_power_limit, isSarEnabled);
+
+ mSarMgr = new SarManager(mContext, mTelephonyManager, mLooper.getLooper(),
+ mWifiNative);
+
+ if (isSarEnabled) {
+ /* Capture the PhoneStateListener */
+ ArgumentCaptor<PhoneStateListener> phoneStateListenerCaptor =
+ ArgumentCaptor.forClass(PhoneStateListener.class);
+ verify(mTelephonyManager).listen(phoneStateListenerCaptor.capture(),
+ eq(PhoneStateListener.LISTEN_CALL_STATE));
+ mPhoneStateListener = phoneStateListenerCaptor.getValue();
+ }
+
+ /* Enable logs from SarManager */
+ enableDebugLogs();
+ }
+
+ /**
+ * Test that we do register the telephony call state listener on devices which do support
+ * setting/resetting Tx power limit.
+ */
+ @Test
+ public void testSarMgr_enabledTxPowerScenario_registerPhone() throws Exception {
+ createSarManager(true);
+ verify(mTelephonyManager).listen(any(), eq(PhoneStateListener.LISTEN_CALL_STATE));
+ }
+
+ /**
+ * Test that we do not register the telephony call state listener on devices which
+ * do not support setting/resetting Tx power limit.
+ */
+ @Test
+ public void testSarMgr_disabledTxPowerScenario_registerPhone() throws Exception {
+ createSarManager(false);
+ verify(mTelephonyManager, never()).listen(any(), anyInt());
+ }
+
+ /**
+ * Test that for devices that support setting/resetting Tx Power limits, device sets the proper
+ * Tx power scenario upon receiving {@link TelephonyManager#CALL_STATE_OFFHOOK} when WiFi STA
+ * is enabled
+ * In this case Wifi is enabled first, then off-hook is detected
+ * Expectation is to get {@link WifiNative#TX_POWER_SCENARIO_NORMAL} when WiFi is turned on
+ * followed by {@link WifiNative#TX_POWER_SCENARIO_VOICE_CALL} when OFFHOOK event is detected
+ */
+ @Test
+ public void testSarMgr_enabledTxPowerScenario_wifiOn_offHook() throws Exception {
+ createSarManager(true);
+ assertNotNull(mPhoneStateListener);
+
+ InOrder inOrder = inOrder(mWifiNative);
+
+ /* Enable WiFi State */
+ mSarMgr.setClientWifiState(WifiManager.WIFI_STATE_ENABLED);
+
+ inOrder.verify(mWifiNative).selectTxPowerScenario(
+ eq(WifiNative.TX_POWER_SCENARIO_NORMAL));
+
+ /* Set phone state to OFFHOOK */
+ mPhoneStateListener.onCallStateChanged(CALL_STATE_OFFHOOK, "");
+
+ inOrder.verify(mWifiNative).selectTxPowerScenario(
+ eq(WifiNative.TX_POWER_SCENARIO_VOICE_CALL));
+ }
+
+ /**
+ * Test that for devices that support setting/resetting Tx Power limits, device sets the proper
+ * Tx power scenario upon receiving {@link TelephonyManager#CALL_STATE_OFFHOOK} when WiFi STA
+ * is enabled
+ * In this case off-hook event is detected first, then wifi is turned on
+ * Expectation is to get {@link WifiNative#TX_POWER_SCENARIO_VOICE_CALL} once wifi is turned on
+ */
+ @Test
+ public void testSarMgr_enabledTxPowerScenario_offHook_wifiOn() throws Exception {
+ createSarManager(true);
+ assertNotNull(mPhoneStateListener);
+
+ /* Set phone state to OFFHOOK */
+ mPhoneStateListener.onCallStateChanged(CALL_STATE_OFFHOOK, "");
+
+ /* Enable WiFi State */
+ mSarMgr.setClientWifiState(WifiManager.WIFI_STATE_ENABLED);
+
+ verify(mWifiNative).selectTxPowerScenario(
+ eq(WifiNative.TX_POWER_SCENARIO_VOICE_CALL));
+ }
+
+ /**
+ * Test that for devices that support setting/resetting Tx Power limits, device sets the proper
+ * Tx power scenarios upon receiving {@link TelephonyManager#CALL_STATE_OFFHOOK} and
+ * {@link TelephonyManager#CALL_STATE_OFFHOOK} when WiFi STA is enabled
+ */
+ @Test
+ public void testSarMgr_enabledTxPowerScenario_wifiOn_offHook_onHook() throws Exception {
+ createSarManager(true);
+ assertNotNull(mPhoneStateListener);
+
+ InOrder inOrder = inOrder(mWifiNative);
+
+ /* Enable WiFi State */
+ mSarMgr.setClientWifiState(WifiManager.WIFI_STATE_ENABLED);
+
+ /* Now device should set tx power scenario to NORMAL */
+ inOrder.verify(mWifiNative).selectTxPowerScenario(
+ eq(WifiNative.TX_POWER_SCENARIO_NORMAL));
+
+ /* Set phone state to OFFHOOK */
+ mPhoneStateListener.onCallStateChanged(CALL_STATE_OFFHOOK, "");
+
+ /* Device should set tx power scenario to Voice call */
+ inOrder.verify(mWifiNative).selectTxPowerScenario(
+ eq(WifiNative.TX_POWER_SCENARIO_VOICE_CALL));
+
+ /* Set state back to ONHOOK */
+ mPhoneStateListener.onCallStateChanged(CALL_STATE_IDLE, "");
+
+ /* Device should set tx power scenario to NORMAL again */
+ inOrder.verify(mWifiNative).selectTxPowerScenario(
+ eq(WifiNative.TX_POWER_SCENARIO_NORMAL));
+ }
+
+ /**
+ * Test that for devices that support setting/resetting Tx Power limits, device does not
+ * sets the Tx power scenarios upon receiving {@link TelephonyManager#CALL_STATE_OFFHOOK} and
+ * {@link TelephonyManager#CALL_STATE_OFFHOOK} when WiFi STA is disabled
+ */
+ @Test
+ public void testSarMgr_enabledTxPowerScenario_wifiOff_offHook_onHook() throws Exception {
+ createSarManager(true);
+ assertNotNull(mPhoneStateListener);
+
+ InOrder inOrder = inOrder(mWifiNative);
+
+ /* Set phone state to OFFHOOK */
+ mPhoneStateListener.onCallStateChanged(CALL_STATE_OFFHOOK, "");
+
+ /* Set state back to ONHOOK */
+ mPhoneStateListener.onCallStateChanged(CALL_STATE_IDLE, "");
+
+ /* Device should not set tx power scenario at all */
+ inOrder.verify(mWifiNative, never()).selectTxPowerScenario(anyInt());
+ }
+}
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java b/tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java
index 1907c56b7..60ada8140 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java
@@ -245,8 +245,6 @@ public class WifiStateMachineTest {
private MockResources getMockResources() {
MockResources resources = new MockResources();
resources.setBoolean(R.bool.config_wifi_enable_wifi_firmware_debugging, false);
- resources.setBoolean(
- R.bool.config_wifi_framework_enable_voice_call_sar_tx_power_limit, false);
return resources;
}
@@ -347,6 +345,7 @@ public class WifiStateMachineTest {
@Mock PropertyService mPropertyService;
@Mock BuildProperties mBuildProperties;
@Mock IBinder mPackageManagerBinder;
+ @Mock SarManager mSarManager;
@Mock WifiConfigManager mWifiConfigManager;
@Mock WifiNative mWifiNative;
@Mock WifiConnectivityManager mWifiConnectivityManager;
@@ -491,7 +490,7 @@ public class WifiStateMachineTest {
private void initializeWsm() throws Exception {
mWsm = new WifiStateMachine(mContext, mFrameworkFacade, mLooper.getLooper(),
mUserManager, mWifiInjector, mBackupManagerProxy, mCountryCode, mWifiNative,
- mWrongPasswordNotifier);
+ mWrongPasswordNotifier, mSarManager);
mWsmThread = getWsmHandlerThread(mWsm);
registerAsyncChannel((x) -> {
@@ -1804,6 +1803,7 @@ public class WifiStateMachineTest {
@Test
public void testWifiInfoCleanedUpEnteringExitingConnectModeState() throws Exception {
InOrder inOrder = inOrder(mWifiConnectivityManager);
+ InOrder inOrderSarMgr = inOrder(mSarManager);
Log.i(TAG, mWsm.getCurrentState().getName());
String initialBSSID = "aa:bb:cc:dd:ee:ff";
WifiInfo wifiInfo = mWsm.getWifiInfo();
@@ -1814,6 +1814,7 @@ public class WifiStateMachineTest {
assertEquals(WifiStateMachine.CONNECT_MODE, mWsm.getOperationalModeForTest());
assertEquals(WifiManager.WIFI_STATE_ENABLED, mWsm.syncGetWifiState());
inOrder.verify(mWifiConnectivityManager).setWifiEnabled(eq(true));
+ inOrderSarMgr.verify(mSarManager).setClientWifiState(WifiManager.WIFI_STATE_ENABLED);
assertNull(wifiInfo.getBSSID());
// Send a SUPPLICANT_STATE_CHANGE_EVENT, verify WifiInfo is updated
@@ -1833,6 +1834,7 @@ public class WifiStateMachineTest {
assertEquals("DefaultState", getCurrentState().getName());
assertEquals(WifiManager.WIFI_STATE_DISABLED, mWsm.syncGetWifiState());
inOrder.verify(mWifiConnectivityManager).setWifiEnabled(eq(false));
+ inOrderSarMgr.verify(mSarManager).setClientWifiState(WifiManager.WIFI_STATE_DISABLED);
assertNull(wifiInfo.getBSSID());
assertEquals(SupplicantState.DISCONNECTED, wifiInfo.getSupplicantState());
@@ -1853,6 +1855,7 @@ public class WifiStateMachineTest {
assertEquals(WifiStateMachine.CONNECT_MODE, mWsm.getOperationalModeForTest());
assertEquals(WifiManager.WIFI_STATE_ENABLED, mWsm.syncGetWifiState());
inOrder.verify(mWifiConnectivityManager).setWifiEnabled(eq(true));
+ inOrderSarMgr.verify(mSarManager).setClientWifiState(WifiManager.WIFI_STATE_ENABLED);
assertEquals("DisconnectedState", getCurrentState().getName());
assertEquals(SupplicantState.DISCONNECTED, wifiInfo.getSupplicantState());
assertNull(wifiInfo.getBSSID());
@@ -1947,158 +1950,6 @@ public class WifiStateMachineTest {
}
/**
- * Test that we do register the telephony call state listener on devices which do support
- * setting/resetting Tx power limit.
- */
- @Test
- public void testVoiceCallSar_enabledTxPowerScenario_WifiOn() throws Exception {
- mResources.setBoolean(
- R.bool.config_wifi_framework_enable_voice_call_sar_tx_power_limit, true);
- initializeWsm();
-
- loadComponentsInStaMode();
- assertEquals(WifiStateMachine.CONNECT_MODE, mWsm.getOperationalModeForTest());
- assertEquals("DisconnectedState", getCurrentState().getName());
- assertNotNull(mPhoneStateListener);
- }
-
- /**
- * Test that we do register the telephony call state listener on devices which do support
- * setting/resetting Tx power limit and set the tx power level if we're in state
- * {@link TelephonyManager#CALL_STATE_OFFHOOK}.
- */
- @Test
- public void testVoiceCallSar_enabledTxPowerScenarioCallStateOffHook_WhenWifiTurnedOn()
- throws Exception {
- mResources.setBoolean(
- R.bool.config_wifi_framework_enable_voice_call_sar_tx_power_limit, true);
- initializeWsm();
-
- when(mWifiNative.selectTxPowerScenario(anyInt())).thenReturn(true);
- when(mTelephonyManager.isOffhook()).thenReturn(true);
-
- loadComponentsInStaMode();
- assertEquals(WifiStateMachine.CONNECT_MODE, mWsm.getOperationalModeForTest());
- assertEquals("DisconnectedState", getCurrentState().getName());
- assertNotNull(mPhoneStateListener);
- verify(mWifiNative).selectTxPowerScenario(eq(WifiNative.TX_POWER_SCENARIO_VOICE_CALL));
- }
-
- /**
- * Test that we do register the telephony call state listener on devices which do support
- * setting/resetting Tx power limit and set the tx power level if we're in state
- * {@link TelephonyManager#CALL_STATE_IDLE}.
- */
- @Test
- public void testVoiceCallSar_enabledTxPowerScenarioCallStateIdle_WhenWifiTurnedOn()
- throws Exception {
- mResources.setBoolean(
- R.bool.config_wifi_framework_enable_voice_call_sar_tx_power_limit, true);
- initializeWsm();
-
- when(mWifiNative.selectTxPowerScenario(anyInt())).thenReturn(true);
- when(mTelephonyManager.isIdle()).thenReturn(true);
-
- loadComponentsInStaMode();
- assertEquals(WifiStateMachine.CONNECT_MODE, mWsm.getOperationalModeForTest());
- assertEquals("DisconnectedState", getCurrentState().getName());
- assertNotNull(mPhoneStateListener);
- }
-
- /**
- * Test that we do register the telephony call state listener on devices which do support
- * setting/resetting Tx power limit and set the tx power level if we're in state
- * {@link TelephonyManager#CALL_STATE_OFFHOOK}. This test checks if the
- * {@link WifiNative#selectTxPowerScenario(int)} failure is handled correctly.
- */
- @Test
- public void testVoiceCallSar_enabledTxPowerScenarioCallStateOffHook_WhenWifiTurnedOn_Fails()
- throws Exception {
- mResources.setBoolean(
- R.bool.config_wifi_framework_enable_voice_call_sar_tx_power_limit, true);
- initializeWsm();
-
- when(mWifiNative.selectTxPowerScenario(anyInt())).thenReturn(false);
- when(mTelephonyManager.isOffhook()).thenReturn(true);
-
- loadComponentsInStaMode();
- assertEquals(WifiStateMachine.CONNECT_MODE, mWsm.getOperationalModeForTest());
- assertEquals("DisconnectedState", getCurrentState().getName());
- assertNotNull(mPhoneStateListener);
- verify(mWifiNative).selectTxPowerScenario(eq(WifiNative.TX_POWER_SCENARIO_VOICE_CALL));
- }
-
- /**
- * Test that we invoke the corresponding WifiNative method when
- * {@link PhoneStateListener#onCallStateChanged(int, String)} is invoked with state
- * {@link TelephonyManager#CALL_STATE_OFFHOOK}.
- */
- @Test
- public void testVoiceCallSar_enabledTxPowerScenarioCallStateOffHook_WhenWifiOn()
- throws Exception {
- when(mWifiNative.selectTxPowerScenario(anyInt())).thenReturn(true);
- testVoiceCallSar_enabledTxPowerScenario_WifiOn();
-
- mPhoneStateListener.onCallStateChanged(TelephonyManager.CALL_STATE_OFFHOOK, "");
- mLooper.dispatchAll();
- verify(mWifiNative).selectTxPowerScenario(eq(WifiNative.TX_POWER_SCENARIO_VOICE_CALL));
- }
-
- /**
- * Test that we invoke the corresponding WifiNative method when
- * {@link PhoneStateListener#onCallStateChanged(int, String)} is invoked with state
- * {@link TelephonyManager#CALL_STATE_IDLE}.
- */
- @Test
- public void testVoiceCallSar_enabledTxPowerScenarioCallStateIdle_WhenWifiOn() throws Exception {
- when(mWifiNative.selectTxPowerScenario(anyInt())).thenReturn(true);
- testVoiceCallSar_enabledTxPowerScenario_WifiOn();
-
- mPhoneStateListener.onCallStateChanged(TelephonyManager.CALL_STATE_IDLE, "");
- mLooper.dispatchAll();
- verify(mWifiNative, atLeastOnce())
- .selectTxPowerScenario(eq(WifiNative.TX_POWER_SCENARIO_NORMAL));
- }
-
- /**
- * Test that we invoke the corresponding WifiNative method when
- * {@link PhoneStateListener#onCallStateChanged(int, String)} is invoked with state
- * {@link TelephonyManager#CALL_STATE_OFFHOOK}. This test checks if the
- * {@link WifiNative#selectTxPowerScenario(int)} failure is handled correctly.
- */
- @Test
- public void testVoiceCallSar_enabledTxPowerScenarioCallStateOffHook_WhenWifiOn_Fails()
- throws Exception {
- when(mWifiNative.selectTxPowerScenario(anyInt())).thenReturn(false);
- testVoiceCallSar_enabledTxPowerScenario_WifiOn();
-
- mPhoneStateListener.onCallStateChanged(TelephonyManager.CALL_STATE_OFFHOOK, "");
- mLooper.dispatchAll();
- verify(mWifiNative).selectTxPowerScenario(eq(WifiNative.TX_POWER_SCENARIO_VOICE_CALL));
- }
-
- /**
- * Test that we don't invoke the corresponding WifiNative method when
- * {@link PhoneStateListener#onCallStateChanged(int, String)} is invoked with state
- * {@link TelephonyManager#CALL_STATE_IDLE} or {@link TelephonyManager#CALL_STATE_OFFHOOK} when
- * wifi is off (state machine is not in SupplicantStarted state).
- */
- @Test
- public void testVoiceCallSar_enabledTxPowerScenarioCallState_WhenWifiOff() throws Exception {
- mResources.setBoolean(
- R.bool.config_wifi_framework_enable_voice_call_sar_tx_power_limit, true);
- initializeWsm();
-
- mPhoneStateListener.onCallStateChanged(TelephonyManager.CALL_STATE_OFFHOOK, "");
- mLooper.dispatchAll();
- verify(mWifiNative, never()).selectTxPowerScenario(anyInt());
-
- mPhoneStateListener.onCallStateChanged(TelephonyManager.CALL_STATE_IDLE, "");
- mLooper.dispatchAll();
- verify(mWifiNative, never()).selectTxPowerScenario(anyInt());
- }
-
- /**
* Verifies that a network disconnection event will result in WifiStateMachine invoking
* {@link WifiConfigManager#removeAllEphemeralOrPasspointConfiguredNetworks()} to remove
* any ephemeral or passpoint networks from it's internal database.