summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLuca Stefani <luca.stefani.ge1@gmail.com>2018-11-13 21:24:01 +0100
committerLuca Stefani <luca.stefani.ge1@gmail.com>2018-11-13 21:24:09 +0100
commitabd1297d9a46fba457ae038027dba2f752da99c2 (patch)
tree25098694b5cc701c4ffbeb02f0243c7e6bf34a6a
parent1b5f262c74180468c52434d0159c747e1626940d (diff)
parente6d6c9b0b0e523e2ecce02e22e4d55954de0ad65 (diff)
downloadandroid_frameworks_opt_net_wifi-abd1297d9a46fba457ae038027dba2f752da99c2.tar.gz
android_frameworks_opt_net_wifi-abd1297d9a46fba457ae038027dba2f752da99c2.tar.bz2
android_frameworks_opt_net_wifi-abd1297d9a46fba457ae038027dba2f752da99c2.zip
Merge tag 'android-9.0.0_r16' into lineage-16.0
Android 9.0.0 Release 16 (PQ1A.181105.017.A1) * tag 'android-9.0.0_r16': Addition of HW Revision to Wifi Metrics SoftApManager: Set country code before channel selection passpoint-r1: add the metrics for installed passpoint profile type [RTT] Recreate RTT controller when HAL indicates it is invalid Add SarManager and SarInfo dumps to wifi dumpsys SAR: Add conditional support for SAP/voice call WifiController - turn off hotspot in ECM WifiPermissionsUtil: remove connectivity app bypass Don't crash on readPacketFilter() failure WifiServiceImpl: notify user of apBand conversion [RTT] Dump native status information into dumpsys 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 Change-Id: Ia81786f66d8e59062d17dc9402d01ece5783e18d
-rw-r--r--service/java/com/android/server/wifi/FrameworkFacade.java11
-rw-r--r--service/java/com/android/server/wifi/SarInfo.java198
-rw-r--r--service/java/com/android/server/wifi/SarManager.java378
-rw-r--r--service/java/com/android/server/wifi/ScanOnlyModeManager.java7
-rw-r--r--service/java/com/android/server/wifi/SoftApManager.java43
-rw-r--r--service/java/com/android/server/wifi/WifiApConfigStore.java109
-rw-r--r--service/java/com/android/server/wifi/WifiController.java17
-rw-r--r--service/java/com/android/server/wifi/WifiInjector.java11
-rw-r--r--service/java/com/android/server/wifi/WifiMetrics.java84
-rw-r--r--service/java/com/android/server/wifi/WifiNative.java17
-rw-r--r--service/java/com/android/server/wifi/WifiServiceImpl.java20
-rw-r--r--service/java/com/android/server/wifi/WifiVendorHal.java257
-rw-r--r--service/java/com/android/server/wifi/hotspot2/PasspointManager.java1
-rw-r--r--service/java/com/android/server/wifi/rtt/RttMetrics.java1
-rw-r--r--service/java/com/android/server/wifi/rtt/RttNative.java18
-rw-r--r--tests/wifitests/src/com/android/server/wifi/MockResources.java15
-rw-r--r--tests/wifitests/src/com/android/server/wifi/SarInfoTest.java287
-rw-r--r--tests/wifitests/src/com/android/server/wifi/SarManagerTest.java874
-rw-r--r--tests/wifitests/src/com/android/server/wifi/ScanOnlyModeManagerTest.java5
-rw-r--r--tests/wifitests/src/com/android/server/wifi/SoftApManagerTest.java173
-rw-r--r--tests/wifitests/src/com/android/server/wifi/WifiApConfigStoreTest.java155
-rw-r--r--tests/wifitests/src/com/android/server/wifi/WifiMetricsTest.java81
-rw-r--r--tests/wifitests/src/com/android/server/wifi/WifiNativeTest.java22
-rw-r--r--tests/wifitests/src/com/android/server/wifi/WifiServiceImplTest.java27
-rw-r--r--tests/wifitests/src/com/android/server/wifi/WifiVendorHalTest.java517
-rw-r--r--tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointManagerTest.java12
-rw-r--r--tests/wifitests/src/com/android/server/wifi/rtt/RttNativeTest.java84
27 files changed, 3146 insertions, 278 deletions
diff --git a/service/java/com/android/server/wifi/FrameworkFacade.java b/service/java/com/android/server/wifi/FrameworkFacade.java
index 15b9cc738..26cb4ff7b 100644
--- a/service/java/com/android/server/wifi/FrameworkFacade.java
+++ b/service/java/com/android/server/wifi/FrameworkFacade.java
@@ -136,17 +136,6 @@ public class FrameworkFacade {
return true;
}
- /**
- * Create a new instance of WifiApConfigStore.
- * @param context reference to a Context
- * @param backupManagerProxy reference to a BackupManagerProxy
- * @return an instance of WifiApConfigStore
- */
- public WifiApConfigStore makeApConfigStore(Context context,
- BackupManagerProxy backupManagerProxy) {
- return new WifiApConfigStore(context, backupManagerProxy);
- }
-
public long getTxPackets(String iface) {
return TrafficStats.getTxPackets(iface);
}
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..a62307e13
--- /dev/null
+++ b/service/java/com/android/server/wifi/SarInfo.java
@@ -0,0 +1,198 @@
+/*
+ * 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 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";
+
+ /* SAR support configs */
+ public boolean sarVoiceCallSupported;
+ public boolean sarSapSupported;
+ public boolean sarSensorSupported;
+
+ public int sensorState = SAR_SENSOR_FREE_SPACE;
+ public boolean isWifiClientEnabled = false;
+ public boolean isWifiSapEnabled = false;
+ public boolean isWifiScanOnlyEnabled = false;
+ public boolean isVoiceCall = false;
+ public int attemptedSarScenario = 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;
+ private long mLastReportedScenarioTs = 0;
+
+ /**
+ * 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 (!isWifiClientEnabled && !isWifiSapEnabled && !isWifiScanOnlyEnabled) {
+ 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 ((sensorState != mLastReportedSensorState)
+ || (isWifiSapEnabled != mLastReportedIsWifiSapEnabled)
+ || (isVoiceCall != 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 = sensorState;
+ mLastReportedIsWifiSapEnabled = isWifiSapEnabled;
+ mLastReportedIsVoiceCall = isVoiceCall;
+ mLastReportedScenario = attemptedSarScenario;
+ mLastReportedScenarioTs = System.currentTimeMillis();
+
+ 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) {
+ attemptedSarScenario = scenario;
+ return (mLastReportedScenario != scenario);
+ }
+
+ /**
+ * dump()
+ * Dumps the state of SarInfo
+ */
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ pw.println("Dump of SarInfo");
+ pw.println("Current values:");
+ pw.println(" Sensor state is: " + sensorStateToString(sensorState));
+ pw.println(" Voice Call state is: " + isVoiceCall);
+ pw.println(" Wifi Client state is: " + isWifiClientEnabled);
+ pw.println(" Wifi Soft AP state is: " + isWifiSapEnabled);
+ pw.println(" Wifi ScanOnly state is: " + isWifiScanOnlyEnabled);
+ 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);
+ pw.println("Last reported scenario: " + mLastReportedScenario);
+ pw.println("Reported " + (System.currentTimeMillis() - mLastReportedScenarioTs) / 1000
+ + " seconds ago");
+ }
+
+ /**
+ * 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..598e5c964 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,30 @@ 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;
- /* Configuration for SAR */
- private boolean mEnableSarTxPowerLimit;
+ private SarInfo mSarInfo;
- /* Current SAR Scenario */
- private int mCurrentSarScenario = WifiNative.TX_POWER_SCENARIO_NORMAL;
+ /* Configuration for SAR support */
+ private boolean mSupportSarTxPowerLimit;
+ private boolean mSupportSarVoiceCall;
+ private boolean mSupportSarSoftAp;
+ private boolean mSupportSarSensor;
+ /* Sensor event definitions */
+ private int mSarSensorEventFreeSpace;
+ private int mSarSensorEventNearBody;
+ private int mSarSensorEventNearHand;
+ private int mSarSensorEventNearHead;
- /* 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 +73,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 +83,174 @@ 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 (mSupportSarTxPowerLimit) {
+ mSarInfo = new SarInfo();
+ setSarConfigsInInfo();
+ registerListeners();
+ }
+ }
- registerListeners();
+ private void readSarConfigs() {
+ mSupportSarTxPowerLimit = mContext.getResources().getBoolean(
+ R.bool.config_wifi_framework_enable_sar_tx_power_limit);
+ /* In case SAR is disabled,
+ then all SAR inputs are automatically disabled as well (irrespective of the config) */
+ if (!mSupportSarTxPowerLimit) {
+ mSupportSarVoiceCall = false;
+ mSupportSarSoftAp = false;
+ mSupportSarSensor = false;
+ return;
+ }
+
+ /* Voice calls are supported when SAR is supported */
+ mSupportSarVoiceCall = true;
+
+ mSupportSarSoftAp = mContext.getResources().getBoolean(
+ R.bool.config_wifi_framework_enable_soft_ap_sar_tx_power_limit);
+
+ mSupportSarSensor = mContext.getResources().getBoolean(
+ R.bool.config_wifi_framework_enable_body_proximity_sar_tx_power_limit);
+
+ /* Read the sar sensor event Ids */
+ if (mSupportSarSensor) {
+ 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);
+ }
+ }
+
+ private void setSarConfigsInInfo() {
+ mSarInfo.sarVoiceCallSupported = mSupportSarVoiceCall;
+ mSarInfo.sarSapSupported = mSupportSarSoftAp;
+ mSarInfo.sarSensorSupported = mSupportSarSensor;
+ }
+
+ private void registerListeners() {
+ if (mSupportSarVoiceCall) {
+ /* Listen for Phone State changes */
+ registerPhoneStateListener();
+ }
+
+ /* Only listen for SAR sensor if supported */
+ if (mSupportSarSensor) {
+ /* 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.sensorState = 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);
+ }
+
+ /**
+ * Register the body/hand/head proximity sensor.
+ */
+ private boolean registerSensorListener() {
+ Log.i(TAG, "Registering for Sensor notification Listener");
+ return mSensorListener.register();
+ }
- /* Only Start listening for events if SAR is enabled */
- if (mEnableSarTxPowerLimit) {
- Log.d(TAG, "Registering Listeners for the SAR Manager");
+ /**
+ * Update Wifi Client State
+ */
+ public void setClientWifiState(int state) {
+ boolean newIsEnabled;
+ /* No action is taken if SAR is not supported */
+ if (!mSupportSarTxPowerLimit) {
+ return;
+ }
- /* Listen for Phone State changes */
- registerPhoneListener();
+ 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.isWifiClientEnabled != newIsEnabled) {
+ mSarInfo.isWifiClientEnabled = newIsEnabled;
+ updateSarScenario();
+ }
+ }
+
+ /**
+ * Update Wifi SoftAP State
+ */
+ public void setSapWifiState(int state) {
+ boolean newIsEnabled;
+ /* No action is taken if SAR is not supported */
+ if (!mSupportSarTxPowerLimit) {
+ 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.isWifiSapEnabled != newIsEnabled) {
+ mSarInfo.isWifiSapEnabled = newIsEnabled;
+ updateSarScenario();
+ }
+ }
+
+ /**
+ * Update Wifi ScanOnly State
+ */
+ public void setScanOnlyWifiState(int state) {
+ boolean newIsEnabled;
+ /* No action is taken if SAR is not supported */
+ if (!mSupportSarTxPowerLimit) {
+ 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.isWifiScanOnlyEnabled != newIsEnabled) {
+ mSarInfo.isWifiScanOnlyEnabled = newIsEnabled;
+ updateSarScenario();
}
}
@@ -104,42 +258,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.isVoiceCall != newIsVoiceCall) {
+ mSarInfo.isVoiceCall = 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.sensorState != newSensorState) {
+ Log.d(TAG, "Setting Sensor state to " + SarInfo.sensorStateToString(newSensorState));
+ mSarInfo.sensorState = newSensorState;
+ updateSarScenario();
}
}
@@ -147,7 +311,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 +318,20 @@ 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("Dump of SarManager");
+ pw.println("isSarSupported: " + mSupportSarTxPowerLimit);
+ pw.println("isSarVoiceCallSupported: " + mSupportSarVoiceCall);
+ pw.println("isSarSoftApSupported: " + mSupportSarSoftAp);
+ pw.println("isSarSensorSupported: " + mSupportSarSensor);
+ pw.println("");
+ if (mSarInfo != null) {
+ mSarInfo.dump(fd, pw, args);
+ }
}
/**
@@ -177,69 +342,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 (!mSupportSarTxPowerLimit || !mSupportSarVoiceCall) {
+ 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;
+
+ /**
+ * 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;
+ }
- if (newSarScenario != mCurrentSarScenario) {
+ /* 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..c880ab639 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);
}
@@ -228,6 +232,26 @@ public class SoftApManager implements ActiveModeManager {
Log.e(TAG, "Unable to start soft AP without valid configuration");
return ERROR_GENERIC;
}
+ // Setup country code
+ if (TextUtils.isEmpty(mCountryCode)) {
+ if (config.apBand == WifiConfiguration.AP_BAND_5GHZ) {
+ // Country code is mandatory for 5GHz band.
+ Log.e(TAG, "Invalid country code, required for setting up "
+ + "soft ap in 5GHz");
+ return ERROR_GENERIC;
+ }
+ // Absence of country code is not fatal for 2Ghz & Any band options.
+ } else if (!mWifiNative.setCountryCodeHal(
+ mApInterfaceName, mCountryCode.toUpperCase(Locale.ROOT))) {
+ if (config.apBand == WifiConfiguration.AP_BAND_5GHZ) {
+ // Return an error if failed to set country code when AP is configured for
+ // 5GHz band.
+ Log.e(TAG, "Failed to set country code, required for setting up "
+ + "soft ap in 5GHz");
+ return ERROR_GENERIC;
+ }
+ // Failure to set country code is not fatal for 2Ghz & Any band options.
+ }
// Make a copy of configuration for updating AP band and channel.
WifiConfiguration localConfig = new WifiConfiguration(config);
@@ -241,18 +265,6 @@ public class SoftApManager implements ActiveModeManager {
return result;
}
- // Setup country code if it is provided.
- if (mCountryCode != null) {
- // Country code is mandatory for 5GHz band, return an error if failed to set
- // country code when AP is configured for 5GHz band.
- if (!mWifiNative.setCountryCodeHal(
- mApInterfaceName, mCountryCode.toUpperCase(Locale.ROOT))
- && config.apBand == WifiConfiguration.AP_BAND_5GHZ) {
- Log.e(TAG, "Failed to set country code, required for setting up "
- + "soft ap in 5GHz");
- return ERROR_GENERIC;
- }
- }
if (localConfig.hiddenSSID) {
Log.d(TAG, "SoftAP is a hidden network");
}
@@ -491,6 +503,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 +527,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/WifiApConfigStore.java b/service/java/com/android/server/wifi/WifiApConfigStore.java
index 109c0a7af..d21452c8c 100644
--- a/service/java/com/android/server/wifi/WifiApConfigStore.java
+++ b/service/java/com/android/server/wifi/WifiApConfigStore.java
@@ -17,15 +17,25 @@
package com.android.server.wifi;
import android.annotation.NonNull;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiConfiguration.KeyMgmt;
import android.os.Environment;
+import android.os.Handler;
+import android.os.Looper;
import android.text.TextUtils;
import android.util.Log;
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
+import com.android.internal.notification.SystemNotificationChannels;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
@@ -44,6 +54,10 @@ import java.util.UUID;
*/
public class WifiApConfigStore {
+ // Intent when user has interacted with the softap settings change notification
+ public static final String ACTION_HOTSPOT_CONFIG_USER_TAPPED_CONTENT =
+ "com.android.server.wifi.WifiApConfigStoreUtil.HOTSPOT_CONFIG_USER_TAPPED_CONTENT";
+
private static final String TAG = "WifiApConfigStore";
private static final String DEFAULT_AP_CONFIG_FILE =
@@ -71,19 +85,26 @@ public class WifiApConfigStore {
private ArrayList<Integer> mAllowed2GChannel = null;
private final Context mContext;
+ private final Handler mHandler;
private final String mApConfigFile;
private final BackupManagerProxy mBackupManagerProxy;
+ private final FrameworkFacade mFrameworkFacade;
private boolean mRequiresApBandConversion = false;
- WifiApConfigStore(Context context, BackupManagerProxy backupManagerProxy) {
- this(context, backupManagerProxy, DEFAULT_AP_CONFIG_FILE);
+ WifiApConfigStore(Context context, Looper looper,
+ BackupManagerProxy backupManagerProxy, FrameworkFacade frameworkFacade) {
+ this(context, looper, backupManagerProxy, frameworkFacade, DEFAULT_AP_CONFIG_FILE);
}
WifiApConfigStore(Context context,
+ Looper looper,
BackupManagerProxy backupManagerProxy,
+ FrameworkFacade frameworkFacade,
String apConfigFile) {
mContext = context;
+ mHandler = new Handler(looper);
mBackupManagerProxy = backupManagerProxy;
+ mFrameworkFacade = frameworkFacade;
mApConfigFile = apConfigFile;
String ap2GChannelListStr = mContext.getResources().getString(
@@ -111,8 +132,30 @@ public class WifiApConfigStore {
/* Save the default configuration to persistent storage. */
writeApConfiguration(mApConfigFile, mWifiApConfig);
}
+
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(ACTION_HOTSPOT_CONFIG_USER_TAPPED_CONTENT);
+ mContext.registerReceiver(
+ mBroadcastReceiver, filter, null /* broadcastPermission */, mHandler);
}
+ private final BroadcastReceiver mBroadcastReceiver =
+ new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ // For now we only have one registered listener, but we easily could expand this
+ // to support multiple signals. Starting off with a switch to support trivial
+ // expansion.
+ switch(intent.getAction()) {
+ case ACTION_HOTSPOT_CONFIG_USER_TAPPED_CONTENT:
+ handleUserHotspotConfigTappedContent();
+ break;
+ default:
+ Log.e(TAG, "Unknown action " + intent.getAction());
+ }
+ }
+ };
+
/**
* Return the current soft access point configuration.
*/
@@ -145,6 +188,43 @@ public class WifiApConfigStore {
return mAllowed2GChannel;
}
+ /**
+ * Helper method to create and send notification to user of apBand conversion.
+ *
+ * @param packageName name of the calling app
+ */
+ public void notifyUserOfApBandConversion(String packageName) {
+ Log.w(TAG, "ready to post notification - triggered by " + packageName);
+ Notification notification = createConversionNotification();
+ NotificationManager notificationManager = (NotificationManager)
+ mContext.getSystemService(Context.NOTIFICATION_SERVICE);
+ notificationManager.notify(SystemMessage.NOTE_SOFTAP_CONFIG_CHANGED, notification);
+ }
+
+ private Notification createConversionNotification() {
+ CharSequence title = mContext.getText(R.string.wifi_softap_config_change);
+ CharSequence contentSummary = mContext.getText(R.string.wifi_softap_config_change_summary);
+ CharSequence content = mContext.getText(R.string.wifi_softap_config_change_detailed);
+ int color = mContext.getResources()
+ .getColor(R.color.system_notification_accent_color, mContext.getTheme());
+
+ return new Notification.Builder(mContext, SystemNotificationChannels.NETWORK_STATUS)
+ .setSmallIcon(R.drawable.ic_wifi_settings)
+ .setPriority(Notification.PRIORITY_HIGH)
+ .setCategory(Notification.CATEGORY_SYSTEM)
+ .setContentTitle(title)
+ .setContentText(contentSummary)
+ .setContentIntent(getPrivateBroadcast(ACTION_HOTSPOT_CONFIG_USER_TAPPED_CONTENT))
+ .setTicker(title)
+ .setShowWhen(false)
+ .setLocalOnly(true)
+ .setColor(color)
+ .setStyle(new Notification.BigTextStyle().bigText(content)
+ .setBigContentTitle(title)
+ .setSummaryText(contentSummary))
+ .build();
+ }
+
private WifiConfiguration apBandCheckConvert(WifiConfiguration config) {
if (mRequiresApBandConversion) {
// some devices are unable to support 5GHz only operation, check for 5GHz and
@@ -386,4 +466,29 @@ public class WifiApConfigStore {
return true;
}
+
+ /**
+ * Helper method to start up settings on the softap config page.
+ */
+ private void startSoftApSettings() {
+ mContext.startActivity(
+ new Intent("com.android.settings.WIFI_TETHER_SETTINGS")
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
+ }
+
+ /**
+ * Helper method to trigger settings to open the softap config page
+ */
+ private void handleUserHotspotConfigTappedContent() {
+ startSoftApSettings();
+ NotificationManager notificationManager = (NotificationManager)
+ mContext.getSystemService(Context.NOTIFICATION_SERVICE);
+ notificationManager.cancel(SystemMessage.NOTE_SOFTAP_CONFIG_CHANGED);
+ }
+
+ private PendingIntent getPrivateBroadcast(String action) {
+ Intent intent = new Intent(action).setPackage("android");
+ return mFrameworkFacade.getBroadcast(
+ mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+ }
}
diff --git a/service/java/com/android/server/wifi/WifiController.java b/service/java/com/android/server/wifi/WifiController.java
index 05ce47300..d9afc9f74 100644
--- a/service/java/com/android/server/wifi/WifiController.java
+++ b/service/java/com/android/server/wifi/WifiController.java
@@ -308,11 +308,7 @@ public class WifiController extends StateMachine {
break;
case CMD_EMERGENCY_CALL_STATE_CHANGED:
case CMD_EMERGENCY_MODE_CHANGED:
- boolean configWiFiDisableInECBM =
- mFacade.getConfigWiFiDisableInECBM(mContext);
- log("WifiController msg " + msg + " getConfigWiFiDisableInECBM "
- + configWiFiDisableInECBM);
- if ((msg.arg1 == 1) && configWiFiDisableInECBM) {
+ if (msg.arg1 == 1) {
transitionTo(mEcmState);
}
break;
@@ -598,8 +594,15 @@ public class WifiController extends StateMachine {
private int mEcmEntryCount;
@Override
public void enter() {
- mWifiStateMachinePrime.shutdownWifi();
- mWifiStateMachine.clearANQPCache();
+ mWifiStateMachinePrime.stopSoftAPMode();
+ boolean configWiFiDisableInECBM =
+ mFacade.getConfigWiFiDisableInECBM(mContext);
+ log("WifiController msg getConfigWiFiDisableInECBM "
+ + configWiFiDisableInECBM);
+ if (configWiFiDisableInECBM) {
+ mWifiStateMachinePrime.shutdownWifi();
+ mWifiStateMachine.clearANQPCache();
+ }
mEcmEntryCount = 1;
}
diff --git a/service/java/com/android/server/wifi/WifiInjector.java b/service/java/com/android/server/wifi/WifiInjector.java
index 0e30af841..dbf730a73 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;
@@ -204,7 +205,8 @@ public class WifiInjector {
SystemProperties.get(BOOT_DEFAULT_WIFI_COUNTRY_CODE),
mContext.getResources()
.getBoolean(R.bool.config_wifi_revert_country_code_on_cellular_loss));
- mWifiApConfigStore = new WifiApConfigStore(mContext, mBackupManagerProxy);
+ mWifiApConfigStore = new WifiApConfigStore(
+ mContext, wifiStateMachineLooper, mBackupManagerProxy, mFrameworkFacade);
// WifiConfigManager/Store objects and their dependencies.
// New config store
@@ -253,7 +255,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 +466,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 +478,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/WifiMetrics.java b/service/java/com/android/server/wifi/WifiMetrics.java
index a3bd1697c..15f65c980 100644
--- a/service/java/com/android/server/wifi/WifiMetrics.java
+++ b/service/java/com/android/server/wifi/WifiMetrics.java
@@ -18,14 +18,18 @@ package com.android.server.wifi;
import android.hardware.wifi.supplicant.V1_0.ISupplicantStaIfaceCallback;
import android.net.NetworkAgent;
+import android.net.wifi.EAPConstants;
import android.net.wifi.ScanResult;
import android.net.wifi.SupplicantState;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
+import android.net.wifi.hotspot2.PasspointConfiguration;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
+import android.os.SystemProperties;
+
import android.util.Base64;
import android.util.Log;
import android.util.Pair;
@@ -175,6 +179,8 @@ public class WifiMetrics {
private final SparseIntArray mAvailableSavedPasspointProviderBssidsInScanHistogram =
new SparseIntArray();
+ private final SparseIntArray mInstalledPasspointProfileType = new SparseIntArray();
+
/** Mapping of "Connect to Network" notifications to counts. */
private final SparseIntArray mConnectToNetworkNotificationCount = new SparseIntArray();
/** Mapping of "Connect to Network" notification user actions to counts. */
@@ -2028,6 +2034,14 @@ public class WifiMetrics {
+ mWifiLogProto.numPasspointProviderUninstallSuccess);
pw.println("mWifiLogProto.numPasspointProvidersSuccessfullyConnected="
+ mWifiLogProto.numPasspointProvidersSuccessfullyConnected);
+
+ pw.println("mWifiLogProto.installedPasspointProfileType: ");
+ for (int i = 0; i < mInstalledPasspointProfileType.size(); i++) {
+ int eapType = mInstalledPasspointProfileType.keyAt(i);
+ pw.println("EAP_METHOD (" + eapType + "): "
+ + mInstalledPasspointProfileType.valueAt(i));
+ }
+
pw.println("mWifiLogProto.numRadioModeChangeToMcc="
+ mWifiLogProto.numRadioModeChangeToMcc);
pw.println("mWifiLogProto.numRadioModeChangeToScc="
@@ -2150,6 +2164,7 @@ public class WifiMetrics {
pw.println("mWifiLogProto.isMacRandomizationOn=" + mIsMacRandomizationOn);
pw.println("mWifiLogProto.scoreExperimentId=" + mWifiLogProto.scoreExperimentId);
+ pw.println("Hardware Version: " + SystemProperties.get("ro.boot.revision", ""));
}
}
}
@@ -2206,6 +2221,56 @@ public class WifiMetrics {
}
/**
+ * Update number of times for type of saved Passpoint profile.
+ *
+ * @param providers Passpoint providers installed on the device.
+ */
+ public void updateSavedPasspointProfilesInfo(
+ Map<String, PasspointProvider> providers) {
+ int passpointType;
+ int eapType;
+ PasspointConfiguration config;
+ synchronized (mLock) {
+ mInstalledPasspointProfileType.clear();
+ for (Map.Entry<String, PasspointProvider> entry : providers.entrySet()) {
+ config = entry.getValue().getConfig();
+ if (config.getCredential().getUserCredential() != null) {
+ eapType = EAPConstants.EAP_TTLS;
+ } else if (config.getCredential().getCertCredential() != null) {
+ eapType = EAPConstants.EAP_TLS;
+ } else if (config.getCredential().getSimCredential() != null) {
+ eapType = config.getCredential().getSimCredential().getEapType();
+ } else {
+ eapType = -1;
+ }
+ switch (eapType) {
+ case EAPConstants.EAP_TLS:
+ passpointType = WifiMetricsProto.PasspointProfileTypeCount.TYPE_EAP_TLS;
+ break;
+ case EAPConstants.EAP_TTLS:
+ passpointType = WifiMetricsProto.PasspointProfileTypeCount.TYPE_EAP_TTLS;
+ break;
+ case EAPConstants.EAP_SIM:
+ passpointType = WifiMetricsProto.PasspointProfileTypeCount.TYPE_EAP_SIM;
+ break;
+ case EAPConstants.EAP_AKA:
+ passpointType = WifiMetricsProto.PasspointProfileTypeCount.TYPE_EAP_AKA;
+ break;
+ case EAPConstants.EAP_AKA_PRIME:
+ passpointType =
+ WifiMetricsProto.PasspointProfileTypeCount.TYPE_EAP_AKA_PRIME;
+ break;
+ default:
+ passpointType = WifiMetricsProto.PasspointProfileTypeCount.TYPE_UNKNOWN;
+
+ }
+ int count = mInstalledPasspointProfileType.get(passpointType);
+ mInstalledPasspointProfileType.put(passpointType, count + 1);
+ }
+ }
+ }
+
+ /**
* append the separate ConnectionEvent, SystemStateEntry and ScanReturnCode collections to their
* respective lists within mWifiLogProto
*
@@ -2405,6 +2470,23 @@ public class WifiMetrics {
keyVal.count = mConnectToNetworkNotificationActionCount.valueAt(i);
notificationActionCountArray[i] = keyVal;
}
+
+ /**
+ * Convert the SparseIntArray of saved Passpoint profile types and counts to proto's
+ * repeated IntKeyVal array.
+ */
+ int counts = mInstalledPasspointProfileType.size();
+ mWifiLogProto.installedPasspointProfileType =
+ new WifiMetricsProto.PasspointProfileTypeCount[counts];
+ for (int i = 0; i < counts; i++) {
+ mWifiLogProto.installedPasspointProfileType[i] =
+ new WifiMetricsProto.PasspointProfileTypeCount();
+ mWifiLogProto.installedPasspointProfileType[i].eapMethodType =
+ mInstalledPasspointProfileType.keyAt(i);
+ mWifiLogProto.installedPasspointProfileType[i].count =
+ mInstalledPasspointProfileType.valueAt(i);
+ }
+
mWifiLogProto.connectToNetworkNotificationActionCount = notificationActionCountArray;
mWifiLogProto.openNetworkRecommenderBlacklistSize =
@@ -2449,6 +2531,7 @@ public class WifiMetrics {
mWifiLogProto.wifiPowerStats = mWifiPowerMetrics.buildProto();
mWifiLogProto.wifiWakeStats = mWifiWakeMetrics.buildProto();
mWifiLogProto.isMacRandomizationOn = mIsMacRandomizationOn;
+ mWifiLogProto.hardwareRevision = SystemProperties.get("ro.boot.revision", "");
}
}
@@ -2529,6 +2612,7 @@ public class WifiMetrics {
mWpsMetrics.clear();
mWifiWakeMetrics.clear();
mObserved80211mcApInScanHistogram.clear();
+ mInstalledPasspointProfileType.clear();
}
}
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/WifiServiceImpl.java b/service/java/com/android/server/wifi/WifiServiceImpl.java
index 6690e2c8b..c38aa1c66 100644
--- a/service/java/com/android/server/wifi/WifiServiceImpl.java
+++ b/service/java/com/android/server/wifi/WifiServiceImpl.java
@@ -1621,6 +1621,21 @@ public class WifiServiceImpl extends IWifiManager.Stub {
}
/**
+ * Method used to inform user of Ap Configuration conversion due to hardware.
+ */
+ @Override
+ public void notifyUserOfApBandConversion(String packageName) {
+ enforceNetworkSettingsPermission();
+
+ if (mVerboseLoggingEnabled) {
+ mLog.info("notifyUserOfApBandConversion uid=% packageName=%")
+ .c(Binder.getCallingUid()).c(packageName).flush();
+ }
+
+ mWifiApConfigStore.notifyUserOfApBandConversion(packageName);
+ }
+
+ /**
* see {@link android.net.wifi.WifiManager#isScanAlwaysAvailable()}
*/
@Override
@@ -2596,6 +2611,11 @@ public class WifiServiceImpl extends IWifiManager.Stub {
wifiScoreReport.dump(fd, pw, args);
}
pw.println();
+ SarManager sarManager = mWifiInjector.getSarManager();
+ if (sarManager != null) {
+ sarManager.dump(fd, pw, args);
+ }
+ pw.println();
}
}
diff --git a/service/java/com/android/server/wifi/WifiVendorHal.java b/service/java/com/android/server/wifi/WifiVendorHal.java
index 0d73459b5..fad90d140 100644
--- a/service/java/com/android/server/wifi/WifiVendorHal.java
+++ b/service/java/com/android/server/wifi/WifiVendorHal.java
@@ -201,7 +201,7 @@ public class WifiVendorHal {
mVerboseLog.err("% returns %")
.c(niceMethodName(trace, 3))
- .c(HexDump.dumpHexString(result))
+ .c(result == null ? "(null)" : HexDump.dumpHexString(result))
.flush();
return result;
@@ -2653,13 +2653,123 @@ 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 (in case voice call is supported),
+ * no backoff is needed */
+ if (sarInfo.sarVoiceCallSupported) {
+ return sarInfo.isVoiceCall;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * 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 (if voice call is
+ * supported).
+ * Otherwise, an exception is thrown.
+ */
+ private int frameworkToHalTxPowerScenario_1_1(SarInfo sarInfo) {
+ if (sarInfo.sarVoiceCallSupported && sarInfo.isVoiceCall) {
+ return android.hardware.wifi.V1_1.IWifiChip.TxPowerScenario.VOICE_CALL;
+ } else {
+ throw new IllegalArgumentException("bad scenario: voice call not active/supported");
+ }
+ }
+
+ /**
+ * 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 SAR sensor is supported, output only dependent on device proximity */
+ if (sarInfo.sarSensorSupported) {
+ return (sarInfo.sensorState != SarInfo.SAR_SENSOR_FREE_SPACE);
+ }
+ if (sarInfo.sarSapSupported && sarInfo.isWifiSapEnabled) {
+ return true;
+ }
+ if (sarInfo.sarVoiceCallSupported && sarInfo.isVoiceCall) {
+ return true;
+ }
+ return false;
+ }
- private int frameworkToHalTxPowerScenario(int scenario) {
- switch (scenario) {
- case WifiNative.TX_POWER_SCENARIO_VOICE_CALL:
+ /**
+ * 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 supported in this device, but SoftAP is,
+ * we make these assumptions:
+ * - All voice calls are treated as if device is near the head.
+ * - SoftAP scenario is treated as if device is near the body.
+ * In case neither SAR sensor, nor SoftAP is supported, 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.sarSensorSupported) {
+ switch(sarInfo.sensorState) {
+ case SarInfo.SAR_SENSOR_NEAR_BODY:
+ case SarInfo.SAR_SENSOR_NEAR_HAND:
+ if (sarInfo.isVoiceCall || sarInfo.isWifiSapEnabled) {
+ 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.isVoiceCall || sarInfo.isWifiSapEnabled) {
+ 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 if (sarInfo.sarSapSupported && sarInfo.sarVoiceCallSupported) {
+ if (sarInfo.isVoiceCall) {
+ return android.hardware.wifi.V1_2.IWifiChip
+ .TxPowerScenario.ON_HEAD_CELL_ON;
+ } else if (sarInfo.isWifiSapEnabled) {
+ return android.hardware.wifi.V1_2.IWifiChip
+ .TxPowerScenario.ON_BODY_CELL_ON;
+ } else {
+ throw new IllegalArgumentException("bad scenario: no voice call/softAP active");
+ }
+ } else if (sarInfo.sarVoiceCallSupported) {
+ /* SAR Sensors and SoftAP not supported, act like V1_1 */
+ if (sarInfo.isVoiceCall) {
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");
+ }
+ } else {
+ throw new IllegalArgumentException("Invalid case: voice call not supported");
}
}
@@ -2667,35 +2777,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.d("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.d("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/service/java/com/android/server/wifi/hotspot2/PasspointManager.java b/service/java/com/android/server/wifi/hotspot2/PasspointManager.java
index a0915fa52..4c2937cb5 100644
--- a/service/java/com/android/server/wifi/hotspot2/PasspointManager.java
+++ b/service/java/com/android/server/wifi/hotspot2/PasspointManager.java
@@ -656,6 +656,7 @@ public class PasspointManager {
numConnectedProviders++;
}
}
+ mWifiMetrics.updateSavedPasspointProfilesInfo(mProviders);
mWifiMetrics.updateSavedPasspointProfiles(numProviders, numConnectedProviders);
}
diff --git a/service/java/com/android/server/wifi/rtt/RttMetrics.java b/service/java/com/android/server/wifi/rtt/RttMetrics.java
index c1bec8f97..ecc1c4812 100644
--- a/service/java/com/android/server/wifi/rtt/RttMetrics.java
+++ b/service/java/com/android/server/wifi/rtt/RttMetrics.java
@@ -116,6 +116,7 @@ public class RttMetrics {
return "numCalls=" + numCalls + ", numIndividualCalls=" + numIndividualCalls
+ ", perUidInfo=" + perUidInfo + ", numRequestsHistogram="
+ numRequestsHistogram + ", requestGapHistogram=" + requestGapHistogram
+ + ", statusHistogram=" + statusHistogram
+ ", measuredDistanceHistogram=" + measuredDistanceHistogram;
}
}
diff --git a/service/java/com/android/server/wifi/rtt/RttNative.java b/service/java/com/android/server/wifi/rtt/RttNative.java
index accd1a2f8..34fd2e3e7 100644
--- a/service/java/com/android/server/wifi/rtt/RttNative.java
+++ b/service/java/com/android/server/wifi/rtt/RttNative.java
@@ -166,6 +166,11 @@ public class RttNative extends IWifiRttControllerEventCallback.Stub {
*/
public boolean rangeRequest(int cmdId, RangingRequest request,
boolean isCalledFromPrivilegedContext) {
+ return rangeRequestInternal(cmdId, request, isCalledFromPrivilegedContext, true);
+ }
+
+ private boolean rangeRequestInternal(int cmdId, RangingRequest request,
+ boolean isCalledFromPrivilegedContext, boolean tryToReinitIfNecessary) {
if (mDbg) {
Log.v(TAG,
"rangeRequest: cmdId=" + cmdId + ", # of requests=" + request.mRttPeers.size());
@@ -175,6 +180,11 @@ public class RttNative extends IWifiRttControllerEventCallback.Stub {
synchronized (mLock) {
if (!isReady()) {
Log.e(TAG, "rangeRequest: RttController is null");
+ if (tryToReinitIfNecessary) {
+ updateController();
+ return rangeRequestInternal(cmdId, request, isCalledFromPrivilegedContext,
+ false);
+ }
return false;
}
@@ -192,6 +202,14 @@ public class RttNative extends IWifiRttControllerEventCallback.Stub {
try {
WifiStatus status = mIWifiRttController.rangeRequest(cmdId, rttConfig);
+ if (status.code == WifiStatusCode.ERROR_WIFI_RTT_CONTROLLER_INVALID
+ && tryToReinitIfNecessary) {
+ Log.d(TAG, "rangeRequest: RTT controller invalidated from under us - reinit!");
+ mIWifiRttController = null;
+ updateController();
+ return rangeRequestInternal(cmdId, request, isCalledFromPrivilegedContext,
+ false);
+ }
if (status.code != WifiStatusCode.SUCCESS) {
Log.e(TAG, "rangeRequest: cannot issue range request -- code=" + status.code);
return false;
diff --git a/tests/wifitests/src/com/android/server/wifi/MockResources.java b/tests/wifitests/src/com/android/server/wifi/MockResources.java
index ab40c6f8d..1a061e22a 100644
--- a/tests/wifitests/src/com/android/server/wifi/MockResources.java
+++ b/tests/wifitests/src/com/android/server/wifi/MockResources.java
@@ -23,11 +23,13 @@ public class MockResources extends android.test.mock.MockResources {
private HashMap<Integer, Boolean> mBooleanValues;
private HashMap<Integer, Integer> mIntegerValues;
private HashMap<Integer, String> mStringValues;
+ private HashMap<Integer, CharSequence> mTextValues;
public MockResources() {
mBooleanValues = new HashMap<Integer, Boolean>();
mIntegerValues = new HashMap<Integer, Integer>();
mStringValues = new HashMap<Integer, String>();
+ mTextValues = new HashMap<Integer, CharSequence>();
}
@Override
@@ -57,6 +59,15 @@ public class MockResources extends android.test.mock.MockResources {
}
}
+ @Override
+ public CharSequence getText(int id) {
+ if (mTextValues.containsKey(id)) {
+ return mTextValues.get(id);
+ } else {
+ return null;
+ }
+ }
+
public void setBoolean(int id, boolean value) {
mBooleanValues.put(id, value);
}
@@ -68,4 +79,8 @@ public class MockResources extends android.test.mock.MockResources {
public void setString(int id, String value) {
mStringValues.put(id, value);
}
+
+ public void setText(int id, CharSequence value) {
+ mTextValues.put(id, value);
+ }
}
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..2bf1f3ee4
--- /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();
+ }
+
+ @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.isWifiClientEnabled = 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.sensorState = 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.isWifiSapEnabled = true;
+ assertTrue(mSarInfo.shouldReport());
+ mSarInfo.reportingSuccessful();
+
+ mSarInfo.sensorState = 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.isWifiScanOnlyEnabled = true;
+ mSarInfo.sensorState = 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.isWifiClientEnabled = true;
+ mSarInfo.sensorState = SarInfo.SAR_SENSOR_NEAR_HEAD;
+ assertTrue(mSarInfo.shouldReport());
+ mSarInfo.reportingSuccessful();
+
+ mSarInfo.sensorState = SarInfo.SAR_SENSOR_NEAR_BODY;
+ assertTrue(mSarInfo.shouldReport());
+ mSarInfo.reportingSuccessful();
+
+ mSarInfo.sensorState = 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.sensorState = SarInfo.SAR_SENSOR_NEAR_HEAD;
+ assertFalse(mSarInfo.shouldReport());
+
+ mSarInfo.isWifiClientEnabled = 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.isWifiClientEnabled = true;
+ assertTrue(mSarInfo.shouldReport());
+ mSarInfo.reportingSuccessful();
+
+ mSarInfo.isVoiceCall = 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.isWifiClientEnabled = true;
+ assertTrue(mSarInfo.shouldReport());
+ mSarInfo.reportingSuccessful();
+
+ mSarInfo.isWifiSapEnabled = 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.isWifiClientEnabled = true;
+ mSarInfo.sensorState = 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.isWifiClientEnabled = true;
+ mSarInfo.sensorState = SarInfo.SAR_SENSOR_NEAR_HEAD;
+ assertTrue(mSarInfo.shouldReport());
+ mSarInfo.reportingSuccessful();
+
+ /* Changing the sensor state and fail to report */
+ mSarInfo.sensorState = SarInfo.SAR_SENSOR_NEAR_BODY;
+ assertTrue(mSarInfo.shouldReport());
+
+ /* Changing the sensor back to the same value as last reported */
+ mSarInfo.sensorState = 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..0cf9dd3f2 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,82 @@ 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 isSarSapEnabled,
+ boolean isSarSensorEnabled) {
+ mResources.setBoolean(
+ R.bool.config_wifi_framework_enable_sar_tx_power_limit, isSarEnabled);
+ mResources.setBoolean(
+ R.bool.config_wifi_framework_enable_soft_ap_sar_tx_power_limit,
+ isSarSapEnabled);
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,19 +203,90 @@ 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 */
+ enableDebugLogs();
+ }
+
+ /**
+ * 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_soft_ap_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, false);
verify(mTelephonyManager).listen(any(), eq(PhoneStateListener.LISTEN_CALL_STATE));
}
@@ -144,7 +296,7 @@ public class SarManagerTest {
*/
@Test
public void testSarMgr_disabledTxPowerScenario_registerPhone() throws Exception {
- createSarManager(false);
+ createSarManager(false, false, false);
verify(mTelephonyManager, never()).listen(any(), anyInt());
}
@@ -153,27 +305,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, 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.isVoiceCall);
/* 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.isVoiceCall);
}
/**
@@ -181,66 +330,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, 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.isVoiceCall);
}
/**
* 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, 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.isVoiceCall);
/* 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.isVoiceCall);
/* 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.isVoiceCall);
+
+ /* 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, false);
InOrder inOrder = inOrder(mWifiNative);
@@ -251,6 +404,635 @@ 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, 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.isVoiceCall);
+
+ /* Set phone state to OFFHOOK */
+ mPhoneStateListener.onCallStateChanged(CALL_STATE_OFFHOOK, "");
+ inOrder.verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertTrue(mSarInfo.isVoiceCall);
+
+ /* 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.isVoiceCall);
+ }
+
+ /**
+ * 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, 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.isVoiceCall);
+ }
+
+ /**
+ * 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, 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.isVoiceCall);
+
+ /* 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, 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.isVoiceCall);
+
+ /* Set phone state to OFFHOOK */
+ mPhoneStateListener.onCallStateChanged(CALL_STATE_OFFHOOK, "");
+ inOrder.verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertTrue(mSarInfo.isVoiceCall);
+
+ /* Set state back to ONHOOK */
+ mPhoneStateListener.onCallStateChanged(CALL_STATE_IDLE, "");
+ inOrder.verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertFalse(mSarInfo.isVoiceCall);
+ }
+
+ /**
+ * 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, 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.sensorState);
+
+ /* Sensor event */
+ sendSensorEvent(SAR_SENSOR_EVENT_BODY);
+ inOrder.verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertEquals(SarInfo.SAR_SENSOR_NEAR_BODY, mSarInfo.sensorState);
+ assertFalse(mSarInfo.isVoiceCall);
+
+ /* Sensor event */
+ sendSensorEvent(SAR_SENSOR_EVENT_HEAD);
+ inOrder.verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertEquals(SarInfo.SAR_SENSOR_NEAR_HEAD, mSarInfo.sensorState);
+ assertFalse(mSarInfo.isVoiceCall);
+
+ /* Sensor event */
+ sendSensorEvent(SAR_SENSOR_EVENT_HAND);
+ inOrder.verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertEquals(SarInfo.SAR_SENSOR_NEAR_HAND, mSarInfo.sensorState);
+ assertFalse(mSarInfo.isVoiceCall);
+
+ /* Sensor event */
+ sendSensorEvent(SAR_SENSOR_EVENT_FREE_SPACE);
+ inOrder.verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertEquals(SarInfo.SAR_SENSOR_FREE_SPACE, mSarInfo.sensorState);
+ assertFalse(mSarInfo.isVoiceCall);
+ }
+
+ /**
+ * 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, 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.sensorState);
+ assertFalse(mSarInfo.isVoiceCall);
+
+ /* Start a Cell call */
+ mPhoneStateListener.onCallStateChanged(CALL_STATE_OFFHOOK, "");
+ inOrder.verify(mWifiNative).selectTxPowerScenario(any(SarInfo.class));
+ assertEquals(SarInfo.SAR_SENSOR_FREE_SPACE, mSarInfo.sensorState);
+ assertTrue(mSarInfo.isVoiceCall);
+
+ /* Sensor event */
+ sendSensorEvent(SAR_SENSOR_EVENT_BODY);
+ inOrder.verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertEquals(SarInfo.SAR_SENSOR_NEAR_BODY, mSarInfo.sensorState);
+ assertTrue(mSarInfo.isVoiceCall);
+
+ /* Sensor event */
+ sendSensorEvent(SAR_SENSOR_EVENT_HEAD);
+ inOrder.verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertEquals(SarInfo.SAR_SENSOR_NEAR_HEAD, mSarInfo.sensorState);
+ assertTrue(mSarInfo.isVoiceCall);
+
+ /* Sensor event */
+ sendSensorEvent(SAR_SENSOR_EVENT_HAND);
+ inOrder.verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertEquals(SarInfo.SAR_SENSOR_NEAR_HAND, mSarInfo.sensorState);
+ assertTrue(mSarInfo.isVoiceCall);
+
+ /* Sensor event */
+ sendSensorEvent(SAR_SENSOR_EVENT_FREE_SPACE);
+ inOrder.verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertEquals(SarInfo.SAR_SENSOR_FREE_SPACE, mSarInfo.sensorState);
+ assertTrue(mSarInfo.isVoiceCall);
+ }
+
+ /**
+ * 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, 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.sensorState);
+ assertFalse(mSarInfo.isVoiceCall);
+
+ /* Sensor event */
+ sendSensorEvent(SAR_SENSOR_EVENT_HEAD);
+ inOrder.verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertEquals(SarInfo.SAR_SENSOR_NEAR_HEAD, mSarInfo.sensorState);
+ assertFalse(mSarInfo.isVoiceCall);
+
+
+ /* Start a Cell call */
+ mPhoneStateListener.onCallStateChanged(CALL_STATE_OFFHOOK, "");
+ inOrder.verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertEquals(SarInfo.SAR_SENSOR_NEAR_HEAD, mSarInfo.sensorState);
+ assertTrue(mSarInfo.isVoiceCall);
+
+ /* End a Cell call */
+ mPhoneStateListener.onCallStateChanged(CALL_STATE_IDLE, "");
+ inOrder.verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertEquals(SarInfo.SAR_SENSOR_NEAR_HEAD, mSarInfo.sensorState);
+ assertFalse(mSarInfo.isVoiceCall);
+ }
+
+ /**
+ * 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, 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.sensorState);
+ assertFalse(mSarInfo.isVoiceCall);
+ }
+
+ /**
+ * 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.sensorState);
+ assertFalse(mSarInfo.isVoiceCall);
+
+ /* Start a Cell Call */
+ mPhoneStateListener.onCallStateChanged(CALL_STATE_OFFHOOK, "");
+ inOrder.verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertEquals(SarInfo.SAR_SENSOR_NEAR_HEAD, mSarInfo.sensorState);
+ assertTrue(mSarInfo.isVoiceCall);
+
+ /* End the call */
+ mPhoneStateListener.onCallStateChanged(CALL_STATE_IDLE, "");
+ inOrder.verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertEquals(SarInfo.SAR_SENSOR_NEAR_HEAD, mSarInfo.sensorState);
+ assertFalse(mSarInfo.isVoiceCall);
+ }
+
+ /**
+ * 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.sensorState);
+ assertFalse(mSarInfo.isVoiceCall);
+
+ /* Start a Cell Call */
+ mPhoneStateListener.onCallStateChanged(CALL_STATE_OFFHOOK, "");
+ inOrder.verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertEquals(SarInfo.SAR_SENSOR_NEAR_HEAD, mSarInfo.sensorState);
+ assertTrue(mSarInfo.isVoiceCall);
+
+ /* End the call */
+ mPhoneStateListener.onCallStateChanged(CALL_STATE_IDLE, "");
+ inOrder.verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertEquals(SarInfo.SAR_SENSOR_NEAR_HEAD, mSarInfo.sensorState);
+ assertFalse(mSarInfo.isVoiceCall);
+ }
+
+ /**
+ * 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.sensorState);
+ assertFalse(mSarInfo.isVoiceCall);
+
+ /* Start a Cell Call */
+ mPhoneStateListener.onCallStateChanged(CALL_STATE_OFFHOOK, "");
+ inOrder.verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertEquals(SarInfo.SAR_SENSOR_NEAR_HEAD, mSarInfo.sensorState);
+ assertTrue(mSarInfo.isVoiceCall);
+
+ /* End the call */
+ mPhoneStateListener.onCallStateChanged(CALL_STATE_IDLE, "");
+ inOrder.verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertEquals(SarInfo.SAR_SENSOR_NEAR_HEAD, mSarInfo.sensorState);
+ assertFalse(mSarInfo.isVoiceCall);
+ }
+
+ /**
+ * 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, 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, 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.isVoiceCall);
+ assertTrue(mSarInfo.isWifiSapEnabled);
+ assertFalse(mSarInfo.isWifiScanOnlyEnabled);
+ }
+
+ /**
+ * 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, 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.sensorState);
+ assertFalse(mSarInfo.isWifiSapEnabled);
+
+ /* Enable WiFi SoftAP State */
+ mSarMgr.setSapWifiState(WifiManager.WIFI_AP_STATE_ENABLED);
+ inOrder.verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertEquals(SarInfo.SAR_SENSOR_NEAR_HEAD, mSarInfo.sensorState);
+ assertTrue(mSarInfo.isWifiSapEnabled);
+
+ /* Disable Wifi SoftAP state */
+ mSarMgr.setSapWifiState(WifiManager.WIFI_AP_STATE_DISABLED);
+ inOrder.verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertEquals(SarInfo.SAR_SENSOR_NEAR_HEAD, mSarInfo.sensorState);
+ assertFalse(mSarInfo.isWifiSapEnabled);
+ }
+
+ /**
+ * 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, 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.sensorState);
+ assertTrue(mSarInfo.isWifiSapEnabled);
+
+ /* 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.sensorState);
+ assertFalse(mSarInfo.isWifiSapEnabled);
+ }
+
+ /**
+ * 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, false);
+
+ /* Enable Wifi ScanOnly State */
+ mSarMgr.setScanOnlyWifiState(WifiManager.WIFI_STATE_ENABLED);
+ captureSarInfo(mWifiNative);
+
+ verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertFalse(mSarInfo.isWifiSapEnabled);
+ assertTrue(mSarInfo.isWifiScanOnlyEnabled);
+ }
+
+ /**
+ * 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, 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.isWifiSapEnabled);
+ assertTrue(mSarInfo.isWifiScanOnlyEnabled);
+
+ /* 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, false);
+
+ InOrder inOrder = inOrder(mWifiNative);
+
+ /* Enable WiFi State */
+ mSarMgr.setClientWifiState(WifiManager.WIFI_STATE_ENABLED);
+ captureSarInfo(mWifiNative);
+
+ inOrder.verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertFalse(mSarInfo.isVoiceCall);
+ assertFalse(mSarInfo.isWifiSapEnabled);
+ assertFalse(mSarInfo.isWifiScanOnlyEnabled);
+
+ /* Enable SoftAP state */
+ mSarMgr.setSapWifiState(WifiManager.WIFI_AP_STATE_ENABLED);
+ inOrder.verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertFalse(mSarInfo.isVoiceCall);
+ assertTrue(mSarInfo.isWifiSapEnabled);
+ assertFalse(mSarInfo.isWifiScanOnlyEnabled);
+
+ /* 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.isVoiceCall);
+ assertFalse(mSarInfo.isWifiSapEnabled);
+ assertTrue(mSarInfo.isWifiScanOnlyEnabled);
+ }
+
+ /**
+ * 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, 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.isVoiceCall);
+ assertFalse(mSarInfo.isWifiSapEnabled);
+ assertFalse(mSarInfo.isWifiScanOnlyEnabled);
+
+ /* Enable SoftAP state */
+ mSarMgr.setSapWifiState(WifiManager.WIFI_AP_STATE_ENABLED);
+ inOrder.verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertFalse(mSarInfo.isVoiceCall);
+ assertTrue(mSarInfo.isWifiSapEnabled);
+ assertFalse(mSarInfo.isWifiScanOnlyEnabled);
+
+ /* Disable WiFi State, reporting should still happen */
+ mSarMgr.setClientWifiState(WifiManager.WIFI_STATE_DISABLED);
+ inOrder.verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertFalse(mSarInfo.isVoiceCall);
+ assertTrue(mSarInfo.isWifiSapEnabled);
+ assertFalse(mSarInfo.isWifiScanOnlyEnabled);
+ assertFalse(mSarInfo.isWifiClientEnabled);
+
+ /* Enable ScanOnly state */
+ mSarMgr.setScanOnlyWifiState(WifiManager.WIFI_STATE_ENABLED);
+ inOrder.verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertFalse(mSarInfo.isVoiceCall);
+ assertTrue(mSarInfo.isWifiSapEnabled);
+ assertTrue(mSarInfo.isWifiScanOnlyEnabled);
+ assertFalse(mSarInfo.isWifiClientEnabled);
+
+ /* Disable SoftAP state */
+ mSarMgr.setSapWifiState(WifiManager.WIFI_AP_STATE_DISABLED);
+ inOrder.verify(mWifiNative).selectTxPowerScenario(eq(mSarInfo));
+ assertFalse(mSarInfo.isVoiceCall);
+ assertFalse(mSarInfo.isWifiSapEnabled);
+ assertTrue(mSarInfo.isWifiScanOnlyEnabled);
+ assertFalse(mSarInfo.isWifiClientEnabled);
}
}
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..21c3797b3 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 =
@@ -113,6 +114,9 @@ public class SoftApManagerTest {
when(mContext.getResources()).thenReturn(mResources);
when(mResources.getInteger(R.integer.config_wifi_framework_soft_ap_timeout_delay))
.thenReturn(600000);
+ when(mWifiNative.setCountryCodeHal(
+ TEST_INTERFACE_NAME, TEST_COUNTRY_CODE.toUpperCase(Locale.ROOT)))
+ .thenReturn(true);
}
private WifiConfiguration createDefaultApConfig() {
@@ -121,7 +125,7 @@ public class SoftApManagerTest {
return defaultConfig;
}
- private SoftApManager createSoftApManager(SoftApModeConfiguration config) throws Exception {
+ private SoftApManager createSoftApManager(SoftApModeConfiguration config, String countryCode) {
if (config.getWifiConfiguration() == null) {
when(mWifiApConfigStore.getApConfiguration()).thenReturn(mDefaultApConfig);
}
@@ -129,11 +133,12 @@ public class SoftApManagerTest {
mLooper.getLooper(),
mFrameworkFacade,
mWifiNative,
- TEST_COUNTRY_CODE,
+ countryCode,
mCallback,
mWifiApConfigStore,
config,
- mWifiMetrics);
+ mWifiMetrics,
+ mSarManager);
mLooper.dispatchAll();
return newSoftApManager;
@@ -205,7 +210,8 @@ public class SoftApManagerTest {
mCallback,
mWifiApConfigStore,
nullApConfig,
- mWifiMetrics);
+ mWifiMetrics,
+ mSarManager);
mLooper.dispatchAll();
newSoftApManager.start();
mLooper.dispatchAll();
@@ -247,7 +253,8 @@ public class SoftApManagerTest {
mCallback,
mWifiApConfigStore,
nullApConfig,
- mWifiMetrics);
+ mWifiMetrics,
+ mSarManager);
mLooper.dispatchAll();
newSoftApManager.start();
mLooper.dispatchAll();
@@ -288,7 +295,8 @@ public class SoftApManagerTest {
mCallback,
mWifiApConfigStore,
nullApConfig,
- mWifiMetrics);
+ mWifiMetrics,
+ mSarManager);
mLooper.dispatchAll();
newSoftApManager.start();
mLooper.dispatchAll();
@@ -307,11 +315,54 @@ public class SoftApManagerTest {
}
/**
+ * Tests that the generic error is propagated and properly reported when starting softap and no
+ * country code is provided.
+ */
+ @Test
+ public void startSoftApOn5GhzFailGeneralErrorForNoCountryCode() throws Exception {
+ WifiConfiguration config = new WifiConfiguration();
+ config.apBand = WifiConfiguration.AP_BAND_5GHZ;
+ config.SSID = TEST_SSID;
+ SoftApModeConfiguration softApConfig =
+ new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, config);
+
+ when(mWifiNative.setupInterfaceForSoftApMode(any())).thenReturn(TEST_INTERFACE_NAME);
+
+ SoftApManager newSoftApManager = new SoftApManager(mContext,
+ mLooper.getLooper(),
+ mFrameworkFacade,
+ mWifiNative,
+ null,
+ mCallback,
+ mWifiApConfigStore,
+ softApConfig,
+ mWifiMetrics,
+ mSarManager);
+ mLooper.dispatchAll();
+ newSoftApManager.start();
+ mLooper.dispatchAll();
+
+ verify(mWifiNative, never()).setCountryCodeHal(eq(TEST_INTERFACE_NAME), any());
+
+ ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
+ verify(mContext, times(2)).sendStickyBroadcastAsUser(intentCaptor.capture(),
+ eq(UserHandle.ALL));
+
+ List<Intent> capturedIntents = intentCaptor.getAllValues();
+ checkApStateChangedBroadcast(capturedIntents.get(0), WIFI_AP_STATE_ENABLING,
+ WIFI_AP_STATE_DISABLED, HOTSPOT_NO_ERROR, TEST_INTERFACE_NAME,
+ softApConfig.getTargetMode());
+ checkApStateChangedBroadcast(capturedIntents.get(1), WIFI_AP_STATE_FAILED,
+ WIFI_AP_STATE_ENABLING, WifiManager.SAP_START_FAILURE_GENERAL, TEST_INTERFACE_NAME,
+ softApConfig.getTargetMode());
+ }
+
+ /**
* Tests that the generic error is propagated and properly reported when starting softap and the
- * specified channel cannot be used.
+ * country code cannot be set.
*/
@Test
- public void startSoftApFailGeneralErrorForConfigChannel() throws Exception {
+ public void startSoftApOn5GhzFailGeneralErrorForCountryCodeSetFailure() throws Exception {
WifiConfiguration config = new WifiConfiguration();
config.apBand = WifiConfiguration.AP_BAND_5GHZ;
config.SSID = TEST_SSID;
@@ -319,21 +370,27 @@ public class SoftApManagerTest {
new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, config);
when(mWifiNative.setupInterfaceForSoftApMode(any())).thenReturn(TEST_INTERFACE_NAME);
- when(mWifiNative.setCountryCodeHal(eq(TEST_INTERFACE_NAME), any())).thenReturn(false);
+ when(mWifiNative.setCountryCodeHal(
+ TEST_INTERFACE_NAME, TEST_COUNTRY_CODE.toUpperCase(Locale.ROOT)))
+ .thenReturn(false);
SoftApManager newSoftApManager = new SoftApManager(mContext,
mLooper.getLooper(),
mFrameworkFacade,
mWifiNative,
- "US",
+ TEST_COUNTRY_CODE,
mCallback,
mWifiApConfigStore,
softApConfig,
- mWifiMetrics);
+ mWifiMetrics,
+ mSarManager);
mLooper.dispatchAll();
newSoftApManager.start();
mLooper.dispatchAll();
+ verify(mWifiNative).setCountryCodeHal(
+ TEST_INTERFACE_NAME, TEST_COUNTRY_CODE.toUpperCase(Locale.ROOT));
+
ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
verify(mContext, times(2)).sendStickyBroadcastAsUser(intentCaptor.capture(),
eq(UserHandle.ALL));
@@ -348,6 +405,76 @@ public class SoftApManagerTest {
}
/**
+ * Tests that there is no failure in starting softap in 2Ghz band when no country code is
+ * provided.
+ */
+ @Test
+ public void startSoftApOn24GhzNoFailForNoCountryCode() throws Exception {
+ WifiConfiguration config = new WifiConfiguration();
+ config.apBand = WifiConfiguration.AP_BAND_2GHZ;
+ config.SSID = TEST_SSID;
+ SoftApModeConfiguration softApConfig =
+ new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, config);
+
+ startSoftApAndVerifyEnabled(softApConfig, null);
+ verify(mWifiNative, never()).setCountryCodeHal(eq(TEST_INTERFACE_NAME), any());
+ }
+
+ /**
+ * Tests that there is no failure in starting softap in ANY band when no country code is
+ * provided.
+ */
+ @Test
+ public void startSoftApOnAnyGhzNoFailForNoCountryCode() throws Exception {
+ WifiConfiguration config = new WifiConfiguration();
+ config.apBand = WifiConfiguration.AP_BAND_ANY;
+ config.SSID = TEST_SSID;
+ SoftApModeConfiguration softApConfig =
+ new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, config);
+
+ startSoftApAndVerifyEnabled(softApConfig, null);
+ verify(mWifiNative, never()).setCountryCodeHal(eq(TEST_INTERFACE_NAME), any());
+ }
+
+ /**
+ * Tests that there is no failure in starting softap in 2Ghz band when country code cannot be
+ * set.
+ */
+ @Test
+ public void startSoftApOn2GhzNoFailForCountryCodeSetFailure() throws Exception {
+ WifiConfiguration config = new WifiConfiguration();
+ config.apBand = WifiConfiguration.AP_BAND_2GHZ;
+ config.SSID = TEST_SSID;
+ SoftApModeConfiguration softApConfig =
+ new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, config);
+
+ when(mWifiNative.setCountryCodeHal(eq(TEST_INTERFACE_NAME), any())).thenReturn(false);
+
+ startSoftApAndVerifyEnabled(softApConfig, TEST_COUNTRY_CODE);
+ verify(mWifiNative).setCountryCodeHal(
+ TEST_INTERFACE_NAME, TEST_COUNTRY_CODE.toUpperCase(Locale.ROOT));
+ }
+
+ /**
+ * Tests that there is no failure in starting softap in ANY band when country code cannot be
+ * set.
+ */
+ @Test
+ public void startSoftApOnAnyNoFailForCountryCodeSetFailure() throws Exception {
+ WifiConfiguration config = new WifiConfiguration();
+ config.apBand = WifiConfiguration.AP_BAND_ANY;
+ config.SSID = TEST_SSID;
+ SoftApModeConfiguration softApConfig =
+ new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, config);
+
+ when(mWifiNative.setCountryCodeHal(eq(TEST_INTERFACE_NAME), any())).thenReturn(false);
+
+ startSoftApAndVerifyEnabled(softApConfig, TEST_COUNTRY_CODE);
+ verify(mWifiNative).setCountryCodeHal(
+ TEST_INTERFACE_NAME, TEST_COUNTRY_CODE.toUpperCase(Locale.ROOT));
+ }
+
+ /**
* Tests that the NO_CHANNEL error is propagated and properly reported when starting softap and
* a valid channel cannot be determined.
*/
@@ -371,7 +498,8 @@ public class SoftApManagerTest {
mCallback,
mWifiApConfigStore,
softApConfig,
- mWifiMetrics);
+ mWifiMetrics,
+ mSarManager);
mLooper.dispatchAll();
newSoftApManager.start();
mLooper.dispatchAll();
@@ -408,7 +536,8 @@ public class SoftApManagerTest {
mCallback,
mWifiApConfigStore,
softApModeConfig,
- mWifiMetrics);
+ mWifiMetrics,
+ mSarManager);
mLooper.dispatchAll();
newSoftApManager.start();
@@ -424,11 +553,13 @@ public class SoftApManagerTest {
@Test
public void stopWhenNotStarted() throws Exception {
mSoftApManager = createSoftApManager(
- new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null));
+ new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null),
+ TEST_COUNTRY_CODE);
mSoftApManager.stop();
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 +590,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,
@@ -901,14 +1033,16 @@ public class SoftApManagerTest {
/** Starts soft AP and verifies that it is enabled successfully. */
protected void startSoftApAndVerifyEnabled(
SoftApModeConfiguration softApConfig) throws Exception {
+ startSoftApAndVerifyEnabled(softApConfig, TEST_COUNTRY_CODE);
+ }
+
+ /** Starts soft AP and verifies that it is enabled successfully. */
+ protected void startSoftApAndVerifyEnabled(
+ SoftApModeConfiguration softApConfig, String countryCode) throws Exception {
WifiConfiguration expectedConfig;
InOrder order = inOrder(mCallback, mWifiNative);
- when(mWifiNative.setCountryCodeHal(
- TEST_INTERFACE_NAME, TEST_COUNTRY_CODE.toUpperCase(Locale.ROOT)))
- .thenReturn(true);
-
- mSoftApManager = createSoftApManager(softApConfig);
+ mSoftApManager = createSoftApManager(softApConfig, countryCode);
WifiConfiguration config = softApConfig.getWifiConfiguration();
if (config == null) {
when(mWifiApConfigStore.getApConfiguration()).thenReturn(mDefaultApConfig);
@@ -938,6 +1072,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/WifiApConfigStoreTest.java b/tests/wifitests/src/com/android/server/wifi/WifiApConfigStoreTest.java
index 1672dca58..88312ce4c 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiApConfigStoreTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiApConfigStoreTest.java
@@ -19,25 +19,38 @@ package com.android.server.wifi;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.content.BroadcastReceiver;
import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiConfiguration.KeyMgmt;
+import android.os.Build;
+import android.os.test.TestLooper;
import android.support.test.filters.SmallTest;
import com.android.internal.R;
+import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.io.File;
import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Random;
/**
@@ -54,19 +67,34 @@ public class WifiApConfigStoreTest {
private static final String TEST_CONFIGURED_AP_SSID = "ConfiguredAP";
private static final String TEST_DEFAULT_HOTSPOT_SSID = "TestShare";
private static final String TEST_DEFAULT_HOTSPOT_PSK = "TestPassword";
+ private static final String TEST_APCONFIG_CHANGE_NOTIFICATION_TITLE = "Notification title";
+ private static final String TEST_APCONFIG_CHANGE_NOTIFICATION_SUMMARY = "Notification summary";
+ private static final String TEST_APCONFIG_CHANGE_NOTIFICATION_DETAILED =
+ "Notification detailed";
private static final int RAND_SSID_INT_MIN = 1000;
private static final int RAND_SSID_INT_MAX = 9999;
private static final String TEST_CHAR_SET_AS_STRING = "abcdefghijklmnopqrstuvwxyz0123456789";
- @Mock Context mContext;
- @Mock BackupManagerProxy mBackupManagerProxy;
- File mApConfigFile;
- Random mRandom;
- MockResources mResources;
+ @Mock private Context mContext;
+ private TestLooper mLooper;
+ @Mock private BackupManagerProxy mBackupManagerProxy;
+ @Mock private FrameworkFacade mFrameworkFacade;
+ private File mApConfigFile;
+ private Random mRandom;
+ private MockResources mResources;
+ @Mock private ApplicationInfo mMockApplInfo;
+ private BroadcastReceiver mBroadcastReceiver;
+ @Mock private NotificationManager mNotificationManager;
+ private ArrayList<Integer> mKnownGood2GChannelList;
@Before
public void setUp() throws Exception {
+ mLooper = new TestLooper();
MockitoAnnotations.initMocks(this);
+ when(mContext.getSystemService(Context.NOTIFICATION_SERVICE))
+ .thenReturn(mNotificationManager);
+ mMockApplInfo.targetSdkVersion = Build.VERSION_CODES.P;
+ when(mContext.getApplicationInfo()).thenReturn(mMockApplInfo);
/* Create a temporary file for AP config file storage. */
mApConfigFile = File.createTempFile(TEST_AP_CONFIG_FILE_PREFIX, "");
@@ -74,15 +102,24 @@ public class WifiApConfigStoreTest {
/* Setup expectations for Resources to return some default settings. */
mResources = new MockResources();
mResources.setString(R.string.config_wifi_framework_sap_2G_channel_list,
- TEST_DEFAULT_2G_CHANNEL_LIST);
+ TEST_DEFAULT_2G_CHANNEL_LIST);
mResources.setString(R.string.wifi_tether_configure_ssid_default,
- TEST_DEFAULT_AP_SSID);
+ TEST_DEFAULT_AP_SSID);
mResources.setString(R.string.wifi_localhotspot_configure_ssid_default,
- TEST_DEFAULT_HOTSPOT_SSID);
+ TEST_DEFAULT_HOTSPOT_SSID);
/* Default to device that does not require ap band conversion */
mResources.setBoolean(R.bool.config_wifi_convert_apband_5ghz_to_any, false);
+ mResources.setText(R.string.wifi_softap_config_change,
+ TEST_APCONFIG_CHANGE_NOTIFICATION_TITLE);
+ mResources.setText(R.string.wifi_softap_config_change_summary,
+ TEST_APCONFIG_CHANGE_NOTIFICATION_SUMMARY);
+ mResources.setText(R.string.wifi_softap_config_change_detailed,
+ TEST_APCONFIG_CHANGE_NOTIFICATION_DETAILED);
when(mContext.getResources()).thenReturn(mResources);
+ // build the known good 2G channel list: TEST_DEFAULT_2G_CHANNEL_LIST
+ mKnownGood2GChannelList = new ArrayList(Arrays.asList(1, 2, 3, 4, 5, 6));
+
mRandom = new Random();
}
@@ -93,6 +130,22 @@ public class WifiApConfigStoreTest {
}
/**
+ * Helper method to create and verify actions for the ApConfigStore used in the following tests.
+ */
+ private WifiApConfigStore createWifiApConfigStore() {
+ WifiApConfigStore store = new WifiApConfigStore(
+ mContext, mLooper.getLooper(), mBackupManagerProxy, mFrameworkFacade,
+ mApConfigFile.getPath());
+
+ ArgumentCaptor<BroadcastReceiver> broadcastReceiverCaptor =
+ ArgumentCaptor.forClass(BroadcastReceiver.class);
+ verify(mContext).registerReceiver(broadcastReceiverCaptor.capture(), any(), any(), any());
+ mBroadcastReceiver = broadcastReceiverCaptor.getValue();
+
+ return store;
+ }
+
+ /**
* Generate a WifiConfiguration based on the specified parameters.
*/
private WifiConfiguration setupApConfig(
@@ -149,7 +202,8 @@ public class WifiApConfigStoreTest {
@Test
public void initWithDefaultConfiguration() throws Exception {
WifiApConfigStore store = new WifiApConfigStore(
- mContext, mBackupManagerProxy, mApConfigFile.getPath());
+ mContext, mLooper.getLooper(), mBackupManagerProxy, mFrameworkFacade,
+ mApConfigFile.getPath());
verifyDefaultApConfig(store.getApConfiguration(), TEST_DEFAULT_AP_SSID);
}
@@ -167,7 +221,8 @@ public class WifiApConfigStoreTest {
40 /* AP channel */);
writeApConfigFile(expectedConfig);
WifiApConfigStore store = new WifiApConfigStore(
- mContext, mBackupManagerProxy, mApConfigFile.getPath());
+ mContext, mLooper.getLooper(), mBackupManagerProxy, mFrameworkFacade,
+ mApConfigFile.getPath());
verifyApConfig(expectedConfig, store.getApConfiguration());
}
@@ -187,7 +242,8 @@ public class WifiApConfigStoreTest {
40 /* AP channel */);
writeApConfigFile(expectedConfig);
WifiApConfigStore store = new WifiApConfigStore(
- mContext, mBackupManagerProxy, mApConfigFile.getPath());
+ mContext, mLooper.getLooper(), mBackupManagerProxy, mFrameworkFacade,
+ mApConfigFile.getPath());
verifyApConfig(expectedConfig, store.getApConfiguration());
store.setApConfiguration(null);
@@ -202,7 +258,8 @@ public class WifiApConfigStoreTest {
public void updateApConfiguration() throws Exception {
/* Initialize WifiApConfigStore with default configuration. */
WifiApConfigStore store = new WifiApConfigStore(
- mContext, mBackupManagerProxy, mApConfigFile.getPath());
+ mContext, mLooper.getLooper(), mBackupManagerProxy, mFrameworkFacade,
+ mApConfigFile.getPath());
verifyDefaultApConfig(store.getApConfiguration(), TEST_DEFAULT_AP_SSID);
/* Update with a valid configuration. */
@@ -226,7 +283,8 @@ public class WifiApConfigStoreTest {
public void convertSingleModeDeviceAnyTo5Ghz() throws Exception {
/* Initialize WifiApConfigStore with default configuration. */
WifiApConfigStore store = new WifiApConfigStore(
- mContext, mBackupManagerProxy, mApConfigFile.getPath());
+ mContext, mLooper.getLooper(), mBackupManagerProxy, mFrameworkFacade,
+ mApConfigFile.getPath());
verifyDefaultApConfig(store.getApConfiguration(), TEST_DEFAULT_AP_SSID);
/* Update with a valid configuration. */
@@ -257,7 +315,8 @@ public class WifiApConfigStoreTest {
public void singleModeDevice5GhzNotConverted() throws Exception {
/* Initialize WifiApConfigStore with default configuration. */
WifiApConfigStore store = new WifiApConfigStore(
- mContext, mBackupManagerProxy, mApConfigFile.getPath());
+ mContext, mLooper.getLooper(), mBackupManagerProxy, mFrameworkFacade,
+ mApConfigFile.getPath());
verifyDefaultApConfig(store.getApConfiguration(), TEST_DEFAULT_AP_SSID);
/* Update with a valid configuration. */
@@ -282,7 +341,8 @@ public class WifiApConfigStoreTest {
/* Initialize WifiApConfigStore with default configuration. */
WifiApConfigStore store = new WifiApConfigStore(
- mContext, mBackupManagerProxy, mApConfigFile.getPath());
+ mContext, mLooper.getLooper(), mBackupManagerProxy, mFrameworkFacade,
+ mApConfigFile.getPath());
verifyDefaultApConfig(store.getApConfiguration(), TEST_DEFAULT_AP_SSID);
/* Update with a valid configuration. */
@@ -315,7 +375,8 @@ public class WifiApConfigStoreTest {
/* Initialize WifiApConfigStore with default configuration. */
WifiApConfigStore store = new WifiApConfigStore(
- mContext, mBackupManagerProxy, mApConfigFile.getPath());
+ mContext, mLooper.getLooper(), mBackupManagerProxy, mFrameworkFacade,
+ mApConfigFile.getPath());
verifyDefaultApConfig(store.getApConfiguration(), TEST_DEFAULT_AP_SSID);
/* Update with a valid configuration. */
@@ -353,7 +414,8 @@ public class WifiApConfigStoreTest {
writeApConfigFile(persistedConfig);
WifiApConfigStore store = new WifiApConfigStore(
- mContext, mBackupManagerProxy, mApConfigFile.getPath());
+ mContext, mLooper.getLooper(), mBackupManagerProxy, mFrameworkFacade,
+ mApConfigFile.getPath());
verifyApConfig(expectedConfig, store.getApConfiguration());
verify(mBackupManagerProxy).notifyDataChanged();
}
@@ -374,7 +436,8 @@ public class WifiApConfigStoreTest {
writeApConfigFile(persistedConfig);
WifiApConfigStore store = new WifiApConfigStore(
- mContext, mBackupManagerProxy, mApConfigFile.getPath());
+ mContext, mLooper.getLooper(), mBackupManagerProxy, mFrameworkFacade,
+ mApConfigFile.getPath());
verifyApConfig(persistedConfig, store.getApConfiguration());
verify(mBackupManagerProxy, never()).notifyDataChanged();
}
@@ -403,7 +466,8 @@ public class WifiApConfigStoreTest {
writeApConfigFile(persistedConfig);
WifiApConfigStore store = new WifiApConfigStore(
- mContext, mBackupManagerProxy, mApConfigFile.getPath());
+ mContext, mLooper.getLooper(), mBackupManagerProxy, mFrameworkFacade,
+ mApConfigFile.getPath());
verifyApConfig(expectedConfig, store.getApConfiguration());
verify(mBackupManagerProxy).notifyDataChanged();
}
@@ -426,7 +490,8 @@ public class WifiApConfigStoreTest {
writeApConfigFile(persistedConfig);
WifiApConfigStore store = new WifiApConfigStore(
- mContext, mBackupManagerProxy, mApConfigFile.getPath());
+ mContext, mLooper.getLooper(), mBackupManagerProxy, mFrameworkFacade,
+ mApConfigFile.getPath());
verifyApConfig(persistedConfig, store.getApConfiguration());
verify(mBackupManagerProxy, never()).notifyDataChanged();
}
@@ -437,7 +502,8 @@ public class WifiApConfigStoreTest {
@Test
public void getDefaultApConfigurationIsValid() {
WifiApConfigStore store = new WifiApConfigStore(
- mContext, mBackupManagerProxy, mApConfigFile.getPath());
+ mContext, mLooper.getLooper(), mBackupManagerProxy, mFrameworkFacade,
+ mApConfigFile.getPath());
WifiConfiguration config = store.getApConfiguration();
assertTrue(WifiApConfigStore.validateApWifiConfiguration(config));
}
@@ -597,4 +663,51 @@ public class WifiApConfigStoreTest {
config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
assertFalse(WifiApConfigStore.validateApWifiConfiguration(config));
}
+
+ /**
+ * Verify the default 2GHz channel list is properly returned.
+ */
+ @Test
+ public void testDefault2GHzChannelListReturned() {
+ // first build known good list
+ WifiApConfigStore store = createWifiApConfigStore();
+ ArrayList<Integer> channels = store.getAllowed2GChannel();
+
+ assertEquals(mKnownGood2GChannelList.size(), channels.size());
+ for (int channel : channels) {
+ assertTrue(mKnownGood2GChannelList.contains(channel));
+ }
+ }
+
+ /**
+ * Verify a notification is posted when triggered when the ap config was converted.
+ */
+ @Test
+ public void testNotifyUserOfApBandConversion() throws Exception {
+ WifiApConfigStore store = createWifiApConfigStore();
+ store.notifyUserOfApBandConversion(TAG);
+ // verify the notification is posted
+ ArgumentCaptor<Notification> notificationCaptor =
+ ArgumentCaptor.forClass(Notification.class);
+ verify(mNotificationManager).notify(eq(SystemMessage.NOTE_SOFTAP_CONFIG_CHANGED),
+ notificationCaptor.capture());
+ Notification notification = notificationCaptor.getValue();
+ assertEquals(TEST_APCONFIG_CHANGE_NOTIFICATION_TITLE,
+ notification.extras.getCharSequence(Notification.EXTRA_TITLE));
+ assertEquals(TEST_APCONFIG_CHANGE_NOTIFICATION_DETAILED,
+ notification.extras.getCharSequence(Notification.EXTRA_BIG_TEXT));
+ assertEquals(TEST_APCONFIG_CHANGE_NOTIFICATION_SUMMARY,
+ notification.extras.getCharSequence(Notification.EXTRA_SUMMARY_TEXT));
+ }
+
+ /**
+ * Verify the posted notification is cleared when the user interacts with it.
+ */
+ @Test
+ public void testNotificationClearedWhenContentIsTapped() throws Exception {
+ WifiApConfigStore store = createWifiApConfigStore();
+ Intent intent = new Intent(WifiApConfigStore.ACTION_HOTSPOT_CONFIG_USER_TAPPED_CONTENT);
+ mBroadcastReceiver.onReceive(mContext, intent);
+ verify(mNotificationManager).cancel(eq(SystemMessage.NOTE_SOFTAP_CONFIG_CHANGED));
+ }
}
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiMetricsTest.java b/tests/wifitests/src/com/android/server/wifi/WifiMetricsTest.java
index 2a60a1096..5646efc62 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiMetricsTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiMetricsTest.java
@@ -18,21 +18,26 @@ package com.android.server.wifi;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import android.net.NetworkAgent;
+import android.net.wifi.EAPConstants;
import android.net.wifi.ScanResult;
import android.net.wifi.SupplicantState;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
import android.net.wifi.WifiSsid;
+import android.net.wifi.hotspot2.PasspointConfiguration;
+import android.net.wifi.hotspot2.pps.Credential;
import android.os.Handler;
import android.os.test.TestLooper;
import android.support.test.filters.SmallTest;
import android.util.Base64;
import android.util.Pair;
+import android.util.SparseIntArray;
import com.android.server.wifi.aware.WifiAwareMetrics;
import com.android.server.wifi.hotspot2.NetworkDetail;
@@ -41,6 +46,7 @@ import com.android.server.wifi.hotspot2.PasspointMatch;
import com.android.server.wifi.hotspot2.PasspointProvider;
import com.android.server.wifi.nano.WifiMetricsProto;
import com.android.server.wifi.nano.WifiMetricsProto.ConnectToNetworkNotificationAndActionCount;
+import com.android.server.wifi.nano.WifiMetricsProto.PasspointProfileTypeCount;
import com.android.server.wifi.nano.WifiMetricsProto.PnoScanMetrics;
import com.android.server.wifi.nano.WifiMetricsProto.SoftApConnectedClientsEvent;
import com.android.server.wifi.nano.WifiMetricsProto.StaEvent;
@@ -58,7 +64,9 @@ import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.BitSet;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -269,12 +277,26 @@ public class WifiMetricsTest {
private static final int NUM_SOFTAP_ON_FAILURE_DUE_TO_HOSTAPD = 31;
private static final int NUM_SOFTAP_INTERFACE_DOWN = 65;
private static final int NUM_CLIENT_INTERFACE_DOWN = 12;
- private static final int NUM_PASSPOINT_PROVIDERS = 4;
+ private static final int NUM_PASSPOINT_PROVIDERS = 7;
private static final int NUM_PASSPOINT_PROVIDER_INSTALLATION = 5;
private static final int NUM_PASSPOINT_PROVIDER_INSTALL_SUCCESS = 4;
private static final int NUM_PASSPOINT_PROVIDER_UNINSTALLATION = 3;
private static final int NUM_PASSPOINT_PROVIDER_UNINSTALL_SUCCESS = 2;
private static final int NUM_PASSPOINT_PROVIDERS_SUCCESSFULLY_CONNECTED = 1;
+ private static final int NUM_EAP_SIM_TYPE = 1;
+ private static final int NUM_EAP_TTLS_TYPE = 2;
+ private static final int NUM_EAP_TLS_TYPE = 3;
+ private static final int NUM_EAP_AKA_TYPE = 4;
+ private static final int NUM_EAP_AKA_PRIME_TYPE = 5;
+ private static final SparseIntArray SAVED_PASSPOINT_PROVIDERS_TYPE = new SparseIntArray();
+ static {
+ SAVED_PASSPOINT_PROVIDERS_TYPE.put(EAPConstants.EAP_SIM, NUM_EAP_SIM_TYPE);
+ SAVED_PASSPOINT_PROVIDERS_TYPE.put(EAPConstants.EAP_TTLS, NUM_EAP_TTLS_TYPE);
+ SAVED_PASSPOINT_PROVIDERS_TYPE.put(EAPConstants.EAP_TLS, NUM_EAP_TLS_TYPE);
+ SAVED_PASSPOINT_PROVIDERS_TYPE.put(EAPConstants.EAP_AKA, NUM_EAP_AKA_TYPE);
+ SAVED_PASSPOINT_PROVIDERS_TYPE.put(EAPConstants.EAP_AKA_PRIME, NUM_EAP_AKA_PRIME_TYPE);
+ }
+
private static final int NUM_PARTIAL_SCAN_RESULTS = 73;
private static final int NUM_PNO_SCAN_ATTEMPTS = 20;
private static final int NUM_PNO_SCAN_FAILED = 5;
@@ -404,13 +426,48 @@ public class WifiMetricsTest {
return testSavedNetworks;
}
+ private PasspointProvider createMockProvider(int eapType) {
+ PasspointProvider provider = mock(PasspointProvider.class);
+ PasspointConfiguration config = new PasspointConfiguration();
+ Credential credential = new Credential();
+
+ config.setCredential(credential);
+ switch (eapType) {
+ case EAPConstants.EAP_TLS:
+ credential.setCertCredential(new Credential.CertificateCredential());
+ break;
+ case EAPConstants.EAP_TTLS:
+ credential.setUserCredential(new Credential.UserCredential());
+ break;
+ case EAPConstants.EAP_AKA:
+ case EAPConstants.EAP_AKA_PRIME:
+ case EAPConstants.EAP_SIM:
+ Credential.SimCredential simCredential = new Credential.SimCredential();
+ simCredential.setEapType(eapType);
+ credential.setSimCredential(simCredential);
+ break;
+ }
+ when(provider.getConfig()).thenReturn(config);
+ return provider;
+ }
+
/**
* Set simple metrics, increment others
*/
public void setAndIncrementMetrics() throws Exception {
+ Map<String, PasspointProvider> providers = new HashMap<>();
mWifiMetrics.updateSavedNetworks(buildSavedNetworkList());
mWifiMetrics.updateSavedPasspointProfiles(NUM_PASSPOINT_PROVIDERS,
NUM_PASSPOINT_PROVIDERS_SUCCESSFULLY_CONNECTED);
+ for (int i = 0; i < SAVED_PASSPOINT_PROVIDERS_TYPE.size(); i++) {
+ int eapType = SAVED_PASSPOINT_PROVIDERS_TYPE.keyAt(i);
+ int count = SAVED_PASSPOINT_PROVIDERS_TYPE.valueAt(i);
+ for (int j = 0; j < count; j++) {
+ providers.put(Integer.toString(eapType) + j, createMockProvider(eapType));
+ }
+ }
+ mWifiMetrics.updateSavedPasspointProfilesInfo(providers);
+
mWifiMetrics.setIsLocationEnabled(TEST_VAL_IS_LOCATION_ENABLED);
mWifiMetrics.setIsScanningAlwaysEnabled(IS_SCANNING_ALWAYS_ENABLED);
@@ -898,6 +955,28 @@ public class WifiMetricsTest {
assertEquals(NUM_CLIENT_INTERFACE_DOWN, mDecodedProto.numClientInterfaceDown);
assertEquals(NUM_SOFTAP_INTERFACE_DOWN, mDecodedProto.numSoftApInterfaceDown);
assertEquals(NUM_PASSPOINT_PROVIDERS, mDecodedProto.numPasspointProviders);
+ for (PasspointProfileTypeCount passpointProfileType : mDecodedProto
+ .installedPasspointProfileType) {
+ switch(passpointProfileType.eapMethodType) {
+ case PasspointProfileTypeCount.TYPE_EAP_AKA:
+ assertEquals(NUM_EAP_AKA_TYPE, passpointProfileType.count);
+ break;
+ case PasspointProfileTypeCount.TYPE_EAP_AKA_PRIME:
+ assertEquals(NUM_EAP_AKA_PRIME_TYPE, passpointProfileType.count);
+ break;
+ case PasspointProfileTypeCount.TYPE_EAP_SIM:
+ assertEquals(NUM_EAP_SIM_TYPE, passpointProfileType.count);
+ break;
+ case PasspointProfileTypeCount.TYPE_EAP_TLS:
+ assertEquals(NUM_EAP_TLS_TYPE, passpointProfileType.count);
+ break;
+ case PasspointProfileTypeCount.TYPE_EAP_TTLS:
+ assertEquals(NUM_EAP_TTLS_TYPE, passpointProfileType.count);
+ break;
+ default:
+ fail("unknown type counted");
+ }
+ }
assertEquals(NUM_PASSPOINT_PROVIDER_INSTALLATION,
mDecodedProto.numPasspointProviderInstallation);
assertEquals(NUM_PASSPOINT_PROVIDER_INSTALL_SUCCESS,
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiNativeTest.java b/tests/wifitests/src/com/android/server/wifi/WifiNativeTest.java
index 31e7e553c..abec9dc8b 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();
+ 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();
+ assertFalse(mWifiNative.selectTxPowerScenario(sarInfo));
+ verify(mWifiVendorHal).selectTxPowerScenario(sarInfo);
+ }
}
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiServiceImplTest.java b/tests/wifitests/src/com/android/server/wifi/WifiServiceImplTest.java
index 6a248161c..f04f53130 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiServiceImplTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiServiceImplTest.java
@@ -2838,4 +2838,31 @@ public class WifiServiceImplTest {
mBroadcastReceiverCaptor.getValue().onReceive(mContext, intent);
verifyNoMoreInteractions(mWifiCountryCode);
}
+
+ /**
+ * Verify calls to notify users of a softap config change check the NETWORK_SETTINGS permission.
+ */
+ @Test
+ public void testNotifyUserOfApBandConversionChecksNetworkSettingsPermission() {
+ mWifiServiceImpl.notifyUserOfApBandConversion(TEST_PACKAGE_NAME);
+ verify(mContext).enforceCallingOrSelfPermission(
+ eq(android.Manifest.permission.NETWORK_SETTINGS),
+ eq("WifiService"));
+ verify(mWifiApConfigStore).notifyUserOfApBandConversion(eq(TEST_PACKAGE_NAME));
+ }
+
+ /**
+ * Verify calls to notify users do not trigger a notification when NETWORK_SETTINGS is not held
+ * by the caller.
+ */
+ @Test
+ public void testNotifyUserOfApBandConversionThrowsExceptionWithoutNetworkSettingsPermission() {
+ doThrow(new SecurityException()).when(mContext)
+ .enforceCallingOrSelfPermission(eq(android.Manifest.permission.NETWORK_SETTINGS),
+ eq("WifiService"));
+ try {
+ mWifiServiceImpl.notifyUserOfApBandConversion(TEST_PACKAGE_NAME);
+ fail("Expected Security exception");
+ } catch (SecurityException e) { }
+ }
}
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiVendorHalTest.java b/tests/wifitests/src/com/android/server/wifi/WifiVendorHalTest.java
index 0f8f56f66..f089ebbe7 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,547 @@ 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();
+ sarInfo.isVoiceCall = 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();
+ sarInfo.sarVoiceCallSupported = true;
+ sarInfo.sarSapSupported = false;
+ sarInfo.sarSensorSupported = false;
+
+ sarInfo.isVoiceCall = 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();
+ sarInfo.sarVoiceCallSupported = true;
+ sarInfo.sarSapSupported = false;
+ sarInfo.sarSensorSupported = false;
+
+ sarInfo.isVoiceCall = 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();
+
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();
+ sarInfo.sarVoiceCallSupported = true;
+ sarInfo.sarSapSupported = false;
+ sarInfo.sarSensorSupported = 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 testResetTxPowerScenario_not_needed_1_1() throws RemoteException {
+ InOrder inOrder = inOrder(mIWifiChipV11);
+
+ // Create a SAR info record (no sensor or SAP support)
+ SarInfo sarInfo = new SarInfo();
+ sarInfo.sarVoiceCallSupported = true;
+ sarInfo.sarSapSupported = false;
+ sarInfo.sarSensorSupported = 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 or SAP support)
+ SarInfo sarInfo = new SarInfo();
+ sarInfo.sarVoiceCallSupported = true;
+ sarInfo.sarSapSupported = false;
+ sarInfo.sarSensorSupported = 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 or SAP support)
+ SarInfo sarInfo = new SarInfo();
+ sarInfo.sarVoiceCallSupported = true;
+ sarInfo.sarSapSupported = false;
+ sarInfo.sarSensorSupported = 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 no sensor support, but with
+ * SAP and voice call support.
+ * When SAP is enabled, should result in SAP with near body scenario
+ * Using IWifiChip 1.2 interface
+ */
+ @Test
+ public void testSapScenarios_SelectTxPowerV1_2() throws RemoteException {
+ // Create a SAR info record (with sensor and SAP support)
+ SarInfo sarInfo = new SarInfo();
+ sarInfo.sarVoiceCallSupported = true;
+ sarInfo.sarSapSupported = true;
+ sarInfo.sarSensorSupported = false;
+
+ sarInfo.isWifiSapEnabled = true;
+
+ // Expose the 1.2 IWifiChip.
+ mWifiVendorHal = new WifiVendorHalSpyV1_2(mHalDeviceManager, mLooper.getLooper());
+ when(mIWifiChipV12.selectTxPowerScenario_1_2(anyInt())).thenReturn(mWifiStatusSuccess);
+
+ // ON_BODY_CELL_ON
+ assertTrue(mWifiVendorHal.startVendorHalSta());
+ assertTrue(mWifiVendorHal.selectTxPowerScenario(sarInfo));
+ verify(mIWifiChipV12).selectTxPowerScenario_1_2(
+ eq(android.hardware.wifi.V1_2.IWifiChip.TxPowerScenario.ON_BODY_CELL_ON));
+ verify(mIWifiChipV12, never()).resetTxPowerScenario();
+ mWifiVendorHal.stopVendorHal();
+ }
+
+ /**
+ * Test the selectTxPowerScenario HIDL method invocation with no sensor support, but with
+ * SAP and voice call support.
+ * When a voice call is ongoing, should result in cell with near head scenario
+ * Using IWifiChip 1.2 interface
*/
@Test
- public void testInvalidSelectTxPowerScenario() throws RemoteException {
+ public void testVoiceCallScenarios_SelectTxPowerV1_2() throws RemoteException {
+ // Create a SAR info record (with sensor and SAP support)
+ SarInfo sarInfo = new SarInfo();
+ sarInfo.sarVoiceCallSupported = true;
+ sarInfo.sarSapSupported = true;
+ sarInfo.sarSensorSupported = false;
+
+ sarInfo.isVoiceCall = true;
+
+ // Expose the 1.2 IWifiChip.
+ mWifiVendorHal = new WifiVendorHalSpyV1_2(mHalDeviceManager, mLooper.getLooper());
+ when(mIWifiChipV12.selectTxPowerScenario_1_2(anyInt())).thenReturn(mWifiStatusSuccess);
+
+ // ON_HEAD_CELL_ON
+ assertTrue(mWifiVendorHal.startVendorHalSta());
+ assertTrue(mWifiVendorHal.selectTxPowerScenario(sarInfo));
+ verify(mIWifiChipV12).selectTxPowerScenario_1_2(
+ eq(android.hardware.wifi.V1_2.IWifiChip.TxPowerScenario.ON_HEAD_CELL_ON));
+ verify(mIWifiChipV12, never()).resetTxPowerScenario();
+ 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 and SAP support)
+ SarInfo sarInfo = new SarInfo();
+ sarInfo.sarVoiceCallSupported = true;
+ sarInfo.sarSapSupported = true;
+ sarInfo.sarSensorSupported = true;
+
+ sarInfo.sensorState = 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 and SAP support)
+ SarInfo sarInfo = new SarInfo();
+ sarInfo.sarVoiceCallSupported = true;
+ sarInfo.sarSapSupported = true;
+ sarInfo.sarSensorSupported = true;
+
+ sarInfo.sensorState = 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 and SAR support)
+ SarInfo sarInfo = new SarInfo();
+ sarInfo.sarVoiceCallSupported = true;
+ sarInfo.sarSapSupported = true;
+ sarInfo.sarSensorSupported = true;
+
+ sarInfo.sensorState = 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.isVoiceCall = 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 and SAP support)
+ SarInfo sarInfo = new SarInfo();
+ sarInfo.sarVoiceCallSupported = true;
+ sarInfo.sarSapSupported = true;
+ sarInfo.sarSensorSupported = true;
+
+ sarInfo.sensorState = 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.isVoiceCall = 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 and SAP support)
+ SarInfo sarInfo = new SarInfo();
+ sarInfo.sarVoiceCallSupported = true;
+ sarInfo.sarSapSupported = true;
+ sarInfo.sarSensorSupported = true;
+
+ sarInfo.sensorState = 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 and SAP support)
+ SarInfo sarInfo = new SarInfo();
+ sarInfo.sarVoiceCallSupported = true;
+ sarInfo.sarSapSupported = true;
+ sarInfo.sarSensorSupported = true;
+
+ sarInfo.sensorState = SarInfo.SAR_SENSOR_NEAR_HEAD;
+ sarInfo.isWifiSapEnabled = true;
+ sarInfo.isVoiceCall = 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 and SAP support)
+ SarInfo sarInfo = new SarInfo();
+ sarInfo.sarVoiceCallSupported = true;
+ sarInfo.sarSapSupported = true;
+ sarInfo.sarSensorSupported = true;
+
+ sarInfo.sensorState = SarInfo.SAR_SENSOR_NEAR_HEAD;
+ sarInfo.isWifiSapEnabled = true;
+ sarInfo.isVoiceCall = 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 and SAP support)
+ SarInfo sarInfo = new SarInfo();
+ sarInfo.sarVoiceCallSupported = true;
+ sarInfo.sarSapSupported = true;
+ sarInfo.sarSensorSupported = true;
+
+ sarInfo.sensorState = SarInfo.SAR_SENSOR_FREE_SPACE;
+ sarInfo.isWifiSapEnabled = true;
+ sarInfo.isVoiceCall = 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();
+ sarInfo.sarVoiceCallSupported = true;
+ sarInfo.sarSapSupported = true;
+ sarInfo.sarSensorSupported = true;
+
+ sarInfo.isWifiSapEnabled = true;
+ sarInfo.isVoiceCall = 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();
}
diff --git a/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointManagerTest.java b/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointManagerTest.java
index 2a76d6a32..abcd0bf34 100644
--- a/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointManagerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointManagerTest.java
@@ -284,6 +284,7 @@ public class PasspointManagerTest {
PasspointProvider provider = createMockProvider(config);
when(mObjectFactory.makePasspointProvider(eq(config), eq(mWifiKeyStore),
eq(mSimAccessor), anyLong(), eq(TEST_CREATOR_UID))).thenReturn(provider);
+
assertTrue(mManager.addOrUpdateProvider(config, TEST_CREATOR_UID));
return provider;
@@ -1378,9 +1379,10 @@ public class PasspointManagerTest {
* @throws Exception
*/
@Test
- public void updateMetrics() throws Exception {
+ public void updateMetrics() {
PasspointProvider provider = addTestProvider(TEST_FQDN);
-
+ ArgumentCaptor<Map<String, PasspointProvider>> argCaptor = ArgumentCaptor.forClass(
+ Map.class);
// Provider have not provided a successful network connection.
int expectedInstalledProviders = 1;
int expectedConnectedProviders = 0;
@@ -1388,7 +1390,10 @@ public class PasspointManagerTest {
mManager.updateMetrics();
verify(mWifiMetrics).updateSavedPasspointProfiles(
eq(expectedInstalledProviders), eq(expectedConnectedProviders));
- reset(provider);
+
+ verify(mWifiMetrics).updateSavedPasspointProfilesInfo(argCaptor.capture());
+ assertEquals(expectedInstalledProviders, argCaptor.getValue().size());
+ assertEquals(provider, argCaptor.getValue().get(TEST_FQDN));
reset(mWifiMetrics);
// Provider have provided a successful network connection.
@@ -1398,6 +1403,7 @@ public class PasspointManagerTest {
verify(mWifiMetrics).updateSavedPasspointProfiles(
eq(expectedInstalledProviders), eq(expectedConnectedProviders));
}
+
/**
* Verify Passpoint Manager's provisioning APIs by invoking methods in PasspointProvisioner for
* initiailization and provisioning a provider.
diff --git a/tests/wifitests/src/com/android/server/wifi/rtt/RttNativeTest.java b/tests/wifitests/src/com/android/server/wifi/rtt/RttNativeTest.java
index 3f5aa5f2d..7bbe6bb79 100644
--- a/tests/wifitests/src/com/android/server/wifi/rtt/RttNativeTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/rtt/RttNativeTest.java
@@ -23,6 +23,7 @@ import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
@@ -50,10 +51,13 @@ import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ErrorCollector;
import org.mockito.ArgumentCaptor;
+import org.mockito.InOrder;
import org.mockito.Mock;
+import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
/**
@@ -62,6 +66,7 @@ import java.util.List;
public class RttNativeTest {
private RttNative mDut;
private WifiStatus mStatusSuccess;
+ private WifiStatus mStatusRttControllerInvalid;
private ArgumentCaptor<ArrayList> mRttConfigCaptor = ArgumentCaptor.forClass(ArrayList.class);
private ArgumentCaptor<List> mRttResultCaptor = ArgumentCaptor.forClass(List.class);
@@ -97,6 +102,9 @@ public class RttNativeTest {
when(mockRttController.rangeCancel(anyInt(), any(ArrayList.class))).thenReturn(
mStatusSuccess);
+ mStatusRttControllerInvalid = new WifiStatus();
+ mStatusRttControllerInvalid.code = WifiStatusCode.ERROR_WIFI_RTT_CONTROLLER_INVALID;
+
mDut = new RttNative(mockRttServiceImpl, mockHalDeviceManager);
mDut.start(null);
verify(mockHalDeviceManager).registerStatusListener(mHdmStatusListener.capture(), any());
@@ -324,15 +332,18 @@ public class RttNativeTest {
int cmdId = 55;
RangingRequest request = RttTestUtils.getDummyRangingRequest((byte) 0);
+ InOrder order = inOrder(mockRttServiceImpl);
+
// (1) configure Wi-Fi down and send a status change indication
when(mockHalDeviceManager.isStarted()).thenReturn(false);
mHdmStatusListener.getValue().onStatusChanged();
- verify(mockRttServiceImpl).disable();
+ order.verify(mockRttServiceImpl).disable();
assertFalse(mDut.isReady());
// (2) issue range request
mDut.rangeRequest(cmdId, request, true);
+ order.verify(mockRttServiceImpl).disable(); // due to re-init attempt
verifyNoMoreInteractions(mockRttServiceImpl, mockRttController);
}
@@ -436,6 +447,77 @@ public class RttNativeTest {
}
}
+ /**
+ * Validate correct re-initialization when the RTT Controller is invalid (which can happen
+ * due to mode change in the HAL). Expect a re-initialization and a rerun of the range request.
+ */
+ @Test
+ public void testRangeRequestInvalidRttControllerOnce() throws Exception {
+ int cmdId = 55;
+ RangingRequest request = RttTestUtils.getDummyRangingRequest((byte) 0);
+
+ InOrder inOrder = Mockito.inOrder(mockRttController);
+
+ // configure failure then success
+ when(mockRttController.rangeRequest(anyInt(), any(ArrayList.class))).thenReturn(
+ mStatusRttControllerInvalid).thenReturn(mStatusSuccess);
+
+ // issue range request
+ boolean result = mDut.rangeRequest(cmdId, request, true);
+ assertTrue("rangeRequest should succeeed", result);
+
+ // verify HAL call
+ inOrder.verify(mockRttController).rangeRequest(eq(cmdId), mRttConfigCaptor.capture());
+ ArrayList<RttConfig> halRequest1 = mRttConfigCaptor.getValue();
+
+ // verify re-initialization (i.e. callback re-registered)
+ inOrder.verify(mockRttController).registerEventCallback(any());
+
+ // verify HAL call
+ inOrder.verify(mockRttController).rangeRequest(eq(cmdId), mRttConfigCaptor.capture());
+ ArrayList<RttConfig> halRequest2 = mRttConfigCaptor.getValue();
+
+ assertTrue("HAL parameters different between calls!",
+ Arrays.equals(halRequest1.toArray(), halRequest2.toArray()));
+ verifyNoMoreInteractions(mockRttController);
+ }
+
+ /**
+ * Validate correct re-initialization when the RTT Controller is invalid (which can happen
+ * due to mode change in the HAL). Expect a re-initialization and a rerun of the range request -
+ * but only once (no infinite loop).
+ */
+ @Test
+ public void testRangeRequestInvalidRttControllerForever() throws Exception {
+ int cmdId = 55;
+ RangingRequest request = RttTestUtils.getDummyRangingRequest((byte) 0);
+
+ InOrder inOrder = Mockito.inOrder(mockRttController);
+
+ // configure failure
+ when(mockRttController.rangeRequest(anyInt(), any(ArrayList.class))).thenReturn(
+ mStatusRttControllerInvalid);
+
+ // issue range request
+ boolean result = mDut.rangeRequest(cmdId, request, true);
+ assertFalse("rangeRequest should fail", result);
+
+ // verify HAL call
+ inOrder.verify(mockRttController).rangeRequest(eq(cmdId), mRttConfigCaptor.capture());
+ ArrayList<RttConfig> halRequest1 = mRttConfigCaptor.getValue();
+
+ // verify re-initialization (i.e. callback re-registered)
+ inOrder.verify(mockRttController).registerEventCallback(any());
+
+ // verify HAL call
+ inOrder.verify(mockRttController).rangeRequest(eq(cmdId), mRttConfigCaptor.capture());
+ ArrayList<RttConfig> halRequest2 = mRttConfigCaptor.getValue();
+
+ assertTrue("HAL parameters different between calls!",
+ Arrays.equals(halRequest1.toArray(), halRequest2.toArray()));
+ verifyNoMoreInteractions(mockRttController);
+ }
+
// Utilities
/**