summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAhmed ElArabawy <arabawy@google.com>2018-06-18 12:26:40 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2018-06-18 12:26:40 +0000
commita5f380856579e7c125b48d2feaff7fb7fa7ac07f (patch)
tree57fd940f0aa2f87e25ac100de8f78bbee2b71c42
parent99efc1409f44ada7f6c7ca3e849b86ec47103159 (diff)
parent26744a15cfead946e7a4ca8b028fe4ea9bf96efe (diff)
Merge changes from topic "sar_support" into pi-dev
* changes: WiFi: Extend SAR to support sap/scan-only modes WiFi: SAR: Cleanup dead code WiFi: Extend SAR in WiFi with body sensors WiFi: SAR Support: Use SarInfo in WifiVendorHal WiFi: SAR Support: Add SarInfo
-rw-r--r--service/java/com/android/server/wifi/SarInfo.java194
-rw-r--r--service/java/com/android/server/wifi/SarManager.java353
-rw-r--r--service/java/com/android/server/wifi/ScanOnlyModeManager.java7
-rw-r--r--service/java/com/android/server/wifi/SoftApManager.java11
-rw-r--r--service/java/com/android/server/wifi/WifiInjector.java8
-rw-r--r--service/java/com/android/server/wifi/WifiNative.java17
-rw-r--r--service/java/com/android/server/wifi/WifiVendorHal.java227
-rw-r--r--tests/wifitests/src/com/android/server/wifi/SarInfoTest.java287
-rw-r--r--tests/wifitests/src/com/android/server/wifi/SarManagerTest.java867
-rw-r--r--tests/wifitests/src/com/android/server/wifi/ScanOnlyModeManagerTest.java5
-rw-r--r--tests/wifitests/src/com/android/server/wifi/SoftApManagerTest.java25
-rw-r--r--tests/wifitests/src/com/android/server/wifi/WifiNativeTest.java22
-rw-r--r--tests/wifitests/src/com/android/server/wifi/WifiVendorHalTest.java403
13 files changed, 2221 insertions, 205 deletions
diff --git a/service/java/com/android/server/wifi/SarInfo.java b/service/java/com/android/server/wifi/SarInfo.java
new file mode 100644
index 000000000..6eb777c65
--- /dev/null
+++ b/service/java/com/android/server/wifi/SarInfo.java
@@ -0,0 +1,194 @@
+/*
+ * 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 java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+/**
+ * This class represents the list of SAR inputs that will be used to select the proper
+ * power profile.
+ * This includes:
+ * - SAR body sensor status
+ * - Is there an ongoing voice call
+ * - Is SoftAP active
+ * It also contains info about state of the other Wifi modes
+ * - Client mode (Sta)
+ * - ScanOnly mode
+ * It also keeps history for the reporting of SAR states/scenario to avoid unnecessary reporting
+ * - keeps track of the last reported states
+ * - keeps track of the last reported SAR scenario
+ * - keeps track of if all wifi modes were disabled (no reporting should happen then)
+ */
+public class SarInfo {
+ /**
+ * This value is used as an initial value for the last reported scenario
+ * It is intended to be different than all valid SAR scenario values (including the
+ * reset value).
+ * Using this to initialize the lastReportedScenario results in that the first scenario
+ * (including reset) would be reported.
+ */
+ public static final int INITIAL_SAR_SCENARIO = -2;
+
+ /**
+ * This value is used for the reset scenario (no TX Power backoff)
+ * Valid scenario values only include scenarios with Tx Power backoff,
+ * so we need this one to represent the "No backoff" case.
+ */
+ public static final int RESET_SAR_SCENARIO = -1;
+
+ private static final String SAR_SENSOR_FREE_SPACE_STR = "SAR_SENSOR_FREE_SPACE";
+ private static final String SAR_SENSOR_NEAR_BODY_STR = "SAR_SENSOR_NEAR_BODY";
+ private static final String SAR_SENSOR_NEAR_HAND_STR = "SAR_SENSOR_NEAR_HAND";
+ private static final String SAR_SENSOR_NEAR_HEAD_STR = "SAR_SENSOR_NEAR_HEAD";
+
+ public static final int SAR_SENSOR_FREE_SPACE = 1;
+ public static final int SAR_SENSOR_NEAR_HAND = 2;
+ public static final int SAR_SENSOR_NEAR_HEAD = 3;
+ public static final int SAR_SENSOR_NEAR_BODY = 4;
+
+ /* For Logging */
+ private static final String TAG = "WifiSarInfo";
+
+ public boolean mSarSensorEnabled;
+
+ public int mSensorState = SAR_SENSOR_FREE_SPACE;
+ public boolean mIsWifiClientEnabled = false;
+ public boolean mIsWifiSapEnabled = false;
+ public boolean mIsWifiScanOnlyEnabled = false;
+ public boolean mIsVoiceCall = false;
+ public int mAttemptedSarScenario = RESET_SAR_SCENARIO;
+
+ private boolean mAllWifiDisabled = true;
+
+ /* Variables representing the last successfully reported values to hal */
+ private int mLastReportedSensorState = SAR_SENSOR_FREE_SPACE;
+ private boolean mLastReportedIsWifiSapEnabled = false;
+ private boolean mLastReportedIsVoiceCall = false;
+ private int mLastReportedScenario = INITIAL_SAR_SCENARIO;
+
+ SarInfo(boolean sarSensorEnabled) {
+ mSarSensorEnabled = sarSensorEnabled;
+ }
+
+ /**
+ * shouldReport()
+ * This method returns false in the following cases:
+ * 1. If all Wifi modes are disabled.
+ * 2. Values contributing to the SAR scenario selection have not changed
+ * since last successful reporting.
+ *
+ * Special cases to allow for devices that require setting the SAR scenario value
+ * when the chip comes up (initial startup, or during operation)
+ * 1. This method would report true even with unchanged values from last reporting,
+ * if any wifi mode is just enabled after all wifi modes were disabled.
+ * 2. This method would report true the first time it is called with any wifi mode enabled.
+ */
+ public boolean shouldReport() {
+ /* Check if all Wifi modes are disabled */
+ if (!mIsWifiClientEnabled && !mIsWifiSapEnabled && !mIsWifiScanOnlyEnabled) {
+ mAllWifiDisabled = true;
+ return false;
+ }
+
+ /* Check if Wifi was all disabled before this call */
+ if (mAllWifiDisabled) {
+ return true;
+ }
+
+ /* Check if some change happened since last successful reporting */
+ if ((mSensorState != mLastReportedSensorState)
+ || (mIsWifiSapEnabled != mLastReportedIsWifiSapEnabled)
+ || (mIsVoiceCall != mLastReportedIsVoiceCall)) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * reportingSuccessful()
+ * This method is called when reporting SAR scenario is fully successful
+ * This results in caching the last reported inputs for future comparison.
+ */
+ public void reportingSuccessful() {
+ mLastReportedSensorState = mSensorState;
+ mLastReportedIsWifiSapEnabled = mIsWifiSapEnabled;
+ mLastReportedIsVoiceCall = mIsVoiceCall;
+ mLastReportedScenario = mAttemptedSarScenario;
+
+ mAllWifiDisabled = false;
+ }
+
+ /**
+ * resetSarScenarioNeeded()
+ * Returns true if a call towards HAL to reset SAR scenario would be necessary.
+ * Returns false if the last call to HAL was already a reset, and hence
+ * another call to reset the SAR scenario would be redundant.
+ */
+ public boolean resetSarScenarioNeeded() {
+ return setSarScenarioNeeded(RESET_SAR_SCENARIO);
+ }
+
+ /**
+ * setSarScenarioNeeded()
+ * Returns true if a call towards HAL to set SAR scenario to that value would be
+ * necessary.
+ * Returns false if the last call to HAL was to set the scenario to that value, hence,
+ * another call to set the SAR scenario to the same value would be redundant.
+ */
+ public boolean setSarScenarioNeeded(int scenario) {
+ mAttemptedSarScenario = scenario;
+ return (mLastReportedScenario != scenario);
+ }
+
+ /**
+ * dump()
+ * Dumps the state of SarInfo
+ */
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ pw.println("*** WiFi SAR Info Dump ***");
+ pw.println("Current values:");
+ pw.println(" Sensor state is: " + sensorStateToString(mSensorState));
+ pw.println(" Voice Call state is: " + mIsVoiceCall);
+ pw.println(" Wifi Client state is: " + mIsWifiClientEnabled);
+ pw.println(" Wifi Soft AP state is: " + mIsWifiSapEnabled);
+ pw.println(" Wifi ScanOnly state is: " + mIsWifiScanOnlyEnabled);
+ pw.println("Last reported values:");
+ pw.println(" Sensor state is: " + sensorStateToString(mLastReportedSensorState));
+ pw.println(" Soft AP state is: " + mLastReportedIsWifiSapEnabled);
+ pw.println(" Voice Call state is: " + mLastReportedIsVoiceCall);
+ }
+
+ /**
+ * Convert SAR sensor state to string
+ */
+ public static String sensorStateToString(int sensorState) {
+ switch(sensorState) {
+ case SAR_SENSOR_FREE_SPACE:
+ return SAR_SENSOR_FREE_SPACE_STR;
+ case SAR_SENSOR_NEAR_BODY:
+ return SAR_SENSOR_NEAR_BODY_STR;
+ case SAR_SENSOR_NEAR_HAND:
+ return SAR_SENSOR_NEAR_HAND_STR;
+ case SAR_SENSOR_NEAR_HEAD:
+ return SAR_SENSOR_NEAR_HEAD_STR;
+ default:
+ return "Invalid SAR sensor state";
+ }
+ }
+}
diff --git a/service/java/com/android/server/wifi/SarManager.java b/service/java/com/android/server/wifi/SarManager.java
index da48a8537..d38eab981 100644
--- a/service/java/com/android/server/wifi/SarManager.java
+++ b/service/java/com/android/server/wifi/SarManager.java
@@ -20,14 +20,16 @@ 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.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
import android.net.wifi.WifiManager;
import android.os.Looper;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
+import android.text.TextUtils;
import android.util.Log;
import com.android.internal.R;
@@ -40,24 +42,28 @@ 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 SAP state through calls from SoftApManager
+ * - Tracking the Scan-Only state through ScanOnlyModeManager
* - Tracking the state of the Cellular calls or data.
- * - Based on above, selecting the SAR profile to use and programming it in wifi hal.
+ * - Tracking the sensor indicating proximity to user head/hand/body.
+ * - It constructs the sar info and send it towards the HAL
*/
public class SarManager {
-
/* For Logging */
private static final String TAG = "WifiSarManager";
private boolean mVerboseLoggingEnabled = true;
+ private SarInfo mSarInfo;
+
/* Configuration for SAR */
private boolean mEnableSarTxPowerLimit;
+ private boolean mEnableSarBodyProximity;
+ /* Sensor event definitions */
+ private int mSarSensorEventFreeSpace;
+ private int mSarSensorEventNearBody;
+ private int mSarSensorEventNearHand;
+ private int mSarSensorEventNearHead;
- /* 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.
*/
@@ -65,6 +71,8 @@ public class SarManager {
private final TelephonyManager mTelephonyManager;
private final WifiPhoneStateListener mPhoneStateListener;
private final WifiNative mWifiNative;
+ private final SarSensorEventListener mSensorListener;
+ private final SensorManager mSensorManager;
private final Looper mLooper;
/**
@@ -73,30 +81,157 @@ public class SarManager {
SarManager(Context context,
TelephonyManager telephonyManager,
Looper looper,
- WifiNative wifiNative) {
+ WifiNative wifiNative,
+ SensorManager sensorManager) {
mContext = context;
mTelephonyManager = telephonyManager;
mWifiNative = wifiNative;
mLooper = looper;
+ mSensorManager = sensorManager;
mPhoneStateListener = new WifiPhoneStateListener(looper);
+ mSensorListener = new SarSensorEventListener();
+
+ readSarConfigs();
+ if (mEnableSarTxPowerLimit) {
+ mSarInfo = new SarInfo(mEnableSarBodyProximity);
+ registerListeners();
+ }
+ }
+
+ private void readSarConfigs() {
+ mEnableSarTxPowerLimit = mContext.getResources().getBoolean(
+ R.bool.config_wifi_framework_enable_sar_tx_power_limit);
+ /* In case SAR is disabled,
+ then SAR sensor is automatically disabled as well (irrespective of the config) */
+ if (!mEnableSarTxPowerLimit) {
+ mEnableSarBodyProximity = false;
+ return;
+ }
+
+ mEnableSarBodyProximity = mContext.getResources().getBoolean(
+ R.bool.config_wifi_framework_enable_body_proximity_sar_tx_power_limit);
+
+ /* Read the sar sensor event Ids */
+ if (mEnableSarBodyProximity) {
+ mSarSensorEventFreeSpace = mContext.getResources().getInteger(
+ R.integer.config_wifi_framework_sar_free_space_event_id);
+ mSarSensorEventNearBody = mContext.getResources().getInteger(
+ R.integer.config_wifi_framework_sar_near_body_event_id);
+ mSarSensorEventNearHand = mContext.getResources().getInteger(
+ R.integer.config_wifi_framework_sar_near_hand_event_id);
+ mSarSensorEventNearHead = mContext.getResources().getInteger(
+ R.integer.config_wifi_framework_sar_near_head_event_id);
+ }
+ }
- registerListeners();
+ private void registerListeners() {
+ /* Listen for Phone State changes */
+ registerPhoneStateListener();
+
+ /* Only listen for SAR sensor if supported */
+ if (mEnableSarBodyProximity) {
+ /* Register the SAR sensor listener.
+ * If this fails, we will assume worst case (near head) */
+ if (!registerSensorListener()) {
+ Log.e(TAG, "Failed to register sensor listener, setting Sensor to NearHead");
+ /*TODO Need to add a metric to determine how often this happens */
+ mSarInfo.mSensorState = SarInfo.SAR_SENSOR_NEAR_HEAD;
+ }
+ }
}
/**
- * Starts the SAR Manager by initializing the different listeners
+ * Register the phone state listener.
*/
- 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);
+ private void registerPhoneStateListener() {
+ Log.i(TAG, "Registering for telephony call state changes");
+ mTelephonyManager.listen(
+ mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
+ }
- /* Only Start listening for events if SAR is enabled */
- if (mEnableSarTxPowerLimit) {
- Log.d(TAG, "Registering Listeners for the SAR Manager");
+ /**
+ * Register the body/hand/head proximity sensor.
+ */
+ private boolean registerSensorListener() {
+ Log.i(TAG, "Registering for Sensor notification Listener");
+ return mSensorListener.register();
+ }
+
+ /**
+ * Update Wifi Client State
+ */
+ public void setClientWifiState(int state) {
+ boolean newIsEnabled;
+ /* No action is taken if SAR is not enabled */
+ if (!mEnableSarTxPowerLimit) {
+ return;
+ }
+
+ if (state == WifiManager.WIFI_STATE_DISABLED) {
+ newIsEnabled = false;
+ } else if (state == WifiManager.WIFI_STATE_ENABLED) {
+ newIsEnabled = true;
+ } else {
+ /* No change so exiting with no action */
+ return;
+ }
+
+ /* Report change to HAL if needed */
+ if (mSarInfo.mIsWifiClientEnabled != newIsEnabled) {
+ mSarInfo.mIsWifiClientEnabled = newIsEnabled;
+ updateSarScenario();
+ }
+ }
+
+ /**
+ * Update Wifi SoftAP State
+ */
+ public void setSapWifiState(int state) {
+ boolean newIsEnabled;
+ /* No action is taken if SAR is not enabled */
+ if (!mEnableSarTxPowerLimit) {
+ return;
+ }
+
+ if (state == WifiManager.WIFI_AP_STATE_DISABLED) {
+ newIsEnabled = false;
+ } else if (state == WifiManager.WIFI_AP_STATE_ENABLED) {
+ newIsEnabled = true;
+ } else {
+ /* No change so exiting with no action */
+ return;
+ }
+
+ /* Report change to HAL if needed */
+ if (mSarInfo.mIsWifiSapEnabled != newIsEnabled) {
+ mSarInfo.mIsWifiSapEnabled = newIsEnabled;
+ updateSarScenario();
+ }
+ }
- /* Listen for Phone State changes */
- registerPhoneListener();
+ /**
+ * Update Wifi ScanOnly State
+ */
+ public void setScanOnlyWifiState(int state) {
+ boolean newIsEnabled;
+ /* No action is taken if SAR is not enabled */
+ if (!mEnableSarTxPowerLimit) {
+ return;
+ }
+
+ if (state == WifiManager.WIFI_STATE_DISABLED) {
+ newIsEnabled = false;
+ } else if (state == WifiManager.WIFI_STATE_ENABLED) {
+ newIsEnabled = true;
+ } else {
+ /* No change so exiting with no action */
+ return;
+ }
+
+ /* Report change to HAL if needed */
+ if (mSarInfo.mIsWifiScanOnlyEnabled != newIsEnabled) {
+ mSarInfo.mIsWifiScanOnlyEnabled = newIsEnabled;
+ updateSarScenario();
}
}
@@ -104,42 +239,52 @@ public class SarManager {
* Report Cell state event
*/
private void onCellStateChangeEvent(int state) {
- boolean currentCellOn = mCellOn;
-
+ boolean newIsVoiceCall;
switch (state) {
case CALL_STATE_OFFHOOK:
case CALL_STATE_RINGING:
- mCellOn = true;
+ newIsVoiceCall = true;
break;
case CALL_STATE_IDLE:
- mCellOn = false;
+ newIsVoiceCall = false;
break;
default:
Log.e(TAG, "Invalid Cell State: " + state);
+ return;
}
- if (mCellOn != currentCellOn) {
+ /* Report change to HAL if needed */
+ if (mSarInfo.mIsVoiceCall != newIsVoiceCall) {
+ mSarInfo.mIsVoiceCall = newIsVoiceCall;
updateSarScenario();
}
}
/**
- * Update Wifi Client State
+ * Report an event from the SAR sensor
*/
- 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;
+ private void onSarSensorEvent(int sarSensorEvent) {
+ int newSensorState;
+ if (sarSensorEvent == mSarSensorEventFreeSpace) {
+ newSensorState = SarInfo.SAR_SENSOR_FREE_SPACE;
+ } else if (sarSensorEvent == mSarSensorEventNearBody) {
+ newSensorState = SarInfo.SAR_SENSOR_NEAR_BODY;
+ } else if (sarSensorEvent == mSarSensorEventNearHand) {
+ newSensorState = SarInfo.SAR_SENSOR_NEAR_HAND;
+ } else if (sarSensorEvent == mSarSensorEventNearHead) {
+ newSensorState = SarInfo.SAR_SENSOR_NEAR_HEAD;
+ } else {
+ Log.e(TAG, "Invalid SAR sensor event id: " + sarSensorEvent);
+ return;
+ }
- /* Since no wifi interface was up,
- time for SAR scenario to take effect */
- sendTxPowerScenario(mCurrentSarScenario);
+ /* Report change to HAL if needed */
+ if (mSarInfo.mSensorState != newSensorState) {
+ Log.d(TAG, "Setting Sensor state to " + SarInfo.sensorStateToString(newSensorState));
+ mSarInfo.mSensorState = newSensorState;
+ updateSarScenario();
}
}
@@ -147,7 +292,6 @@ public class SarManager {
* Enable/disable verbose logging.
*/
public void enableVerboseLogging(int verbose) {
- Log.d(TAG, "Inside enableVerboseLogging: " + verbose);
if (verbose > 0) {
mVerboseLoggingEnabled = true;
} else {
@@ -155,18 +299,16 @@ public class SarManager {
}
}
- 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.
+ * dump()
+ * Dumps SarManager state (as well as its SarInfo member variable state)
*/
- private void registerPhoneListener() {
- Log.i(TAG, "Registering for telephony call state changes");
- mTelephonyManager.listen(
- mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ pw.println("*** WiFi SAR Manager Dump ***");
+ pw.println("isSarEnabled: " + mEnableSarTxPowerLimit);
+ pw.println("isSarSensorEnabled: " + mEnableSarBodyProximity);
+ pw.println("");
+ mSarInfo.dump(fd, pw, args);
}
/**
@@ -177,69 +319,96 @@ public class SarManager {
super(looper);
}
+ /**
+ * onCallStateChanged()
+ * This callback is called when a SAR sensor event is received
+ * Note that this runs in the WifiStateMachineHandlerThread
+ * since the corresponding Looper was passed to the WifiPhoneStateListener constructor.
+ */
@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;
-
+ 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;
+ private class SarSensorEventListener implements SensorEventListener {
- if (mCellOn) {
- newSarScenario = WifiNative.TX_POWER_SCENARIO_VOICE_CALL;
- } else {
- newSarScenario = WifiNative.TX_POWER_SCENARIO_NORMAL;
- }
+ private Sensor mSensor;
- if (newSarScenario != mCurrentSarScenario) {
+ /**
+ * Register the SAR listener to get SAR sensor events
+ */
+ private boolean register() {
+ /* Get the sensor type from configuration */
+ String sensorType = mContext.getResources().getString(
+ R.string.config_wifi_sar_sensor_type);
+ if (TextUtils.isEmpty(sensorType)) {
+ Log.e(TAG, "Empty SAR sensor type");
+ return false;
+ }
+
+ /* Get the sensor object */
+ Sensor sensor = null;
+ List<Sensor> sensorList = mSensorManager.getSensorList(Sensor.TYPE_ALL);
+ for (Sensor s : sensorList) {
+ if (sensorType.equals(s.getStringType())) {
+ sensor = s;
+ break;
+ }
+ }
+ if (sensor == null) {
+ Log.e(TAG, "Failed to Find the SAR Sensor");
+ return false;
+ }
- // Only update HAL with new scenario if WiFi interface is enabled
- if (mWifiStaEnabled) {
- Log.d(TAG, "Sending SAR Scenario #" + scenarioToString(newSarScenario));
- sendTxPowerScenario(newSarScenario);
+ /* Now register the listener */
+ if (!mSensorManager.registerListener(this, sensor,
+ SensorManager.SENSOR_DELAY_NORMAL)) {
+ Log.e(TAG, "Failed to register SAR Sensor Listener");
+ return false;
}
- mCurrentSarScenario = newSarScenario;
+ return true;
}
- }
- /**
- * 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");
+ /**
+ * onSensorChanged()
+ * This callback is called when a SAR sensor event is received
+ * Note that this runs in the WifiStateMachineHandlerThread
+ * since, the corresponding Looper was passed to the SensorManager instance.
+ */
+ @Override
+ public void onSensorChanged(SensorEvent event) {
+ onSarSensorEvent((int) event.values[0]);
+ }
+
+ @Override
+ public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
}
/**
- * Convert SAR Scenario to string
+ * updateSarScenario()
+ * Update HAL with the new SAR scenario if needed.
*/
- 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;
+ private void updateSarScenario() {
+ if (!mSarInfo.shouldReport()) {
+ return;
+ }
+
+ /* Report info to HAL*/
+ if (mWifiNative.selectTxPowerScenario(mSarInfo)) {
+ mSarInfo.reportingSuccessful();
+ } else {
+ Log.e(TAG, "Failed in WifiNative.selectTxPowerScenario()");
}
- return str;
+ return;
}
}
diff --git a/service/java/com/android/server/wifi/ScanOnlyModeManager.java b/service/java/com/android/server/wifi/ScanOnlyModeManager.java
index 346d2ca67..991657929 100644
--- a/service/java/com/android/server/wifi/ScanOnlyModeManager.java
+++ b/service/java/com/android/server/wifi/ScanOnlyModeManager.java
@@ -48,6 +48,7 @@ public class ScanOnlyModeManager implements ActiveModeManager {
private final Listener mListener;
private final ScanRequestProxy mScanRequestProxy;
private final WakeupController mWakeupController;
+ private final SarManager mSarManager;
private String mClientInterfaceName;
private boolean mIfaceIsUp = false;
@@ -58,13 +59,15 @@ public class ScanOnlyModeManager implements ActiveModeManager {
@NonNull WifiNative wifiNative, @NonNull Listener listener,
@NonNull WifiMetrics wifiMetrics,
@NonNull ScanRequestProxy scanRequestProxy,
- @NonNull WakeupController wakeupController) {
+ @NonNull WakeupController wakeupController,
+ @NonNull SarManager sarManager) {
mContext = context;
mWifiNative = wifiNative;
mListener = listener;
mWifiMetrics = wifiMetrics;
mScanRequestProxy = scanRequestProxy;
mWakeupController = wakeupController;
+ mSarManager = sarManager;
mStateMachine = new ScanOnlyModeStateMachine(looper);
}
@@ -242,6 +245,7 @@ public class ScanOnlyModeManager implements ActiveModeManager {
mIfaceIsUp = false;
onUpChanged(mWifiNative.isInterfaceUp(mClientInterfaceName));
+ mSarManager.setScanOnlyWifiState(WifiManager.WIFI_STATE_ENABLED);
}
@Override
@@ -281,6 +285,7 @@ public class ScanOnlyModeManager implements ActiveModeManager {
mClientInterfaceName = null;
}
updateWifiState(WifiManager.WIFI_STATE_DISABLED);
+ mSarManager.setScanOnlyWifiState(WifiManager.WIFI_STATE_DISABLED);
// once we leave started, nothing else to do... stop the state machine
mStateMachine.quitNow();
diff --git a/service/java/com/android/server/wifi/SoftApManager.java b/service/java/com/android/server/wifi/SoftApManager.java
index 6c52918a5..1afe9ed9d 100644
--- a/service/java/com/android/server/wifi/SoftApManager.java
+++ b/service/java/com/android/server/wifi/SoftApManager.java
@@ -93,6 +93,8 @@ public class SoftApManager implements ActiveModeManager {
private int mNumAssociatedStations = 0;
private boolean mTimeoutEnabled = false;
+ private final SarManager mSarManager;
+
/**
* Listener for soft AP events.
*/
@@ -118,7 +120,8 @@ public class SoftApManager implements ActiveModeManager {
@NonNull WifiManager.SoftApCallback callback,
@NonNull WifiApConfigStore wifiApConfigStore,
@NonNull SoftApModeConfiguration apConfig,
- @NonNull WifiMetrics wifiMetrics) {
+ @NonNull WifiMetrics wifiMetrics,
+ @NonNull SarManager sarManager) {
mContext = context;
mFrameworkFacade = framework;
mWifiNative = wifiNative;
@@ -133,6 +136,7 @@ public class SoftApManager implements ActiveModeManager {
mApConfig = config;
}
mWifiMetrics = wifiMetrics;
+ mSarManager = sarManager;
mStateMachine = new SoftApStateMachine(looper);
}
@@ -491,6 +495,9 @@ public class SoftApManager implements ActiveModeManager {
if (mSettingObserver != null) {
mSettingObserver.register();
}
+
+ mSarManager.setSapWifiState(WifiManager.WIFI_AP_STATE_ENABLED);
+
Log.d(TAG, "Resetting num stations on start");
mNumAssociatedStations = 0;
scheduleTimeoutMessage();
@@ -512,6 +519,8 @@ public class SoftApManager implements ActiveModeManager {
mWifiMetrics.addSoftApUpChangedEvent(false, mMode);
updateApState(WifiManager.WIFI_AP_STATE_DISABLED,
WifiManager.WIFI_AP_STATE_DISABLING, 0);
+
+ mSarManager.setSapWifiState(WifiManager.WIFI_AP_STATE_DISABLED);
mApInterfaceName = null;
mIfaceIsUp = false;
mStateMachine.quitNow();
diff --git a/service/java/com/android/server/wifi/WifiInjector.java b/service/java/com/android/server/wifi/WifiInjector.java
index 0e30af841..199548090 100644
--- a/service/java/com/android/server/wifi/WifiInjector.java
+++ b/service/java/com/android/server/wifi/WifiInjector.java
@@ -20,6 +20,7 @@ import android.annotation.NonNull;
import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.content.Context;
+import android.hardware.SystemSensorManager;
import android.net.NetworkKey;
import android.net.NetworkScoreManager;
import android.net.wifi.IWifiScanner;
@@ -253,7 +254,7 @@ public class WifiInjector {
this, mWifiConfigManager,
mWifiPermissionsUtil, mWifiMetrics, mClock);
mSarManager = new SarManager(mContext, makeTelephonyManager(), wifiStateMachineLooper,
- mWifiNative);
+ mWifiNative, new SystemSensorManager(mContext, wifiStateMachineLooper));
if (mUseRealLogger) {
mWifiDiagnostics = new WifiDiagnostics(
mContext, this, mWifiNative, mBuildProperties,
@@ -464,7 +465,7 @@ public class WifiInjector {
@NonNull SoftApModeConfiguration config) {
return new SoftApManager(mContext, mWifiStateMachineHandlerThread.getLooper(),
mFrameworkFacade, mWifiNative, mCountryCode.getCountryCode(), callback,
- mWifiApConfigStore, config, mWifiMetrics);
+ mWifiApConfigStore, config, mWifiMetrics, mSarManager);
}
/**
@@ -476,7 +477,8 @@ public class WifiInjector {
public ScanOnlyModeManager makeScanOnlyModeManager(
@NonNull ScanOnlyModeManager.Listener listener) {
return new ScanOnlyModeManager(mContext, mWifiStateMachineHandlerThread.getLooper(),
- mWifiNative, listener, mWifiMetrics, mScanRequestProxy, mWakeupController);
+ mWifiNative, listener, mWifiMetrics, mScanRequestProxy, mWakeupController,
+ mSarManager);
}
/**
diff --git a/service/java/com/android/server/wifi/WifiNative.java b/service/java/com/android/server/wifi/WifiNative.java
index 0f785873b..bc599c141 100644
--- a/service/java/com/android/server/wifi/WifiNative.java
+++ b/service/java/com/android/server/wifi/WifiNative.java
@@ -2820,21 +2820,14 @@ public class WifiNative {
}
/**
- * Tx power level scenarios that can be selected.
- */
- public static final int TX_POWER_SCENARIO_NORMAL = 0;
- public static final int TX_POWER_SCENARIO_VOICE_CALL = 1;
-
- /**
- * Select one of the pre-configured TX power level scenarios or reset it back to normal.
- * Primarily used for meeting SAR requirements during voice calls.
+ * Select one of the pre-configured transmit power level scenarios or reset it back to normal.
+ * Primarily used for meeting SAR requirements.
*
- * @param scenario Should be one {@link #TX_POWER_SCENARIO_NORMAL} or
- * {@link #TX_POWER_SCENARIO_VOICE_CALL}.
+ * @param sarInfo The collection of inputs used to select the SAR scenario.
* @return true for success; false for failure or if the HAL version does not support this API.
*/
- public boolean selectTxPowerScenario(int scenario) {
- return mWifiVendorHal.selectTxPowerScenario(scenario);
+ public boolean selectTxPowerScenario(SarInfo sarInfo) {
+ return mWifiVendorHal.selectTxPowerScenario(sarInfo);
}
/********************************************************
diff --git a/service/java/com/android/server/wifi/WifiVendorHal.java b/service/java/com/android/server/wifi/WifiVendorHal.java
index 0d73459b5..361387e2f 100644
--- a/service/java/com/android/server/wifi/WifiVendorHal.java
+++ b/service/java/com/android/server/wifi/WifiVendorHal.java
@@ -2653,13 +2653,95 @@ public class WifiVendorHal {
return android.hardware.wifi.V1_2.IWifiStaIface.castFrom(iface);
}
+ /**
+ * sarPowerBackoffRequired_1_1()
+ * This method checks if we need to backoff wifi Tx power due to SAR requirements.
+ * It handles the case when the device is running the V1_1 version of WifiChip HAL
+ * In that HAL version, it is required to perform wifi Tx power backoff only if
+ * a voice call is ongoing.
+ */
+ private boolean sarPowerBackoffRequired_1_1(SarInfo sarInfo) {
+ /* As long as no voice call is active, no backoff is needed */
+ return sarInfo.mIsVoiceCall;
+ }
+
+ /**
+ * frameworkToHalTxPowerScenario_1_1()
+ * This method maps the information inside the SarInfo instance into a SAR scenario
+ * when device is running the V1_1 version of WifiChip HAL.
+ * In this HAL version, only one scenario is defined which is for VOICE_CALL
+ * otherwise, an exception is thrown.
+ */
+ private int frameworkToHalTxPowerScenario_1_1(SarInfo sarInfo) {
+ if (sarInfo.mIsVoiceCall) {
+ return android.hardware.wifi.V1_1.IWifiChip.TxPowerScenario.VOICE_CALL;
+ } else {
+ throw new IllegalArgumentException("bad scenario: voice call not active");
+ }
+ }
- private int frameworkToHalTxPowerScenario(int scenario) {
- switch (scenario) {
- case WifiNative.TX_POWER_SCENARIO_VOICE_CALL:
+ /**
+ * sarPowerBackoffRequired_1_2()
+ * This method checks if we need to backoff wifi Tx power due to SAR requirements.
+ * It handles the case when the device is running the V1_2 version of WifiChip HAL
+ * In that HAL version, behavior depends on if SAR sensor input is considered in this device.
+ * If it is, then whenever the device is near the user body/hand/head, back-off is required.
+ * Otherwise, we should revert to the V1_1 HAL behavior which is only to perform backoff when
+ * a voice call is ongoing.
+ */
+ private boolean sarPowerBackoffRequired_1_2(SarInfo sarInfo) {
+ if (sarInfo.mSarSensorEnabled) {
+ return (sarInfo.mSensorState != SarInfo.SAR_SENSOR_FREE_SPACE);
+ } else {
+ return sarInfo.mIsVoiceCall;
+ }
+ }
+
+ /**
+ * frameworkToHalTxPowerScenario_1_2()
+ * This method maps the information inside the SarInfo instance into a SAR scenario
+ * when device is running the V1_2 version of WifiChip HAL.
+ * In this HAL version, behavior depends on if SAR sensor input is considered in this device.
+ * If it is, then based on regulatory compliance requirements,
+ * - There is no need to treat NEAR_HAND different from NEAR_BODY, both can be considered
+ * near the user body.
+ * - Running in softAP mode can be treated the same way as running a voice call from tx power
+ * backoff perspective.
+ * If SAR sensor input is not considered in this device, then we should revert to the V1_1 HAL
+ * behavior, and the only valid scenario would be when a voice call is ongoing.
+ */
+ private int frameworkToHalTxPowerScenario_1_2(SarInfo sarInfo) {
+ if (sarInfo.mSarSensorEnabled) {
+ switch(sarInfo.mSensorState) {
+ case SarInfo.SAR_SENSOR_NEAR_BODY:
+ case SarInfo.SAR_SENSOR_NEAR_HAND:
+ if (sarInfo.mIsVoiceCall || sarInfo.mIsWifiSapEnabled) {
+ return android.hardware.wifi.V1_2.IWifiChip
+ .TxPowerScenario.ON_BODY_CELL_ON;
+ } else {
+ return android.hardware.wifi.V1_2.IWifiChip
+ .TxPowerScenario.ON_BODY_CELL_OFF;
+ }
+
+ case SarInfo.SAR_SENSOR_NEAR_HEAD:
+ if (sarInfo.mIsVoiceCall || sarInfo.mIsWifiSapEnabled) {
+ return android.hardware.wifi.V1_2.IWifiChip
+ .TxPowerScenario.ON_HEAD_CELL_ON;
+ } else {
+ return android.hardware.wifi.V1_2.IWifiChip
+ .TxPowerScenario.ON_HEAD_CELL_OFF;
+ }
+
+ default:
+ throw new IllegalArgumentException("bad scenario: Invalid sensor state");
+ }
+ } else {
+ /* SAR Sensors not enabled, act like V1_1 */
+ if (sarInfo.mIsVoiceCall) {
return android.hardware.wifi.V1_1.IWifiChip.TxPowerScenario.VOICE_CALL;
- default:
- throw new IllegalArgumentException("bad scenario: " + scenario);
+ } else {
+ throw new IllegalArgumentException("bad scenario: voice call not active");
+ }
}
}
@@ -2667,35 +2749,130 @@ public class WifiVendorHal {
* Select one of the pre-configured TX power level scenarios or reset it back to normal.
* Primarily used for meeting SAR requirements during voice calls.
*
- * @param scenario Should be one {@link WifiNative#TX_POWER_SCENARIO_NORMAL} or
- * {@link WifiNative#TX_POWER_SCENARIO_VOICE_CALL}.
+ * Note: If it was found out that the scenario to be reported is the same as last reported one,
+ * then exit with success.
+ * This is to handle the case when some HAL versions deal with different inputs equally,
+ * in that case, we should not call the hal unless there is a change in scenario.
+ * Note: It is assumed that this method is only called if SAR is enabled. The logic of whether
+ * to call it or not resides in SarManager class.
+ * Note: This method is called whether SAR sensor is supported or not. The passed SarInfo object
+ * contains a flag to indicate the SAR sensor support.
+ *
+ * @param sarInfo The collection of inputs to select the SAR scenario.
* @return true for success; false for failure or if the HAL version does not support this API.
*/
- public boolean selectTxPowerScenario(int scenario) {
+ public boolean selectTxPowerScenario(SarInfo sarInfo) {
synchronized (sLock) {
- try {
- android.hardware.wifi.V1_1.IWifiChip iWifiChipV11 = getWifiChipForV1_1Mockable();
- if (iWifiChipV11 == null) return boolResult(false);
- WifiStatus status;
- if (scenario != WifiNative.TX_POWER_SCENARIO_NORMAL) {
- int halScenario;
- try {
- halScenario = frameworkToHalTxPowerScenario(scenario);
- } catch (IllegalArgumentException e) {
- mLog.err("Illegal argument for select tx power scenario")
- .c(e.toString()).flush();
+ // First attempt to get a V_1_2 instance of the Wifi HAL.
+ android.hardware.wifi.V1_2.IWifiChip iWifiChipV12 = getWifiChipForV1_2Mockable();
+ if (iWifiChipV12 != null) {
+ return selectTxPowerScenario_1_2(iWifiChipV12, sarInfo);
+ }
+
+ // Now attempt to get a V_1_1 instance of the Wifi HAL.
+ android.hardware.wifi.V1_1.IWifiChip iWifiChipV11 = getWifiChipForV1_1Mockable();
+ if (iWifiChipV11 != null) {
+ return selectTxPowerScenario_1_1(iWifiChipV11, sarInfo);
+ }
+
+ // HAL version does not support SAR
+ return false;
+ }
+ }
+
+ private boolean selectTxPowerScenario_1_1(
+ android.hardware.wifi.V1_1.IWifiChip iWifiChip, SarInfo sarInfo) {
+ WifiStatus status;
+ try {
+ if (sarPowerBackoffRequired_1_1(sarInfo)) {
+ // Power backoff is needed, so calculate the required scenario,
+ // and attempt to set it.
+ int halScenario = frameworkToHalTxPowerScenario_1_1(sarInfo);
+ if (sarInfo.setSarScenarioNeeded(halScenario)) {
+ status = iWifiChip.selectTxPowerScenario(halScenario);
+ if (ok(status)) {
+ mLog.e("Setting SAR scenario to " + halScenario);
+ return true;
+ } else {
+ mLog.e("Failed to set SAR scenario to " + halScenario);
return false;
}
- status = iWifiChipV11.selectTxPowerScenario(halScenario);
+ }
+
+ // Reaching here means setting SAR scenario would be redundant,
+ // do nothing and return with success.
+ return true;
+ }
+
+ // We don't need to perform power backoff, so attempt to reset SAR scenario.
+ if (sarInfo.resetSarScenarioNeeded()) {
+ status = iWifiChip.resetTxPowerScenario();
+ if (ok(status)) {
+ mLog.d("Resetting SAR scenario");
+ return true;
} else {
- status = iWifiChipV11.resetTxPowerScenario();
+ mLog.e("Failed to reset SAR scenario");
+ return false;
}
- if (!ok(status)) return false;
- } catch (RemoteException e) {
- handleRemoteException(e);
- return false;
}
+
+ // Resetting SAR scenario would be redundant,
+ // do nothing and return with success.
return true;
+ } catch (RemoteException e) {
+ handleRemoteException(e);
+ return false;
+ } catch (IllegalArgumentException e) {
+ mLog.err("Illegal argument for selectTxPowerScenario_1_1()").c(e.toString()).flush();
+ return false;
+ }
+ }
+
+ private boolean selectTxPowerScenario_1_2(
+ android.hardware.wifi.V1_2.IWifiChip iWifiChip, SarInfo sarInfo) {
+ WifiStatus status;
+ try {
+ if (sarPowerBackoffRequired_1_2(sarInfo)) {
+ // Power backoff is needed, so calculate the required scenario,
+ // and attempt to set it.
+ int halScenario = frameworkToHalTxPowerScenario_1_2(sarInfo);
+ if (sarInfo.setSarScenarioNeeded(halScenario)) {
+ status = iWifiChip.selectTxPowerScenario_1_2(halScenario);
+ if (ok(status)) {
+ mLog.e("Setting SAR scenario to " + halScenario);
+ return true;
+ } else {
+ mLog.e("Failed to set SAR scenario to " + halScenario);
+ return false;
+ }
+ }
+
+ // Reaching here means setting SAR scenario would be redundant,
+ // do nothing and return with success.
+ return true;
+ }
+
+ // We don't need to perform power backoff, so attempt to reset SAR scenario.
+ if (sarInfo.resetSarScenarioNeeded()) {
+ status = iWifiChip.resetTxPowerScenario();
+ if (ok(status)) {
+ mLog.d("Resetting SAR scenario");
+ return true;
+ } else {
+ mLog.e("Failed to reset SAR scenario");
+ return false;
+ }
+ }
+
+ // Resetting SAR scenario would be redundant,
+ // do nothing and return with success.
+ return true;
+ } catch (RemoteException e) {
+ handleRemoteException(e);
+ return false;
+ } catch (IllegalArgumentException e) {
+ mLog.err("Illegal argument for selectTxPowerScenario_1_2()").c(e.toString()).flush();
+ return false;
}
}
diff --git a/tests/wifitests/src/com/android/server/wifi/SarInfoTest.java b/tests/wifitests/src/com/android/server/wifi/SarInfoTest.java
new file mode 100644
index 000000000..1f0e44c8a
--- /dev/null
+++ b/tests/wifitests/src/com/android/server/wifi/SarInfoTest.java
@@ -0,0 +1,287 @@
+/*
+ * 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.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.support.test.filters.SmallTest;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * unit tests for {@link com.android.server.wifi.SarInfo}.
+ */
+@SmallTest
+public class SarInfoTest {
+ private static final String TAG = "WifiSarInfoTest";
+
+ private SarInfo mSarInfo;
+
+ private static final int SAR_SCENARIO_1 = 1;
+ private static final int SAR_SCENARIO_2 = 2;
+
+ @Before
+ public void setUp() throws Exception {
+ mSarInfo = new SarInfo(true);
+ }
+
+ @After
+ public void cleanUp() throws Exception {
+ }
+
+ /**
+ * Test that at start, resetSarScenarioNeeded returns true,
+ * to allow for initial setting of normal scenario.
+ */
+ @Test
+ public void testSarInfo_resetSarScenarioNeed_atStart() throws Exception {
+ assertTrue(mSarInfo.resetSarScenarioNeeded());
+ }
+
+ /**
+ * Test that at start, setSarScenarioNeeded returns true.
+ */
+ @Test
+ public void testSarInfo_setSarScenarioNeeded_atStart() throws Exception {
+ assertTrue(mSarInfo.setSarScenarioNeeded(SAR_SCENARIO_1));
+ }
+
+ /**
+ * Test performing two successive reset of SAR scenario.
+ * The first should succeed, while the second should fail, since it is redundant.
+ */
+ @Test
+ public void testSarInfo_repeat_reset_scenario() throws Exception {
+ /* Initial reset is allowed */
+ assertTrue(mSarInfo.resetSarScenarioNeeded());
+ mSarInfo.reportingSuccessful();
+
+ /* Now resetting again should not be allowed */
+ assertFalse(mSarInfo.resetSarScenarioNeeded());
+ }
+
+ /**
+ * Test performing set SAR scenario after reset.
+ * The two attempts should succeed.
+ */
+ @Test
+ public void testSarInfo_set_after_reset_scenario() throws Exception {
+ assertTrue(mSarInfo.resetSarScenarioNeeded());
+ mSarInfo.reportingSuccessful();
+
+ /* Setting scenario should be allowed, since last call was for a reset */
+ assertTrue(mSarInfo.setSarScenarioNeeded(SAR_SCENARIO_1));
+ }
+
+ /**
+ * Test performing setting SAR scenario twice with same value.
+ * The second attempt should fail.
+ */
+ @Test
+ public void testSarInfo_set_twice_same_value_scenario() throws Exception {
+ assertTrue(mSarInfo.setSarScenarioNeeded(SAR_SCENARIO_1));
+ mSarInfo.reportingSuccessful();
+
+ /* Second attempt should fail */
+ assertFalse(mSarInfo.setSarScenarioNeeded(SAR_SCENARIO_1));
+ }
+
+ /**
+ * Test performing setting SAR scenario twice with different values.
+ * Both attempts should succeed.
+ */
+ @Test
+ public void testSarInfo_set_twice_different_values_scenario() throws Exception {
+ assertTrue(mSarInfo.setSarScenarioNeeded(SAR_SCENARIO_1));
+ mSarInfo.reportingSuccessful();
+
+ /* Setting scenario should be allowed */
+ assertTrue(mSarInfo.setSarScenarioNeeded(SAR_SCENARIO_2));
+ }
+
+ /**
+ * Test performing reset of SAR scenario after setting it.
+ * Both attempts should succeed.
+ */
+ @Test
+ public void testSarInfo_reset_after_set_scenario() throws Exception {
+ assertTrue(mSarInfo.setSarScenarioNeeded(SAR_SCENARIO_1));
+ mSarInfo.reportingSuccessful();
+
+ /* Resetting scenario should be allowed */
+ assertTrue(mSarInfo.resetSarScenarioNeeded());
+ }
+
+ /**
+ * Test that at start, shouldReport returns false (wifi modes still disabled).
+ */
+ @Test
+ public void testSarInfo_shouldReport_all_wifi_disabled() throws Exception {
+ assertFalse(mSarInfo.shouldReport());
+ }
+
+ /**
+ * Test that once Wifi (any mode) is enabled, shouldReport returns true.
+ */
+ @Test
+ public void testSarInfo_shouldReport_wifi_enabled() throws Exception {
+ mSarInfo.mIsWifiClientEnabled = true;
+ assertTrue(mSarInfo.shouldReport());
+ }
+
+ /**
+ * Test that setting sensor (with wifi disabled), shouldReport returns false.
+ */
+ @Test
+ public void testSarInfo_check_sensor_wifi_disabled() throws Exception {
+ mSarInfo.mSensorState = SarInfo.SAR_SENSOR_NEAR_HEAD;
+ assertFalse(mSarInfo.shouldReport());
+ }
+
+ /**
+ * Test that setting sensor (with some wifi mode enabled), shouldReport returns true.
+ */
+ @Test
+ public void testSarInfo_check_sensor_wifi_enabled() throws Exception {
+ mSarInfo.mIsWifiSapEnabled = true;
+ assertTrue(mSarInfo.shouldReport());
+ mSarInfo.reportingSuccessful();
+
+ mSarInfo.mSensorState = SarInfo.SAR_SENSOR_NEAR_HEAD;
+ assertTrue(mSarInfo.shouldReport());
+ }
+
+ /**
+ * Test that setting sensor (with some wifi mode enabled), shouldReport returns true
+ * only the first time, following attempts should return false (since sensor state
+ * did not change)
+ */
+ @Test
+ public void testSarInfo_check_sensor_multiple_wifi_enabled() throws Exception {
+ mSarInfo.mIsWifiScanOnlyEnabled = true;
+ mSarInfo.mSensorState = SarInfo.SAR_SENSOR_NEAR_HEAD;
+ assertTrue(mSarInfo.shouldReport());
+ mSarInfo.reportingSuccessful();
+
+ assertFalse(mSarInfo.shouldReport());
+ }
+
+ /**
+ * Test that setting sensor with different values (with wifi enabled),
+ * shouldReport returns true every time.
+ */
+ @Test
+ public void testSarInfo_check_sensor_multiple_values_wifi_enabled() throws Exception {
+ mSarInfo.mIsWifiClientEnabled = true;
+ mSarInfo.mSensorState = SarInfo.SAR_SENSOR_NEAR_HEAD;
+ assertTrue(mSarInfo.shouldReport());
+ mSarInfo.reportingSuccessful();
+
+ mSarInfo.mSensorState = SarInfo.SAR_SENSOR_NEAR_BODY;
+ assertTrue(mSarInfo.shouldReport());
+ mSarInfo.reportingSuccessful();
+
+ mSarInfo.mSensorState = SarInfo.SAR_SENSOR_NEAR_HEAD;
+ assertTrue(mSarInfo.shouldReport());
+ }
+
+ /**
+ * Test setting sensor while wifi is disabled, then enable wifi.
+ */
+ @Test
+ public void testSarInfo_change_sensors_while_wifi_disabled() throws Exception {
+ mSarInfo.mSensorState = SarInfo.SAR_SENSOR_NEAR_HEAD;
+ assertFalse(mSarInfo.shouldReport());
+
+ mSarInfo.mIsWifiClientEnabled = true;
+ assertTrue(mSarInfo.shouldReport());
+ mSarInfo.reportingSuccessful();
+ }
+
+ /**
+ * Test having a voice call, shouldReport should return true
+ * Note: will need to report once before starting the call to remove
+ * the effect of sensor state change.
+ */
+ @Test
+ public void testSarInfo_voice_call_wifi_enabled() throws Exception {
+ mSarInfo.mIsWifiClientEnabled = true;
+ assertTrue(mSarInfo.shouldReport());
+ mSarInfo.reportingSuccessful();
+
+ mSarInfo.mIsVoiceCall = true;
+ assertTrue(mSarInfo.shouldReport());
+ }
+
+ /**
+ * Test starting SAP, shouldReport should return true
+ * Note: will need to report once before starting SAP to remove
+ * the effect of sensor state change.
+ */
+ @Test
+ public void testSarInfo_sap_wifi_enabled() throws Exception {
+ mSarInfo.mIsWifiClientEnabled = true;
+ assertTrue(mSarInfo.shouldReport());
+ mSarInfo.reportingSuccessful();
+
+ mSarInfo.mIsWifiSapEnabled = true;
+ assertTrue(mSarInfo.shouldReport());
+ }
+
+ /**
+ * Test that setting sensor (with wifi enabled), reporting not successful
+ * Then, we should expect that shouldReport returns true evne if we have
+ * no further changes until reporting is successful.
+ */
+ @Test
+ public void testSarInfo_check_sensor_reporting_no_success_reporting() throws Exception {
+ mSarInfo.mIsWifiClientEnabled = true;
+ mSarInfo.mSensorState = SarInfo.SAR_SENSOR_NEAR_HEAD;
+ assertTrue(mSarInfo.shouldReport());
+
+ /* No call to reportingSuccessful() will be done */
+ assertTrue(mSarInfo.shouldReport());
+
+ /* Now call reportingSuccessful() */
+ mSarInfo.reportingSuccessful();
+ assertFalse(mSarInfo.shouldReport());
+ }
+
+ /**
+ * Test that setting sensor (with wifi enabled), reporting successful
+ * Then, changing the sensor state with no successful reporting.
+ * Followed by reverting to the previous state.
+ */
+ @Test
+ public void testSarInfo_check_sensor_reporting_no_success_reporting_revert() throws Exception {
+ mSarInfo.mIsWifiClientEnabled = true;
+ mSarInfo.mSensorState = SarInfo.SAR_SENSOR_NEAR_HEAD;
+ assertTrue(mSarInfo.shouldReport());
+ mSarInfo.reportingSuccessful();
+
+ /* Changing the sensor state and fail to report */
+ mSarInfo.mSensorState = SarInfo.SAR_SENSOR_NEAR_BODY;
+ assertTrue(mSarInfo.shouldReport());
+
+ /* Changing the sensor back to the same value as last reported */
+ mSarInfo.mSensorState = SarInfo.SAR_SENSOR_NEAR_HEAD;
+ assertFalse(mSarInfo.shouldReport());
+ }
+}
diff --git a/tests/wifitests/src/com/android/server/wifi/SarManagerTest.java b/tests/wifitests/src/com/android/server/wifi/SarManagerTest.java
index 163280a39..369dcba33 100644
--- a/tests/wifitests/src/com/android/server/wifi/SarManagerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/SarManagerTest.java
@@ -16,39 +16,44 @@
package com.android.server.wifi;
+import static android.telephony.TelephonyManager.CALL_STATE_IDLE;
+import static android.telephony.TelephonyManager.CALL_STATE_OFFHOOK;
+
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
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.Sensor;
import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
+import android.hardware.SystemSensorManager;
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;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.List;
+
/**
* unit tests for {@link com.android.server.wifi.SarManager}.
*/
@@ -56,6 +61,12 @@ import org.mockito.MockitoAnnotations;
public class SarManagerTest {
private static final String TAG = "WifiSarManagerTest";
private static final String OP_PACKAGE_NAME = "com.xxx";
+ private static final String SAR_SENSOR_NAME = "com.google.sensor.sar";
+
+ private static final int SAR_SENSOR_EVENT_FREE_SPACE = 1;
+ private static final int SAR_SENSOR_EVENT_HAND = 2;
+ private static final int SAR_SENSOR_EVENT_HEAD = 3;
+ private static final int SAR_SENSOR_EVENT_BODY = 4;
private void enableDebugLogs() {
mSarMgr.enableVerboseLogging(1);
@@ -70,23 +81,26 @@ public class SarManagerTest {
private TestLooper mLooper;
private MockResources mResources;
private PhoneStateListener mPhoneStateListener;
+ private List<Sensor> mSensorList;
+ private Sensor mSensor;
+ private SarInfo mSarInfo;
- @Mock private Context mContext;
+ @Mock private Context mContext;
+ @Mock SensorEventListener mSensorEventListener;
+ @Mock SystemSensorManager mSensorManager;
@Mock TelephonyManager mTelephonyManager;
@Mock private ApplicationInfo mMockApplInfo;
@Mock WifiNative mWifiNative;
@Before
public void setUp() throws Exception {
- Log.e(TAG, "Setting Up ...");
-
- // Ensure Looper exists
+ /* Ensure Looper exists */
mLooper = new TestLooper();
MockitoAnnotations.initMocks(this);
/* Default behavior is to return with success */
- when(mWifiNative.selectTxPowerScenario(anyInt())).thenReturn(true);
+ when(mWifiNative.selectTxPowerScenario(any(SarInfo.class))).thenReturn(true);
mResources = getMockResources();
@@ -105,15 +119,78 @@ public class SarManagerTest {
}
/**
+ * Helper function to capture SarInfo object
+ */
+ private void captureSarInfo(WifiNative wifiNative) {
+ /* Capture the SensorEventListener */
+ ArgumentCaptor<SarInfo> sarInfoCaptor = ArgumentCaptor.forClass(SarInfo.class);
+ verify(wifiNative).selectTxPowerScenario(sarInfoCaptor.capture());
+ mSarInfo = sarInfoCaptor.getValue();
+ assertNotNull(mSarInfo);
+ }
+
+ /**
+ * Helper function to create and prepare sensor info
+ */
+ private void prepareSensorInfo(boolean registerReturn) {
+ /* Create a sensor object (note, this can not be mocked since it is a final class) */
+ Constructor<Sensor> constructor =
+ (Constructor<Sensor>) Sensor.class.getDeclaredConstructors()[0];
+ constructor.setAccessible(true);
+
+ try {
+ mSensor = constructor.newInstance();
+ } catch (Exception e) {
+ fail("Failed to create a sensor object");
+ }
+
+ /* Now set the mStringType field with the proper field */
+ Field declaredField = null;
+ try {
+ declaredField = Sensor.class.getDeclaredField("mStringType");
+ declaredField.setAccessible(true);
+ declaredField.set(mSensor, SAR_SENSOR_NAME);
+ } catch (Exception e) {
+ fail("Could not set sensor string type");
+ }
+
+ /* Prepare the sensor list */
+ mSensorList = new ArrayList<Sensor>();
+ mSensorList.add(mSensor);
+ when(mSensorManager.getSensorList(Sensor.TYPE_ALL)).thenReturn(mSensorList);
+ when(mSensorManager.registerListener(any(SensorEventListener.class), any(Sensor.class),
+ anyInt())).thenReturn(registerReturn);
+ }
+
+ /**
* Helper function to set configuration for SAR and create the SAR Manager
*
*/
- private void createSarManager(boolean isSarEnabled) {
+ private void createSarManager(boolean isSarEnabled, boolean isSarSensorEnabled) {
+ mResources.setBoolean(
+ R.bool.config_wifi_framework_enable_sar_tx_power_limit, isSarEnabled);
mResources.setBoolean(
- R.bool.config_wifi_framework_enable_voice_call_sar_tx_power_limit, isSarEnabled);
+ R.bool.config_wifi_framework_enable_body_proximity_sar_tx_power_limit,
+ isSarSensorEnabled);
+ mResources.setString(R.string.config_wifi_sar_sensor_type, SAR_SENSOR_NAME);
+
+ /* Set the event id configs */
+ mResources.setInteger(R.integer.config_wifi_framework_sar_free_space_event_id,
+ SAR_SENSOR_EVENT_FREE_SPACE);
+ mResources.setInteger(R.integer.config_wifi_framework_sar_near_hand_event_id,
+ SAR_SENSOR_EVENT_HAND);
+ mResources.setInteger(R.integer.config_wifi_framework_sar_near_head_event_id,
+ SAR_SENSOR_EVENT_HEAD);
+ mResources.setInteger(R.integer.config_wifi_framework_sar_near_body_event_id,
+ SAR_SENSOR_EVENT_BODY);
+
+ /* Prepare sensor info only if SarSensorEnabled */
+ if (isSarSensorEnabled) {
+ prepareSensorInfo(true);
+ }
mSarMgr = new SarManager(mContext, mTelephonyManager, mLooper.getLooper(),
- mWifiNative);
+ mWifiNative, mSensorManager);
if (isSarEnabled) {
/* Capture the PhoneStateListener */
@@ -122,6 +199,17 @@ public class SarManagerTest {
verify(mTelephonyManager).listen(phoneStateListenerCaptor.capture(),
eq(PhoneStateListener.LISTEN_CALL_STATE));
mPhoneStateListener = phoneStateListenerCaptor.getValue();
+ assertNotNull(mPhoneStateListener);
+ }
+
+ if (isSarSensorEnabled) {
+ /* Capture the SensorEventListener */
+ ArgumentCaptor<SensorEventListener> sensorEventListenerCaptor =
+ ArgumentCaptor.forClass(SensorEventListener.class);
+ verify(mSensorManager).registerListener(sensorEventListenerCaptor.capture(),
+ any(Sensor.class), anyInt());
+ mSensorEventListener = sensorEventListenerCaptor.getValue();
+ assertNotNull(mSensorEventListener);
}
/* Enable logs from SarManager */
@@ -129,12 +217,70 @@ public class SarManagerTest {
}
/**
+ * Helper function to create SarManager with some error cases for sensor handling
+ */
+ private void createSarManagerSensorNegTest(String configSensorName, boolean addToConfigs,
+ boolean sensorRegisterReturn) {
+ mResources.setBoolean(
+ R.bool.config_wifi_framework_enable_sar_tx_power_limit, true);
+ mResources.setBoolean(
+ R.bool.config_wifi_framework_enable_body_proximity_sar_tx_power_limit, true);
+ if (addToConfigs) {
+ mResources.setString(R.string.config_wifi_sar_sensor_type, configSensorName);
+ }
+
+ /* Set the event id configs */
+ mResources.setInteger(R.integer.config_wifi_framework_sar_free_space_event_id,
+ SAR_SENSOR_EVENT_FREE_SPACE);
+ mResources.setInteger(R.integer.config_wifi_framework_sar_near_hand_event_id,
+ SAR_SENSOR_EVENT_HAND);
+ mResources.setInteger(R.integer.config_wifi_framework_sar_near_head_event_id,
+ SAR_SENSOR_EVENT_HEAD);
+ mResources.setInteger(R.integer.config_wifi_framework_sar_near_body_event_id,
+ SAR_SENSOR_EVENT_BODY);
+
+ prepareSensorInfo(sensorRegisterReturn);
+
+ mSarMgr = new SarManager(mContext, mTelephonyManager, mLooper.getLooper(),
+ mWifiNative, mSensorManager);
+
+ /* Capture the PhoneStateListener */
+ ArgumentCaptor<PhoneStateListener> phoneStateListenerCaptor =
+ ArgumentCaptor.forClass(PhoneStateListener.class);
+ verify(mTelephonyManager).listen(phoneStateListenerCaptor.capture(),
+ eq(PhoneStateListener.LISTEN_CALL_STATE));
+ mPhoneStateListener = phoneStateListenerCaptor.getValue();
+ assertNotNull(mPhoneStateListener);
+
+ /* Enable logs from SarManager */
+ enableDebugLogs();
+ }
+
+ /**
+ * Helper function to create and pass a sensor event
+ */
+ private void sendSensorEvent(int eventId) {
+ SensorEvent event;
+ Constructor<SensorEvent> constructor =
+ (Constructor<SensorEvent>) SensorEvent.class.getDeclaredConstructors()[0];
+ constructor.setAccessible(true);
+
+ try {
+ event = constructor.newInstance(1);
+ event.values[0] = (float) eventId;
+ mSensorEventListener.onSensorChanged(event);
+ } catch (Exception e) {
+ fail("Failed to create a Sensor Event");
+ }
+ }
+
+ /**
* 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);
+ createSarManager(true, false);
verify(mTelephonyManager).listen(any(), eq(PhoneStateListener.LISTEN_CALL_STATE));
}
@@ -144,7 +290,7 @@ public class SarManagerTest {
*/
@Test
public void testSarMgr_disabledTxPowerScenario_registerPhone() throws Exception {
- createSarManager(false);
+ createSarManager(false, false);
verify(mTelephonyManager, never()).listen(any(), anyInt());
}
@@ -153,27 +299,24 @@ public class SarManagerTest {
* 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);
+ createSarManager(true, false);
InOrder inOrder = inOrder(mWifiNative);
/* Enable WiFi State */
mSarMgr.setClientWifiState(WifiManager.WIFI_STATE_ENABLED);
+ captureSarInfo(mWifiNative);
- inOrder.verify(mWifiNative).selectTxPowerScenario(
- eq(WifiNative.TX_POWER_SCENARIO_NORMAL));
+ inOrder.verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertFalse(mSarInfo.mIsVoiceCall);
/* Set phone state to OFFHOOK */
mPhoneStateListener.onCallStateChanged(CALL_STATE_OFFHOOK, "");
-
- inOrder.verify(mWifiNative).selectTxPowerScenario(
- eq(WifiNative.TX_POWER_SCENARIO_VOICE_CALL));
+ inOrder.verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertTrue(mSarInfo.mIsVoiceCall);
}
/**
@@ -181,66 +324,70 @@ public class SarManagerTest {
* 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);
+ createSarManager(true, false);
+
+ InOrder inOrder = inOrder(mWifiNative);
/* Set phone state to OFFHOOK */
mPhoneStateListener.onCallStateChanged(CALL_STATE_OFFHOOK, "");
/* Enable WiFi State */
mSarMgr.setClientWifiState(WifiManager.WIFI_STATE_ENABLED);
+ captureSarInfo(mWifiNative);
- verify(mWifiNative).selectTxPowerScenario(
- eq(WifiNative.TX_POWER_SCENARIO_VOICE_CALL));
+ inOrder.verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertTrue(mSarInfo.mIsVoiceCall);
}
/**
* 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
+ * {@link TelephonyManager#CALL_STATE_IDLE} when WiFi STA is enabled
*/
@Test
public void testSarMgr_enabledTxPowerScenario_wifiOn_offHook_onHook() throws Exception {
- createSarManager(true);
- assertNotNull(mPhoneStateListener);
+ createSarManager(true, false);
InOrder inOrder = inOrder(mWifiNative);
/* Enable WiFi State */
mSarMgr.setClientWifiState(WifiManager.WIFI_STATE_ENABLED);
+ captureSarInfo(mWifiNative);
/* Now device should set tx power scenario to NORMAL */
- inOrder.verify(mWifiNative).selectTxPowerScenario(
- eq(WifiNative.TX_POWER_SCENARIO_NORMAL));
+ inOrder.verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertFalse(mSarInfo.mIsVoiceCall);
/* 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));
+ inOrder.verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertTrue(mSarInfo.mIsVoiceCall);
/* 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));
+ inOrder.verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertFalse(mSarInfo.mIsVoiceCall);
+
+ /* Disable WiFi State */
+ mSarMgr.setClientWifiState(WifiManager.WIFI_STATE_DISABLED);
+ inOrder.verify(mWifiNative, never()).selectTxPowerScenario(any(SarInfo.class));
}
/**
* 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
+ * {@link TelephonyManager#CALL_STATE_IDLE} when WiFi STA is disabled
*/
@Test
public void testSarMgr_enabledTxPowerScenario_wifiOff_offHook_onHook() throws Exception {
- createSarManager(true);
- assertNotNull(mPhoneStateListener);
+ createSarManager(true, false);
InOrder inOrder = inOrder(mWifiNative);
@@ -251,6 +398,634 @@ public class SarManagerTest {
mPhoneStateListener.onCallStateChanged(CALL_STATE_IDLE, "");
/* Device should not set tx power scenario at all */
- inOrder.verify(mWifiNative, never()).selectTxPowerScenario(anyInt());
+ inOrder.verify(mWifiNative, never()).selectTxPowerScenario(any(SarInfo.class));
+ }
+
+ /**
+ * Test that for devices supporting SAR the following scenario:
+ * - Wifi enabled
+ * - A call starts
+ * - Wifi disabled
+ * - Call ends
+ * - Wifi back on
+ */
+ @Test
+ public void testSarMgr_enabledSar_wifiOn_offHook_wifiOff_onHook() throws Exception {
+ createSarManager(true, false);
+
+ InOrder inOrder = inOrder(mWifiNative);
+
+ /* Enable WiFi State */
+ mSarMgr.setClientWifiState(WifiManager.WIFI_STATE_ENABLED);
+ captureSarInfo(mWifiNative);
+
+ /* Now device should set tx power scenario to NORMAL */
+ inOrder.verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertFalse(mSarInfo.mIsVoiceCall);
+
+ /* Set phone state to OFFHOOK */
+ mPhoneStateListener.onCallStateChanged(CALL_STATE_OFFHOOK, "");
+ inOrder.verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertTrue(mSarInfo.mIsVoiceCall);
+
+ /* Disable WiFi State */
+ mSarMgr.setClientWifiState(WifiManager.WIFI_STATE_DISABLED);
+ inOrder.verify(mWifiNative, never()).selectTxPowerScenario(any(SarInfo.class));
+
+ /* Set state back to ONHOOK */
+ mPhoneStateListener.onCallStateChanged(CALL_STATE_IDLE, "");
+ inOrder.verify(mWifiNative, never()).selectTxPowerScenario(any(SarInfo.class));
+
+ /* Enable WiFi State again */
+ mSarMgr.setClientWifiState(WifiManager.WIFI_STATE_ENABLED);
+ inOrder.verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertFalse(mSarInfo.mIsVoiceCall);
+ }
+
+ /**
+ * Test that for devices supporting SAR, Wifi disabled, a call starts, a call ends, Wifi
+ * enabled.
+ */
+ @Test
+ public void testSarMgr_enabledSar_wifiOff_offHook_onHook_wifiOn() throws Exception {
+ createSarManager(true, false);
+
+ InOrder inOrder = inOrder(mWifiNative);
+
+ /* Set phone state to OFFHOOK */
+ mPhoneStateListener.onCallStateChanged(CALL_STATE_OFFHOOK, "");
+ inOrder.verify(mWifiNative, never()).selectTxPowerScenario(any(SarInfo.class));
+
+ /* Set state back to ONHOOK */
+ mPhoneStateListener.onCallStateChanged(CALL_STATE_IDLE, "");
+ inOrder.verify(mWifiNative, never()).selectTxPowerScenario(any(SarInfo.class));
+
+ /* Enable WiFi State */
+ mSarMgr.setClientWifiState(WifiManager.WIFI_STATE_ENABLED);
+ captureSarInfo(mWifiNative);
+
+ inOrder.verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertFalse(mSarInfo.mIsVoiceCall);
+ }
+
+ /**
+ * Test that for devices supporting SAR, Wifi disabled, a call starts, wifi on, wifi off,
+ * call ends.
+ */
+ @Test
+ public void testSarMgr_enabledSar_offHook_wifiOnOff_onHook() throws Exception {
+ createSarManager(true, false);
+
+ InOrder inOrder = inOrder(mWifiNative);
+
+ /* Set phone state to OFFHOOK */
+ mPhoneStateListener.onCallStateChanged(CALL_STATE_OFFHOOK, "");
+ inOrder.verify(mWifiNative, never()).selectTxPowerScenario(any(SarInfo.class));
+
+ /* Enable WiFi State */
+ mSarMgr.setClientWifiState(WifiManager.WIFI_STATE_ENABLED);
+ captureSarInfo(mWifiNative);
+ assertNotNull(mSarInfo);
+
+ inOrder.verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertTrue(mSarInfo.mIsVoiceCall);
+
+ /* Disable WiFi State */
+ mSarMgr.setClientWifiState(WifiManager.WIFI_STATE_DISABLED);
+ inOrder.verify(mWifiNative, never()).selectTxPowerScenario(any(SarInfo.class));
+
+ /* Set state back to ONHOOK */
+ mPhoneStateListener.onCallStateChanged(CALL_STATE_IDLE, "");
+ inOrder.verify(mWifiNative, never()).selectTxPowerScenario(any(SarInfo.class));
+ }
+
+ /**
+ * Test the error case for for devices supporting SAR, Wifi enabled, a call starts,
+ * call ends. With all of these cases, the call to set Tx power scenario fails.
+ */
+ @Test
+ public void testSarMgr_enabledSar_error_wifiOn_offOnHook() throws Exception {
+ createSarManager(true, false);
+
+ when(mWifiNative.selectTxPowerScenario(any(SarInfo.class))).thenReturn(false);
+ InOrder inOrder = inOrder(mWifiNative);
+
+ /* Enable WiFi State */
+ mSarMgr.setClientWifiState(WifiManager.WIFI_STATE_ENABLED);
+ captureSarInfo(mWifiNative);
+ assertNotNull(mSarInfo);
+
+ inOrder.verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertFalse(mSarInfo.mIsVoiceCall);
+
+ /* Set phone state to OFFHOOK */
+ mPhoneStateListener.onCallStateChanged(CALL_STATE_OFFHOOK, "");
+ inOrder.verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertTrue(mSarInfo.mIsVoiceCall);
+
+ /* Set state back to ONHOOK */
+ mPhoneStateListener.onCallStateChanged(CALL_STATE_IDLE, "");
+ inOrder.verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertFalse(mSarInfo.mIsVoiceCall);
+ }
+
+ /**
+ * Test that for a device that has SAR enabled, with sar sensor enabled,
+ * wifi enabled, Then Tx power scenarios follow events from sensor for body/hand/head/none
+ */
+ @Test
+ public void testSarMgr_sarSensorOn_WifiOn_sensorEventsTriggered() throws Exception {
+ createSarManager(true, true);
+
+ InOrder inOrder = inOrder(mWifiNative);
+
+ /* Enable Wifi Client */
+ mSarMgr.setClientWifiState(WifiManager.WIFI_STATE_ENABLED);
+ captureSarInfo(mWifiNative);
+
+ inOrder.verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertEquals(SarInfo.SAR_SENSOR_FREE_SPACE, mSarInfo.mSensorState);
+
+ /* Sensor event */
+ sendSensorEvent(SAR_SENSOR_EVENT_BODY);
+ inOrder.verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertEquals(SarInfo.SAR_SENSOR_NEAR_BODY, mSarInfo.mSensorState);
+ assertFalse(mSarInfo.mIsVoiceCall);
+
+ /* Sensor event */
+ sendSensorEvent(SAR_SENSOR_EVENT_HEAD);
+ inOrder.verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertEquals(SarInfo.SAR_SENSOR_NEAR_HEAD, mSarInfo.mSensorState);
+ assertFalse(mSarInfo.mIsVoiceCall);
+
+ /* Sensor event */
+ sendSensorEvent(SAR_SENSOR_EVENT_HAND);
+ inOrder.verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertEquals(SarInfo.SAR_SENSOR_NEAR_HAND, mSarInfo.mSensorState);
+ assertFalse(mSarInfo.mIsVoiceCall);
+
+ /* Sensor event */
+ sendSensorEvent(SAR_SENSOR_EVENT_FREE_SPACE);
+ inOrder.verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertEquals(SarInfo.SAR_SENSOR_FREE_SPACE, mSarInfo.mSensorState);
+ assertFalse(mSarInfo.mIsVoiceCall);
+ }
+
+ /**
+ * Test that for a device that has SAR enabled, with sar sensor enabled,
+ * wifi enabled, cellOn,
+ * then Tx power scenarios follow events from sensor for body/hand/head/none
+ */
+ @Test
+ public void testSarMgr_sarSensorOn_wifiOn_cellOn_sensorEventsTriggered() throws Exception {
+ createSarManager(true, true);
+
+ InOrder inOrder = inOrder(mWifiNative);
+
+ /* Enable Wifi Client */
+ mSarMgr.setClientWifiState(WifiManager.WIFI_STATE_ENABLED);
+ captureSarInfo(mWifiNative);
+
+ /* Should get the an event with no calls */
+ inOrder.verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertEquals(SarInfo.SAR_SENSOR_FREE_SPACE, mSarInfo.mSensorState);
+ assertFalse(mSarInfo.mIsVoiceCall);
+
+ /* Start a Cell call */
+ mPhoneStateListener.onCallStateChanged(CALL_STATE_OFFHOOK, "");
+ inOrder.verify(mWifiNative).selectTxPowerScenario(any(SarInfo.class));
+ assertEquals(SarInfo.SAR_SENSOR_FREE_SPACE, mSarInfo.mSensorState);
+ assertTrue(mSarInfo.mIsVoiceCall);
+
+ /* Sensor event */
+ sendSensorEvent(SAR_SENSOR_EVENT_BODY);
+ inOrder.verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertEquals(SarInfo.SAR_SENSOR_NEAR_BODY, mSarInfo.mSensorState);
+ assertTrue(mSarInfo.mIsVoiceCall);
+
+ /* Sensor event */
+ sendSensorEvent(SAR_SENSOR_EVENT_HEAD);
+ inOrder.verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertEquals(SarInfo.SAR_SENSOR_NEAR_HEAD, mSarInfo.mSensorState);
+ assertTrue(mSarInfo.mIsVoiceCall);
+
+ /* Sensor event */
+ sendSensorEvent(SAR_SENSOR_EVENT_HAND);
+ inOrder.verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertEquals(SarInfo.SAR_SENSOR_NEAR_HAND, mSarInfo.mSensorState);
+ assertTrue(mSarInfo.mIsVoiceCall);
+
+ /* Sensor event */
+ sendSensorEvent(SAR_SENSOR_EVENT_FREE_SPACE);
+ inOrder.verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertEquals(SarInfo.SAR_SENSOR_FREE_SPACE, mSarInfo.mSensorState);
+ assertTrue(mSarInfo.mIsVoiceCall);
+ }
+
+ /**
+ * Test that for a device that has SAR enabled, with sar sensor enabled,
+ * wifi enabled, device next to user head, a call has started and stopped,
+ * then Tx power scenarios should adjust properly
+ */
+ @Test
+ public void testSarMgr_sarSensorOn_wifiOn_onHead_cellOnOff() throws Exception {
+ createSarManager(true, true);
+
+ InOrder inOrder = inOrder(mWifiNative);
+
+ /* Enable Wifi Client */
+ mSarMgr.setClientWifiState(WifiManager.WIFI_STATE_ENABLED);
+ captureSarInfo(mWifiNative);
+
+ inOrder.verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertEquals(SarInfo.SAR_SENSOR_FREE_SPACE, mSarInfo.mSensorState);
+ assertFalse(mSarInfo.mIsVoiceCall);
+
+ /* Sensor event */
+ sendSensorEvent(SAR_SENSOR_EVENT_HEAD);
+ inOrder.verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertEquals(SarInfo.SAR_SENSOR_NEAR_HEAD, mSarInfo.mSensorState);
+ assertFalse(mSarInfo.mIsVoiceCall);
+
+ /* Start a Cell call */
+ mPhoneStateListener.onCallStateChanged(CALL_STATE_OFFHOOK, "");
+ inOrder.verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertEquals(SarInfo.SAR_SENSOR_NEAR_HEAD, mSarInfo.mSensorState);
+ assertTrue(mSarInfo.mIsVoiceCall);
+
+ /* End a Cell call */
+ mPhoneStateListener.onCallStateChanged(CALL_STATE_IDLE, "");
+ inOrder.verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertEquals(SarInfo.SAR_SENSOR_NEAR_HEAD, mSarInfo.mSensorState);
+ assertFalse(mSarInfo.mIsVoiceCall);
+ }
+
+ /**
+ * Test that for a device that has SAR enabled, with sar sensor enabled,
+ * all wifi states disabled, when a sensor event is triggered no setting of Tx power scenario
+ * is initiated.
+ * Then when Wifi is enabled, Tx power setting will be initiated to reflect the sensor event.
+ */
+ @Test
+ public void testSarMgr_sarSensorOn_WifiOffOn_sensorEventTriggered() throws Exception {
+ createSarManager(true, true);
+
+ InOrder inOrder = inOrder(mWifiNative);
+
+ /* Sensor event */
+ sendSensorEvent(SAR_SENSOR_EVENT_BODY);
+ inOrder.verify(mWifiNative, never()).selectTxPowerScenario(any(SarInfo.class));
+
+ /* Enable Wifi Client */
+ mSarMgr.setClientWifiState(WifiManager.WIFI_STATE_ENABLED);
+ captureSarInfo(mWifiNative);
+
+ inOrder.verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertEquals(SarInfo.SAR_SENSOR_NEAR_BODY, mSarInfo.mSensorState);
+ assertFalse(mSarInfo.mIsVoiceCall);
+ }
+
+ /**
+ * Test the error case when SAR sensor name does not exist in configuration.
+ * In this case, SarManager should assume operation near head all the time.
+ */
+ @Test
+ public void testSarMgr_error_sar_name_does_not_exist() throws Exception {
+ createSarManagerSensorNegTest(SAR_SENSOR_NAME, false, true);
+
+ InOrder inOrder = inOrder(mWifiNative);
+
+ verify(mSensorManager, never()).registerListener(any(SensorEventListener.class),
+ any(Sensor.class), anyInt());
+
+ /* Enable WiFi Client */
+ mSarMgr.setClientWifiState(WifiManager.WIFI_STATE_ENABLED);
+ captureSarInfo(mWifiNative);
+
+ inOrder.verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertEquals(SarInfo.SAR_SENSOR_NEAR_HEAD, mSarInfo.mSensorState);
+ assertFalse(mSarInfo.mIsVoiceCall);
+
+ /* Start a Cell Call */
+ mPhoneStateListener.onCallStateChanged(CALL_STATE_OFFHOOK, "");
+ inOrder.verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertEquals(SarInfo.SAR_SENSOR_NEAR_HEAD, mSarInfo.mSensorState);
+ assertTrue(mSarInfo.mIsVoiceCall);
+
+ /* End the call */
+ mPhoneStateListener.onCallStateChanged(CALL_STATE_IDLE, "");
+ inOrder.verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertEquals(SarInfo.SAR_SENSOR_NEAR_HEAD, mSarInfo.mSensorState);
+ assertFalse(mSarInfo.mIsVoiceCall);
+ }
+
+ /**
+ * Test the error case when SarManager uses the wrong sensor name in configuration.
+ * In this case, SarManager should assume operation near head all the time.
+ */
+ @Test
+ public void testSarMgr_error_sar_name_mismatch() throws Exception {
+ createSarManagerSensorNegTest("wrong.sensor.name", true, true);
+
+ InOrder inOrder = inOrder(mWifiNative);
+
+ verify(mSensorManager, never()).registerListener(any(SensorEventListener.class),
+ any(Sensor.class), anyInt());
+
+ /* Enable WiFi Client */
+ mSarMgr.setClientWifiState(WifiManager.WIFI_STATE_ENABLED);
+ captureSarInfo(mWifiNative);
+
+ inOrder.verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertEquals(SarInfo.SAR_SENSOR_NEAR_HEAD, mSarInfo.mSensorState);
+ assertFalse(mSarInfo.mIsVoiceCall);
+
+ /* Start a Cell Call */
+ mPhoneStateListener.onCallStateChanged(CALL_STATE_OFFHOOK, "");
+ inOrder.verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertEquals(SarInfo.SAR_SENSOR_NEAR_HEAD, mSarInfo.mSensorState);
+ assertTrue(mSarInfo.mIsVoiceCall);
+
+ /* End the call */
+ mPhoneStateListener.onCallStateChanged(CALL_STATE_IDLE, "");
+ inOrder.verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertEquals(SarInfo.SAR_SENSOR_NEAR_HEAD, mSarInfo.mSensorState);
+ assertFalse(mSarInfo.mIsVoiceCall);
+ }
+
+ /**
+ * Test the error case when SarManager fails to register as a SensorEventListener.
+ * In this case, SarManager should assume operation near head all the time.
+ */
+ @Test
+ public void testSarMgr_error_sar_register_failure() throws Exception {
+ createSarManagerSensorNegTest(SAR_SENSOR_NAME, true, false);
+
+ verify(mSensorManager).registerListener(any(SensorEventListener.class),
+ any(Sensor.class), anyInt());
+
+ InOrder inOrder = inOrder(mWifiNative);
+
+ /* Enable WiFi Client */
+ mSarMgr.setClientWifiState(WifiManager.WIFI_STATE_ENABLED);
+ captureSarInfo(mWifiNative);
+
+ inOrder.verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertEquals(SarInfo.SAR_SENSOR_NEAR_HEAD, mSarInfo.mSensorState);
+ assertFalse(mSarInfo.mIsVoiceCall);
+
+ /* Start a Cell Call */
+ mPhoneStateListener.onCallStateChanged(CALL_STATE_OFFHOOK, "");
+ inOrder.verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertEquals(SarInfo.SAR_SENSOR_NEAR_HEAD, mSarInfo.mSensorState);
+ assertTrue(mSarInfo.mIsVoiceCall);
+
+ /* End the call */
+ mPhoneStateListener.onCallStateChanged(CALL_STATE_IDLE, "");
+ inOrder.verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertEquals(SarInfo.SAR_SENSOR_NEAR_HEAD, mSarInfo.mSensorState);
+ assertFalse(mSarInfo.mIsVoiceCall);
+ }
+
+ /**
+ * Test that Start of SoftAP for a device that does not have SAR enabled does not result in
+ * setting the Tx power scenario
+ */
+ @Test
+ public void testSarMgr_disabledTxPowerScenario_sapOn() throws Exception {
+ createSarManager(false, false);
+
+ /* Enable WiFi SoftAP State */
+ mSarMgr.setSapWifiState(WifiManager.WIFI_AP_STATE_ENABLED);
+
+ verify(mWifiNative, never()).selectTxPowerScenario(any(SarInfo.class));
+ }
+
+ /**
+ * Test that Start of SoftAP for a device that has SAR enabled, SAR sensor disabled.
+ */
+ @Test
+ public void testSarMgr_enabledTxPowerScenario_sapOn() throws Exception {
+ createSarManager(true, false);
+
+ InOrder inOrder = inOrder(mWifiNative);
+
+ /* Enable WiFi SoftAP State */
+ mSarMgr.setSapWifiState(WifiManager.WIFI_AP_STATE_ENABLED);
+ captureSarInfo(mWifiNative);
+
+ inOrder.verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertFalse(mSarInfo.mIsVoiceCall);
+ assertTrue(mSarInfo.mIsWifiSapEnabled);
+ assertFalse(mSarInfo.mIsWifiScanOnlyEnabled);
+ }
+
+ /**
+ * Test that for a device that has SAR enabled, SAR sensor enabled, near head, and when
+ * wifi sta is enabled, turning on sap then turning it off.
+ */
+ @Test
+ public void testSarMgr_enabledTxPowerScenario_staOn_sapOnOff() throws Exception {
+ createSarManager(true, true);
+
+ InOrder inOrder = inOrder(mWifiNative);
+
+ /* Sensor event */
+ sendSensorEvent(SAR_SENSOR_EVENT_HEAD);
+ inOrder.verify(mWifiNative, never()).selectTxPowerScenario(any(SarInfo.class));
+
+ /* Enable WiFi Client State */
+ mSarMgr.setClientWifiState(WifiManager.WIFI_STATE_ENABLED);
+ captureSarInfo(mWifiNative);
+
+ inOrder.verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertEquals(SarInfo.SAR_SENSOR_NEAR_HEAD, mSarInfo.mSensorState);
+ assertFalse(mSarInfo.mIsWifiSapEnabled);
+
+ /* Enable WiFi SoftAP State */
+ mSarMgr.setSapWifiState(WifiManager.WIFI_AP_STATE_ENABLED);
+ inOrder.verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertEquals(SarInfo.SAR_SENSOR_NEAR_HEAD, mSarInfo.mSensorState);
+ assertTrue(mSarInfo.mIsWifiSapEnabled);
+
+ /* Disable Wifi SoftAP state */
+ mSarMgr.setSapWifiState(WifiManager.WIFI_AP_STATE_DISABLED);
+ inOrder.verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertEquals(SarInfo.SAR_SENSOR_NEAR_HEAD, mSarInfo.mSensorState);
+ assertFalse(mSarInfo.mIsWifiSapEnabled);
+ }
+
+ /**
+ * Test that for a device that has SAR enabled, SAR sensor enabled, Near body, and when
+ * disabling wifi softAP while Wifi Sta is also disabled, no update to the HAL for Tx
+ * power scenario is issued.
+ * Then, when wifi client is enabled, the Tx Power scenario is set.
+ * This is to verify that no call to update tx power when all wifi modes are disabled.
+ */
+ @Test
+ public void testSarMgr_enabledTxPowerScenario_sapOnOff_staOffOn() throws Exception {
+ createSarManager(true, true);
+
+ InOrder inOrder = inOrder(mWifiNative);
+
+ /* Sensor event */
+ sendSensorEvent(SAR_SENSOR_EVENT_BODY);
+ inOrder.verify(mWifiNative, never()).selectTxPowerScenario(any(SarInfo.class));
+
+ /* Enable WiFi softAP State */
+ mSarMgr.setSapWifiState(WifiManager.WIFI_AP_STATE_ENABLED);
+ captureSarInfo(mWifiNative);
+
+ inOrder.verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertEquals(SarInfo.SAR_SENSOR_NEAR_BODY, mSarInfo.mSensorState);
+ assertTrue(mSarInfo.mIsWifiSapEnabled);
+
+ /* Disable Wifi SoftAP state */
+ mSarMgr.setSapWifiState(WifiManager.WIFI_AP_STATE_DISABLED);
+ inOrder.verify(mWifiNative, never()).selectTxPowerScenario(any(SarInfo.class));
+
+ /* Enable WiFi Clinet State */
+ mSarMgr.setClientWifiState(WifiManager.WIFI_STATE_ENABLED);
+ inOrder.verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertEquals(SarInfo.SAR_SENSOR_NEAR_BODY, mSarInfo.mSensorState);
+ assertFalse(mSarInfo.mIsWifiSapEnabled);
+ }
+
+ /**
+ * Test that for a device that has SAR enabled, when scan-only state is enabled with both SoftAP
+ * and Client states disabled, the SarInfo is reported with proper values.
+ */
+ @Test
+ public void testSarMgr_enabledTxPowerScenario_staOff_sapOff_scanOnlyOn() throws Exception {
+ createSarManager(true, false);
+
+ /* Enable Wifi ScanOnly State */
+ mSarMgr.setScanOnlyWifiState(WifiManager.WIFI_STATE_ENABLED);
+ captureSarInfo(mWifiNative);
+
+ verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertFalse(mSarInfo.mIsWifiSapEnabled);
+ assertTrue(mSarInfo.mIsWifiScanOnlyEnabled);
+ }
+
+ /**
+ * Test that for a device that has SAR enabled, when scan-only state is enabled, and then
+ * client state is enabled, no additional setting of Tx power scenario is initiated
+ */
+ @Test
+ public void testSarMgr_enabledTxPowerScenario_staOn_sapOff_scanOnlyOn() throws Exception {
+ createSarManager(true, false);
+
+ InOrder inOrder = inOrder(mWifiNative);
+
+ /* Enable Wifi ScanOnly State */
+ mSarMgr.setScanOnlyWifiState(WifiManager.WIFI_STATE_ENABLED);
+ captureSarInfo(mWifiNative);
+
+ inOrder.verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertFalse(mSarInfo.mIsWifiSapEnabled);
+ assertTrue(mSarInfo.mIsWifiScanOnlyEnabled);
+
+ /* Now enable Client state */
+ mSarMgr.setClientWifiState(WifiManager.WIFI_STATE_ENABLED);
+ inOrder.verify(mWifiNative, never()).selectTxPowerScenario(any(SarInfo.class));
+ }
+
+ /**
+ * Test the success case for for devices supporting SAR, with no SAR sensor support,
+ * Wifi enabled, SoftAP enabled, wifi disabled, scan-only enabled, SoftAP disabled.
+ *
+ * SarManager should report these changes as they occur(only when changes occur to
+ * inputs affecting the SAR scenario).
+ */
+ @Test
+ public void testSarMgr_enabledTxPowerScenario_wifi_sap_scanOnly() throws Exception {
+ createSarManager(true, false);
+
+ InOrder inOrder = inOrder(mWifiNative);
+
+ /* Enable WiFi State */
+ mSarMgr.setClientWifiState(WifiManager.WIFI_STATE_ENABLED);
+ captureSarInfo(mWifiNative);
+
+ inOrder.verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertFalse(mSarInfo.mIsVoiceCall);
+ assertFalse(mSarInfo.mIsWifiSapEnabled);
+ assertFalse(mSarInfo.mIsWifiScanOnlyEnabled);
+
+ /* Enable SoftAP state */
+ mSarMgr.setSapWifiState(WifiManager.WIFI_AP_STATE_ENABLED);
+ inOrder.verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertFalse(mSarInfo.mIsVoiceCall);
+ assertTrue(mSarInfo.mIsWifiSapEnabled);
+ assertFalse(mSarInfo.mIsWifiScanOnlyEnabled);
+
+ /* Disable WiFi State */
+ mSarMgr.setClientWifiState(WifiManager.WIFI_STATE_DISABLED);
+ inOrder.verify(mWifiNative, never()).selectTxPowerScenario(any(SarInfo.class));
+
+ /* Enable ScanOnly state */
+ mSarMgr.setScanOnlyWifiState(WifiManager.WIFI_STATE_ENABLED);
+ inOrder.verify(mWifiNative, never()).selectTxPowerScenario(any(SarInfo.class));
+
+ /* Disable SoftAP state */
+ mSarMgr.setSapWifiState(WifiManager.WIFI_AP_STATE_DISABLED);
+ inOrder.verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertFalse(mSarInfo.mIsVoiceCall);
+ assertFalse(mSarInfo.mIsWifiSapEnabled);
+ assertTrue(mSarInfo.mIsWifiScanOnlyEnabled);
+ }
+
+ /**
+ * Test the error case for devices supporting SAR, with no SAR sensor support,
+ * Wifi enabled, SoftAP enabled, wifi disabled, scan-only enabled, SoftAP disabled
+ * Throughout this test case, calls to the hal return with error.
+ */
+ @Test
+ public void testSarMgr_enabledTxPowerScenario_error_wifi_sap_scanOnly() throws Exception {
+ createSarManager(true, false);
+
+ when(mWifiNative.selectTxPowerScenario(any(SarInfo.class))).thenReturn(false);
+ InOrder inOrder = inOrder(mWifiNative);
+
+ /* Enable WiFi State */
+ mSarMgr.setClientWifiState(WifiManager.WIFI_STATE_ENABLED);
+ captureSarInfo(mWifiNative);
+
+ inOrder.verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertFalse(mSarInfo.mIsVoiceCall);
+ assertFalse(mSarInfo.mIsWifiSapEnabled);
+ assertFalse(mSarInfo.mIsWifiScanOnlyEnabled);
+
+ /* Enable SoftAP state */
+ mSarMgr.setSapWifiState(WifiManager.WIFI_AP_STATE_ENABLED);
+ inOrder.verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertFalse(mSarInfo.mIsVoiceCall);
+ assertTrue(mSarInfo.mIsWifiSapEnabled);
+ assertFalse(mSarInfo.mIsWifiScanOnlyEnabled);
+
+ /* Disable WiFi State, reporting should still happen */
+ mSarMgr.setClientWifiState(WifiManager.WIFI_STATE_DISABLED);
+ inOrder.verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertFalse(mSarInfo.mIsVoiceCall);
+ assertTrue(mSarInfo.mIsWifiSapEnabled);
+ assertFalse(mSarInfo.mIsWifiScanOnlyEnabled);
+ assertFalse(mSarInfo.mIsWifiClientEnabled);
+
+ /* Enable ScanOnly state */
+ mSarMgr.setScanOnlyWifiState(WifiManager.WIFI_STATE_ENABLED);
+ inOrder.verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertFalse(mSarInfo.mIsVoiceCall);
+ assertTrue(mSarInfo.mIsWifiSapEnabled);
+ assertTrue(mSarInfo.mIsWifiScanOnlyEnabled);
+ assertFalse(mSarInfo.mIsWifiClientEnabled);
+
+ /* Disable SoftAP state */
+ mSarMgr.setSapWifiState(WifiManager.WIFI_AP_STATE_DISABLED);
+ inOrder.verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertFalse(mSarInfo.mIsVoiceCall);
+ assertFalse(mSarInfo.mIsWifiSapEnabled);
+ assertTrue(mSarInfo.mIsWifiScanOnlyEnabled);
+ assertFalse(mSarInfo.mIsWifiClientEnabled);
}
}
diff --git a/tests/wifitests/src/com/android/server/wifi/ScanOnlyModeManagerTest.java b/tests/wifitests/src/com/android/server/wifi/ScanOnlyModeManagerTest.java
index 41362eec6..8c2444592 100644
--- a/tests/wifitests/src/com/android/server/wifi/ScanOnlyModeManagerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/ScanOnlyModeManagerTest.java
@@ -71,6 +71,7 @@ public class ScanOnlyModeManagerTest {
@Mock WifiMonitor mWifiMonitor;
@Mock ScanRequestProxy mScanRequestProxy;
@Mock WakeupController mWakeupController;
+ @Mock SarManager mSarManager;
final ArgumentCaptor<WifiNative.InterfaceCallback> mInterfaceCallbackCaptor =
ArgumentCaptor.forClass(WifiNative.InterfaceCallback.class);
@@ -86,7 +87,7 @@ public class ScanOnlyModeManagerTest {
private ScanOnlyModeManager createScanOnlyModeManager() {
return new ScanOnlyModeManager(mContext, mLooper.getLooper(), mWifiNative, mListener,
- mWifiMetrics, mScanRequestProxy, mWakeupController);
+ mWifiMetrics, mScanRequestProxy, mWakeupController, mSarManager);
}
private void startScanOnlyModeAndVerifyEnabled() throws Exception {
@@ -112,6 +113,7 @@ public class ScanOnlyModeManagerTest {
checkWifiStateChangeListenerUpdate(WIFI_STATE_ENABLED);
verify(mScanRequestProxy, atLeastOnce()).clearScanResults();
verify(mScanRequestProxy, atLeastOnce()).enableScanningForHiddenNetworks(false);
+ verify(mSarManager).setScanOnlyWifiState(eq(WIFI_STATE_ENABLED));
}
private void checkWifiScanStateChangedBroadcast(Intent intent, int expectedCurrentState) {
@@ -170,6 +172,7 @@ public class ScanOnlyModeManagerTest {
mLooper.dispatchAll();
verify(mWifiNative).teardownInterface(TEST_INTERFACE_NAME);
verify(mContext, never()).sendStickyBroadcastAsUser(any(), eq(UserHandle.ALL));
+ verify(mSarManager).setScanOnlyWifiState(eq(WIFI_STATE_DISABLED));
verifyNoMoreInteractions(mListener);
}
diff --git a/tests/wifitests/src/com/android/server/wifi/SoftApManagerTest.java b/tests/wifitests/src/com/android/server/wifi/SoftApManagerTest.java
index 0b937849d..6a2c21242 100644
--- a/tests/wifitests/src/com/android/server/wifi/SoftApManagerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/SoftApManagerTest.java
@@ -90,6 +90,7 @@ public class SoftApManagerTest {
@Mock FrameworkFacade mFrameworkFacade;
@Mock WifiApConfigStore mWifiApConfigStore;
@Mock WifiMetrics mWifiMetrics;
+ @Mock SarManager mSarManager;
final ArgumentCaptor<WifiNative.InterfaceCallback> mWifiNativeInterfaceCallbackCaptor =
ArgumentCaptor.forClass(WifiNative.InterfaceCallback.class);
final ArgumentCaptor<WifiNative.SoftApListener> mSoftApListenerCaptor =
@@ -133,7 +134,8 @@ public class SoftApManagerTest {
mCallback,
mWifiApConfigStore,
config,
- mWifiMetrics);
+ mWifiMetrics,
+ mSarManager);
mLooper.dispatchAll();
return newSoftApManager;
@@ -205,7 +207,8 @@ public class SoftApManagerTest {
mCallback,
mWifiApConfigStore,
nullApConfig,
- mWifiMetrics);
+ mWifiMetrics,
+ mSarManager);
mLooper.dispatchAll();
newSoftApManager.start();
mLooper.dispatchAll();
@@ -247,7 +250,8 @@ public class SoftApManagerTest {
mCallback,
mWifiApConfigStore,
nullApConfig,
- mWifiMetrics);
+ mWifiMetrics,
+ mSarManager);
mLooper.dispatchAll();
newSoftApManager.start();
mLooper.dispatchAll();
@@ -288,7 +292,8 @@ public class SoftApManagerTest {
mCallback,
mWifiApConfigStore,
nullApConfig,
- mWifiMetrics);
+ mWifiMetrics,
+ mSarManager);
mLooper.dispatchAll();
newSoftApManager.start();
mLooper.dispatchAll();
@@ -329,7 +334,8 @@ public class SoftApManagerTest {
mCallback,
mWifiApConfigStore,
softApConfig,
- mWifiMetrics);
+ mWifiMetrics,
+ mSarManager);
mLooper.dispatchAll();
newSoftApManager.start();
mLooper.dispatchAll();
@@ -371,7 +377,8 @@ public class SoftApManagerTest {
mCallback,
mWifiApConfigStore,
softApConfig,
- mWifiMetrics);
+ mWifiMetrics,
+ mSarManager);
mLooper.dispatchAll();
newSoftApManager.start();
mLooper.dispatchAll();
@@ -408,7 +415,8 @@ public class SoftApManagerTest {
mCallback,
mWifiApConfigStore,
softApModeConfig,
- mWifiMetrics);
+ mWifiMetrics,
+ mSarManager);
mLooper.dispatchAll();
newSoftApManager.start();
@@ -429,6 +437,7 @@ public class SoftApManagerTest {
mLooper.dispatchAll();
/* Verify no state changes. */
verify(mCallback, never()).onStateChanged(anyInt(), anyInt());
+ verify(mSarManager, never()).setSapWifiState(anyInt());
verify(mContext, never()).sendStickyBroadcastAsUser(any(), any());
verify(mWifiNative, never()).teardownInterface(anyString());
}
@@ -459,6 +468,7 @@ public class SoftApManagerTest {
softApModeConfig.getTargetMode());
order.verify(mCallback).onStateChanged(WifiManager.WIFI_AP_STATE_DISABLED, 0);
+ verify(mSarManager).setSapWifiState(WifiManager.WIFI_AP_STATE_DISABLED);
order.verify(mContext).sendStickyBroadcastAsUser(intentCaptor.capture(),
eq(UserHandle.ALL));
checkApStateChangedBroadcast(intentCaptor.getValue(), WIFI_AP_STATE_DISABLED,
@@ -938,6 +948,7 @@ public class SoftApManagerTest {
mLooper.dispatchAll();
order.verify(mCallback).onStateChanged(WifiManager.WIFI_AP_STATE_ENABLED, 0);
order.verify(mCallback).onNumClientsChanged(0);
+ verify(mSarManager).setSapWifiState(WifiManager.WIFI_AP_STATE_ENABLED);
verify(mContext, times(2)).sendStickyBroadcastAsUser(intentCaptor.capture(),
eq(UserHandle.ALL));
List<Intent> capturedIntents = intentCaptor.getAllValues();
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiNativeTest.java b/tests/wifitests/src/com/android/server/wifi/WifiNativeTest.java
index 31e7e553c..fbdc8f507 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiNativeTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiNativeTest.java
@@ -586,4 +586,26 @@ public class WifiNativeTest {
verify(mWificondControl).startHostapd(WIFI_IFACE_NAME, mockListener);
verify(mWifiMetrics).incrementNumSetupSoftApInterfaceFailureDueToHostapd();
}
+
+ /**
+ * Test that selectTxPowerScenario() calls into WifiVendorHal (success case)
+ */
+ @Test
+ public void testSelectTxPowerScenario_success() throws Exception {
+ when(mWifiVendorHal.selectTxPowerScenario(any(SarInfo.class))).thenReturn(true);
+ SarInfo sarInfo = new SarInfo(true);
+ assertTrue(mWifiNative.selectTxPowerScenario(sarInfo));
+ verify(mWifiVendorHal).selectTxPowerScenario(sarInfo);
+ }
+
+ /**
+ * Test that selectTxPowerScenario() calls into WifiVendorHal (failure case)
+ */
+ @Test
+ public void testSelectTxPowerScenario_failure() throws Exception {
+ when(mWifiVendorHal.selectTxPowerScenario(any(SarInfo.class))).thenReturn(false);
+ SarInfo sarInfo = new SarInfo(true);
+ assertFalse(mWifiNative.selectTxPowerScenario(sarInfo));
+ verify(mWifiVendorHal).selectTxPowerScenario(sarInfo);
+ }
}
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiVendorHalTest.java b/tests/wifitests/src/com/android/server/wifi/WifiVendorHalTest.java
index 0f8f56f66..fc030b83c 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiVendorHalTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiVendorHalTest.java
@@ -32,6 +32,7 @@ import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
@@ -99,6 +100,7 @@ import com.android.server.wifi.util.NativeUtil;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
+import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.stubbing.Answer;
@@ -119,6 +121,7 @@ public class WifiVendorHalTest {
private static final String TEST_IFACE_NAME = "wlan0";
private static final String TEST_IFACE_NAME_1 = "wlan1";
private static final MacAddress TEST_MAC_ADDRESS = MacAddress.fromString("ee:33:a2:94:10:92");
+ private static final int SAR_SENSOR_INVALID_STATE = -6;
WifiVendorHal mWifiVendorHal;
private WifiStatus mWifiStatusSuccess;
@@ -1997,67 +2000,433 @@ public class WifiVendorHalTest {
}
/**
- * Test the new selectTxPowerScenario HIDL method invocation. This should return failure if the
- * HAL service is exposing the 1.0 interface.
+ * Test the selectTxPowerScenario HIDL method invocation for 1.0 interface.
+ * This should return failure since SAR is not supported for this interface version.
*/
@Test
- public void testSelectTxPowerScenario() throws RemoteException {
+ public void testSelectTxPowerScenario_1_0() throws RemoteException {
+ // Create a SAR info record (no sensor support)
+ SarInfo sarInfo = new SarInfo(false);
+ sarInfo.mIsVoiceCall = true;
+
assertTrue(mWifiVendorHal.startVendorHalSta());
// Should fail because we exposed the 1.0 IWifiChip.
- assertFalse(
- mWifiVendorHal.selectTxPowerScenario(WifiNative.TX_POWER_SCENARIO_VOICE_CALL));
+ assertFalse(mWifiVendorHal.selectTxPowerScenario(sarInfo));
verify(mIWifiChipV11, never()).selectTxPowerScenario(anyInt());
mWifiVendorHal.stopVendorHal();
+ }
+
+ /**
+ * Test the selectTxPowerScenario HIDL method invocation for 1.1 interface.
+ * This should return success.
+ */
+ @Test
+ public void testSelectTxPowerScenario_1_1() throws RemoteException {
+ // Create a SAR info record (no sensor support)
+ SarInfo sarInfo = new SarInfo(false);
+ sarInfo.mIsVoiceCall = true;
// Now expose the 1.1 IWifiChip.
mWifiVendorHal = new WifiVendorHalSpyV1_1(mHalDeviceManager, mLooper.getLooper());
when(mIWifiChipV11.selectTxPowerScenario(anyInt())).thenReturn(mWifiStatusSuccess);
assertTrue(mWifiVendorHal.startVendorHalSta());
- assertTrue(
- mWifiVendorHal.selectTxPowerScenario(WifiNative.TX_POWER_SCENARIO_VOICE_CALL));
+ assertTrue(mWifiVendorHal.selectTxPowerScenario(sarInfo));
verify(mIWifiChipV11).selectTxPowerScenario(
eq(android.hardware.wifi.V1_1.IWifiChip.TxPowerScenario.VOICE_CALL));
verify(mIWifiChipV11, never()).resetTxPowerScenario();
mWifiVendorHal.stopVendorHal();
}
+ /**
+ * Test the selectTxPowerScenario HIDL method invocation for 1.2 interface.
+ * This should return success.
+ */
+ @Test
+ public void testSelectTxPowerScenario_1_2() throws RemoteException {
+ // Create a SAR info record (no sensor support)
+ SarInfo sarInfo = new SarInfo(false);
+ sarInfo.mIsVoiceCall = true;
+
+ // Now expose the 1.2 IWifiChip
+ mWifiVendorHal = new WifiVendorHalSpyV1_2(mHalDeviceManager, mLooper.getLooper());
+ when(mIWifiChipV12.selectTxPowerScenario_1_2(anyInt())).thenReturn(mWifiStatusSuccess);
+
+ assertTrue(mWifiVendorHal.startVendorHalSta());
+ assertTrue(mWifiVendorHal.selectTxPowerScenario(sarInfo));
+ verify(mIWifiChipV12).selectTxPowerScenario_1_2(
+ eq(android.hardware.wifi.V1_2.IWifiChip.TxPowerScenario.VOICE_CALL));
+ verify(mIWifiChipV12, never()).resetTxPowerScenario();
+ mWifiVendorHal.stopVendorHal();
+ }
+
/**
- * Test the new resetTxPowerScenario HIDL method invocation. This should return failure if the
- * HAL service is exposing the 1.0 interface.
+ * Test the resetTxPowerScenario HIDL method invocation for 1.0 interface.
+ * This should return failure since it does not supprt SAR.
*/
@Test
- public void testResetTxPowerScenario() throws RemoteException {
+ public void testResetTxPowerScenario_1_0() throws RemoteException {
+ // Create a SAR info record (no sensor support)
+ SarInfo sarInfo = new SarInfo(false);
+
assertTrue(mWifiVendorHal.startVendorHalSta());
// Should fail because we exposed the 1.0 IWifiChip.
- assertFalse(mWifiVendorHal.selectTxPowerScenario(WifiNative.TX_POWER_SCENARIO_NORMAL));
+ assertFalse(mWifiVendorHal.selectTxPowerScenario(sarInfo));
verify(mIWifiChipV11, never()).resetTxPowerScenario();
mWifiVendorHal.stopVendorHal();
+ }
+
+ /**
+ * Test the resetTxPowerScenario HIDL method invocation for 1.1 interface.
+ * This should return success.
+ */
+ @Test
+ public void testResetTxPowerScenario_1_1() throws RemoteException {
+ // Create a SAR info record (no sensor support)
+ SarInfo sarInfo = new SarInfo(false);
// Now expose the 1.1 IWifiChip.
mWifiVendorHal = new WifiVendorHalSpyV1_1(mHalDeviceManager, mLooper.getLooper());
when(mIWifiChipV11.resetTxPowerScenario()).thenReturn(mWifiStatusSuccess);
assertTrue(mWifiVendorHal.startVendorHalSta());
- assertTrue(mWifiVendorHal.selectTxPowerScenario(WifiNative.TX_POWER_SCENARIO_NORMAL));
+ assertTrue(mWifiVendorHal.selectTxPowerScenario(sarInfo));
verify(mIWifiChipV11).resetTxPowerScenario();
verify(mIWifiChipV11, never()).selectTxPowerScenario(anyInt());
mWifiVendorHal.stopVendorHal();
}
/**
- * Test the new selectTxPowerScenario HIDL method invocation with a bad scenario index.
+ * Test resetting SAR scenario when not needed, should return true without invoking
+ * the HAL method.
+ * This is using HAL 1.1 interface.
*/
@Test
- public void testInvalidSelectTxPowerScenario() throws RemoteException {
+ public void testResetTxPowerScenario_not_needed_1_1() throws RemoteException {
+ InOrder inOrder = inOrder(mIWifiChipV11);
+
+ // Create a SAR info record (no sensor support)
+ SarInfo sarInfo = new SarInfo(false);
+
+ // Now expose the 1.1 IWifiChip.
+ mWifiVendorHal = new WifiVendorHalSpyV1_1(mHalDeviceManager, mLooper.getLooper());
+ when(mIWifiChipV11.resetTxPowerScenario()).thenReturn(mWifiStatusSuccess);
+
+ assertTrue(mWifiVendorHal.startVendorHalSta());
+
+ /* Calling reset once */
+ assertTrue(mWifiVendorHal.selectTxPowerScenario(sarInfo));
+ inOrder.verify(mIWifiChipV11).resetTxPowerScenario();
+ inOrder.verify(mIWifiChipV11, never()).selectTxPowerScenario(anyInt());
+ sarInfo.reportingSuccessful();
+
+ /* Calling reset second time */
+ assertTrue(mWifiVendorHal.selectTxPowerScenario(sarInfo));
+ inOrder.verify(mIWifiChipV11, never()).resetTxPowerScenario();
+ inOrder.verify(mIWifiChipV11, never()).selectTxPowerScenario(anyInt());
+
+ mWifiVendorHal.stopVendorHal();
+ }
+
+ /**
+ * Test the new resetTxPowerScenario HIDL method invocation for 1.2 interface.
+ * This should return success.
+ */
+ @Test
+ public void testResetTxPowerScenario_1_2() throws RemoteException {
+ // Create a SAR info record (no sensor support)
+ SarInfo sarInfo = new SarInfo(false);
+
+ // Now expose the 1.2 IWifiChip.
+ mWifiVendorHal = new WifiVendorHalSpyV1_2(mHalDeviceManager, mLooper.getLooper());
+ when(mIWifiChipV12.resetTxPowerScenario()).thenReturn(mWifiStatusSuccess);
+
+ assertTrue(mWifiVendorHal.startVendorHalSta());
+ assertTrue(mWifiVendorHal.selectTxPowerScenario(sarInfo));
+ verify(mIWifiChipV12).resetTxPowerScenario();
+ verify(mIWifiChipV12, never()).selectTxPowerScenario_1_2(anyInt());
+ mWifiVendorHal.stopVendorHal();
+ }
+
+ /**
+ * Test resetting SAR scenario when not needed, should return true without invoking
+ * the HAL method.
+ * This is using HAL 1.2 interface.
+ */
+ @Test
+ public void testResetTxPowerScenario_not_needed_1_2() throws RemoteException {
+ InOrder inOrder = inOrder(mIWifiChipV12);
+
+ // Create a SAR info record (no sensor support)
+ SarInfo sarInfo = new SarInfo(false);
+
+ // Now expose the 1.2 IWifiChip.
+ mWifiVendorHal = new WifiVendorHalSpyV1_2(mHalDeviceManager, mLooper.getLooper());
+ when(mIWifiChipV12.resetTxPowerScenario()).thenReturn(mWifiStatusSuccess);
+
+ assertTrue(mWifiVendorHal.startVendorHalSta());
+
+ /* Calling reset once */
+ assertTrue(mWifiVendorHal.selectTxPowerScenario(sarInfo));
+ inOrder.verify(mIWifiChipV12).resetTxPowerScenario();
+ inOrder.verify(mIWifiChipV12, never()).selectTxPowerScenario(anyInt());
+ sarInfo.reportingSuccessful();
+
+ /* Calling reset second time */
+ assertTrue(mWifiVendorHal.selectTxPowerScenario(sarInfo));
+ inOrder.verify(mIWifiChipV12, never()).resetTxPowerScenario();
+ inOrder.verify(mIWifiChipV12, never()).selectTxPowerScenario(anyInt());
+
+ mWifiVendorHal.stopVendorHal();
+ }
+
+ /**
+ * Test the selectTxPowerScenario HIDL method invocation with sensor related scenarios
+ * to IWifiChip 1.2 interface
+ */
+ @Test
+ public void testHeadSensorScenarios_SelectTxPowerV1_2() throws RemoteException {
+ // Create a SAR info record (with sensor support)
+ SarInfo sarInfo = new SarInfo(true);
+ sarInfo.mSensorState = SarInfo.SAR_SENSOR_NEAR_HEAD;
+
+ // Expose the 1.2 IWifiChip.
+ mWifiVendorHal = new WifiVendorHalSpyV1_2(mHalDeviceManager, mLooper.getLooper());
+ when(mIWifiChipV12.selectTxPowerScenario_1_2(anyInt())).thenReturn(mWifiStatusSuccess);
+
+ // ON_HEAD_CELL_OFF
+ assertTrue(mWifiVendorHal.startVendorHalSta());
+ assertTrue(mWifiVendorHal.selectTxPowerScenario(sarInfo));
+ verify(mIWifiChipV12).selectTxPowerScenario_1_2(
+ eq(android.hardware.wifi.V1_2.IWifiChip.TxPowerScenario.ON_HEAD_CELL_OFF));
+ verify(mIWifiChipV12, never()).resetTxPowerScenario();
+ mWifiVendorHal.stopVendorHal();
+ }
+
+ /**
+ * Test setting SAR scenario when not needed, should return true without invoking
+ * the HAL method.
+ * This is using HAL 1.2 interface.
+ */
+ @Test
+ public void testSetTxPowerScenario_not_needed_1_2() throws RemoteException {
+ InOrder inOrder = inOrder(mIWifiChipV12);
+
+ // Create a SAR info record (no sensor support)
+ SarInfo sarInfo = new SarInfo(true);
+ sarInfo.mSensorState = SarInfo.SAR_SENSOR_NEAR_HEAD;
+
+ // Now expose the 1.2 IWifiChip.
+ mWifiVendorHal = new WifiVendorHalSpyV1_2(mHalDeviceManager, mLooper.getLooper());
+ when(mIWifiChipV12.selectTxPowerScenario_1_2(anyInt())).thenReturn(mWifiStatusSuccess);
+
+ assertTrue(mWifiVendorHal.startVendorHalSta());
+
+ /* Calling set once */
+ assertTrue(mWifiVendorHal.selectTxPowerScenario(sarInfo));
+ inOrder.verify(mIWifiChipV12).selectTxPowerScenario_1_2(
+ eq(android.hardware.wifi.V1_2.IWifiChip.TxPowerScenario.ON_HEAD_CELL_OFF));
+ inOrder.verify(mIWifiChipV12, never()).resetTxPowerScenario();
+ sarInfo.reportingSuccessful();
+
+ /* Calling set second time */
+ assertTrue(mWifiVendorHal.selectTxPowerScenario(sarInfo));
+ inOrder.verify(mIWifiChipV12, never()).resetTxPowerScenario();
+ inOrder.verify(mIWifiChipV12, never()).selectTxPowerScenario(anyInt());
+
+ mWifiVendorHal.stopVendorHal();
+ }
+
+ /**
+ * Test the selectTxPowerScenairo HIDL method invocation with sensor events for
+ * IWifiChip 1.2 interface (Near hand event) along with a voice call.
+ * This should be reverted to BODY events (First with CELL_OFF followed by CELL_ON).
+ */
+ @Test
+ public void testHandSensorScenarios_SelectTxPowerV1_2() throws RemoteException {
+ // Create a SAR info record (with sensor support)
+ SarInfo sarInfo = new SarInfo(true);
+ sarInfo.mSensorState = SarInfo.SAR_SENSOR_NEAR_HAND;
+
+ // Expose the 1.2 IWifiChip.
+ mWifiVendorHal = new WifiVendorHalSpyV1_2(mHalDeviceManager, mLooper.getLooper());
+ when(mIWifiChipV12.selectTxPowerScenario_1_2(anyInt())).thenReturn(mWifiStatusSuccess);
+
+ assertTrue(mWifiVendorHal.startVendorHalSta());
+
+ // First select a scenario with cell off
+ assertTrue(mWifiVendorHal.selectTxPowerScenario(sarInfo));
+ verify(mIWifiChipV12).selectTxPowerScenario_1_2(
+ eq(android.hardware.wifi.V1_2.IWifiChip.TxPowerScenario.ON_BODY_CELL_OFF));
+
+ // Then select a scenario with cell on
+ sarInfo.mIsVoiceCall = true;
+ assertTrue(mWifiVendorHal.selectTxPowerScenario(sarInfo));
+ verify(mIWifiChipV12).selectTxPowerScenario_1_2(
+ eq(android.hardware.wifi.V1_2.IWifiChip.TxPowerScenario.ON_BODY_CELL_ON));
+
+ mWifiVendorHal.stopVendorHal();
+ }
+
+ /**
+ * Test the selectTxPowerScenario HIDL method invocation with a sensor info to IWifiChip
+ * 1.1 interface.
+ * Sensor mode should be ignored, and act only based on Cell on/off.
+ */
+ @Test
+ public void testOnHeadCellOffOn_SelectTxPowerScenarioV1_1() throws RemoteException {
+ // Create a SAR info record (with sensor support)
+ SarInfo sarInfo = new SarInfo(true);
+ sarInfo.mSensorState = SarInfo.SAR_SENSOR_NEAR_HEAD;
+
// Expose the 1.1 IWifiChip.
mWifiVendorHal = new WifiVendorHalSpyV1_1(mHalDeviceManager, mLooper.getLooper());
when(mIWifiChipV11.selectTxPowerScenario(anyInt())).thenReturn(mWifiStatusSuccess);
+ when(mIWifiChipV11.resetTxPowerScenario()).thenReturn(mWifiStatusSuccess);
assertTrue(mWifiVendorHal.startVendorHalSta());
- assertFalse(mWifiVendorHal.selectTxPowerScenario(-6));
- verify(mIWifiChipV11, never()).selectTxPowerScenario(anyInt());
- verify(mIWifiChipV11, never()).resetTxPowerScenario();
+
+ // First select a scenario with cell off
+ assertTrue(mWifiVendorHal.selectTxPowerScenario(sarInfo));
+ verify(mIWifiChipV11).resetTxPowerScenario();
+
+ // Then select a scenario with cell on
+ sarInfo.mIsVoiceCall = true;
+ assertTrue(mWifiVendorHal.selectTxPowerScenario(sarInfo));
+ verify(mIWifiChipV11).selectTxPowerScenario(
+ eq(android.hardware.wifi.V1_1.IWifiChip.TxPowerScenario.VOICE_CALL));
+
+ mWifiVendorHal.stopVendorHal();
+ }
+
+ /**
+ * Test the new selectTxPowerScenario HIDL method invocation with a bad input.
+ * This should not result into any calls to the HAL.
+ * Use IWifiChip 1.2 interface
+ */
+ @Test
+ public void testInvalidSelectTxPowerScenario_1_2() throws RemoteException {
+ // Create a SAR info record (with sensor support)
+ SarInfo sarInfo = new SarInfo(true);
+ sarInfo.mSensorState = SAR_SENSOR_INVALID_STATE;
+
+ // Expose the 1.2 IWifiChip.
+ mWifiVendorHal = new WifiVendorHalSpyV1_2(mHalDeviceManager, mLooper.getLooper());
+
+ assertTrue(mWifiVendorHal.startVendorHalSta());
+ assertFalse(mWifiVendorHal.selectTxPowerScenario(sarInfo));
+ verify(mIWifiChipV12, never()).selectTxPowerScenario(anyInt());
+ verify(mIWifiChipV12, never()).resetTxPowerScenario();
+ mWifiVendorHal.stopVendorHal();
+ }
+
+ /**
+ * Test the selectTxPowerScenario HIDL method invocation with IWifiChip 1.2 interface.
+ * The following inputs:
+ * - Sensor support is enabled
+ * - Sensor state is NEAR_HEAD
+ * - SAP is enabled
+ * - No voice call
+ */
+ @Test
+ public void testSelectTxPowerScenario_1_2_head_sap() throws RemoteException {
+ // Create a SAR info record (with sensor support)
+ SarInfo sarInfo = new SarInfo(true);
+ sarInfo.mSensorState = SarInfo.SAR_SENSOR_NEAR_HEAD;
+ sarInfo.mIsWifiSapEnabled = true;
+ sarInfo.mIsVoiceCall = false;
+
+ // Expose the 1.2 IWifiChip.
+ mWifiVendorHal = new WifiVendorHalSpyV1_2(mHalDeviceManager, mLooper.getLooper());
+ when(mIWifiChipV12.selectTxPowerScenario_1_2(anyInt())).thenReturn(mWifiStatusSuccess);
+
+ assertTrue(mWifiVendorHal.startVendorHalSta());
+ assertTrue(mWifiVendorHal.selectTxPowerScenario(sarInfo));
+ verify(mIWifiChipV12).selectTxPowerScenario_1_2(
+ eq(android.hardware.wifi.V1_2.IWifiChip.TxPowerScenario.ON_HEAD_CELL_ON));
+
+ mWifiVendorHal.stopVendorHal();
+ }
+
+ /**
+ * Test the selectTxPowerScenario HIDL method invocation with IWifiChip 1.2 interface.
+ * The following inputs:
+ * - Sensor support is enabled
+ * - Sensor state is NEAR_HEAD
+ * - SAP is enabled
+ * - voice call is enabled
+ */
+ @Test
+ public void testSelectTxPowerScenario_1_2_head_sap_call() throws RemoteException {
+ // Create a SAR info record (with sensor support)
+ SarInfo sarInfo = new SarInfo(true);
+ sarInfo.mSensorState = SarInfo.SAR_SENSOR_NEAR_HEAD;
+ sarInfo.mIsWifiSapEnabled = true;
+ sarInfo.mIsVoiceCall = true;
+
+ // Expose the 1.2 IWifiChip.
+ mWifiVendorHal = new WifiVendorHalSpyV1_2(mHalDeviceManager, mLooper.getLooper());
+ when(mIWifiChipV12.selectTxPowerScenario_1_2(anyInt())).thenReturn(mWifiStatusSuccess);
+
+ assertTrue(mWifiVendorHal.startVendorHalSta());
+ assertTrue(mWifiVendorHal.selectTxPowerScenario(sarInfo));
+ verify(mIWifiChipV12).selectTxPowerScenario_1_2(
+ eq(android.hardware.wifi.V1_2.IWifiChip.TxPowerScenario.ON_HEAD_CELL_ON));
+
+ mWifiVendorHal.stopVendorHal();
+ }
+
+ /**
+ * Test the selectTxPowerScenario HIDL method invocation with IWifiChip 1.2 interface.
+ * The following inputs:
+ * - Sensor support is enabled
+ * - Sensor state is FREE_SPACE
+ * - SAP is enabled
+ * - No voice call
+ */
+ @Test
+ public void testSelectTxPowerScenario_1_2_freespace_sap() throws RemoteException {
+ // Create a SAR info record (with sensor support)
+ SarInfo sarInfo = new SarInfo(true);
+ sarInfo.mSensorState = SarInfo.SAR_SENSOR_FREE_SPACE;
+ sarInfo.mIsWifiSapEnabled = true;
+ sarInfo.mIsVoiceCall = false;
+
+ // Expose the 1.2 IWifiChip.
+ mWifiVendorHal = new WifiVendorHalSpyV1_2(mHalDeviceManager, mLooper.getLooper());
+ when(mIWifiChipV12.resetTxPowerScenario()).thenReturn(mWifiStatusSuccess);
+
+ assertTrue(mWifiVendorHal.startVendorHalSta());
+ assertTrue(mWifiVendorHal.selectTxPowerScenario(sarInfo));
+
+ verify(mIWifiChipV12).resetTxPowerScenario();
+ verify(mIWifiChipV12, never()).selectTxPowerScenario_1_2(anyInt());
+ mWifiVendorHal.stopVendorHal();
+ }
+
+ /**
+ * Test the selectTxPowerScenario HIDL method invocation with IWifiChip 1.2 interface.
+ * The following inputs:
+ * - Sensor support is disabled
+ * - SAP is enabled
+ * - No voice call
+ */
+ @Test
+ public void testSelectTxPowerScenario_1_2_no_sensors_sap() throws RemoteException {
+ // Create a SAR info record (with no sensor support)
+ SarInfo sarInfo = new SarInfo(false);
+ sarInfo.mIsWifiSapEnabled = true;
+ sarInfo.mIsVoiceCall = false;
+
+ // Expose the 1.2 IWifiChip.
+ mWifiVendorHal = new WifiVendorHalSpyV1_2(mHalDeviceManager, mLooper.getLooper());
+ when(mIWifiChipV12.resetTxPowerScenario()).thenReturn(mWifiStatusSuccess);
+
+ assertTrue(mWifiVendorHal.startVendorHalSta());
+ assertTrue(mWifiVendorHal.selectTxPowerScenario(sarInfo));
+
+ verify(mIWifiChipV12).resetTxPowerScenario();
+ verify(mIWifiChipV12, never()).selectTxPowerScenario_1_2(anyInt());
mWifiVendorHal.stopVendorHal();
}