summaryrefslogtreecommitdiff
path: root/service
diff options
context:
space:
mode:
Diffstat (limited to 'service')
-rw-r--r--service/java/com/android/server/wifi/SarManager.java298
-rw-r--r--service/java/com/android/server/wifi/WifiInjector.java3
2 files changed, 209 insertions, 92 deletions
diff --git a/service/java/com/android/server/wifi/SarManager.java b/service/java/com/android/server/wifi/SarManager.java
index da48a8537..f157ac41e 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;
@@ -41,23 +43,25 @@ import java.util.List;
* It deals with the following:
* - Tracking the STA state through calls from the ClientModeManager.
* - Tracking the state of the Cellular calls or data.
- * - Based on above, selecting the SAR profile to use and programming it in wifi hal.
+ * - Tracking the sensor indicating proximity to user head/hand/body.
+ * - It constructs the sar info and send it towards the HAL
*/
public class SarManager {
-
/* For Logging */
private static final String TAG = "WifiSarManager";
private boolean mVerboseLoggingEnabled = true;
+ private SarInfo mSarInfo;
+
/* Configuration for SAR */
private boolean mEnableSarTxPowerLimit;
+ private boolean mEnableSarBodyProximity;
+ /* Sensor event definitions */
+ private int mSarSensorEventFreeSpace;
+ private int mSarSensorEventNearBody;
+ private int mSarSensorEventNearHand;
+ private int mSarSensorEventNearHead;
- /* Current SAR Scenario */
- private int mCurrentSarScenario = WifiNative.TX_POWER_SCENARIO_NORMAL;
-
- /* Booleans for Cell and wifi states */
- private boolean mCellOn = false;
- private boolean mWifiStaEnabled = false;
/**
* Other parameters passed in or created in the constructor.
*/
@@ -65,6 +69,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 +79,105 @@ public class SarManager {
SarManager(Context context,
TelephonyManager telephonyManager,
Looper looper,
- WifiNative wifiNative) {
+ WifiNative wifiNative,
+ SensorManager sensorManager) {
mContext = context;
mTelephonyManager = telephonyManager;
mWifiNative = wifiNative;
mLooper = looper;
+ mSensorManager = sensorManager;
mPhoneStateListener = new WifiPhoneStateListener(looper);
+ mSensorListener = new SarSensorEventListener();
+
+ readSarConfigs();
+ if (mEnableSarTxPowerLimit) {
+ mSarInfo = new SarInfo(mEnableSarBodyProximity);
+ registerListeners();
+ }
+ }
+
+ private void readSarConfigs() {
+ mEnableSarTxPowerLimit = mContext.getResources().getBoolean(
+ R.bool.config_wifi_framework_enable_sar_tx_power_limit);
+ /* In case SAR is disabled,
+ then SAR sensor is automatically disabled as well (irrespective of the config) */
+ if (!mEnableSarTxPowerLimit) {
+ mEnableSarBodyProximity = false;
+ return;
+ }
- registerListeners();
+ mEnableSarBodyProximity = mContext.getResources().getBoolean(
+ R.bool.config_wifi_framework_enable_body_proximity_sar_tx_power_limit);
+
+ /* Read the sar sensor event Ids */
+ if (mEnableSarBodyProximity) {
+ mSarSensorEventFreeSpace = mContext.getResources().getInteger(
+ R.integer.config_wifi_framework_sar_free_space_event_id);
+ mSarSensorEventNearBody = mContext.getResources().getInteger(
+ R.integer.config_wifi_framework_sar_near_body_event_id);
+ mSarSensorEventNearHand = mContext.getResources().getInteger(
+ R.integer.config_wifi_framework_sar_near_hand_event_id);
+ mSarSensorEventNearHead = mContext.getResources().getInteger(
+ R.integer.config_wifi_framework_sar_near_head_event_id);
+ }
+ }
+
+ private void registerListeners() {
+ /* Listen for Phone State changes */
+ registerPhoneStateListener();
+
+ /* Only listen for SAR sensor if supported */
+ if (mEnableSarBodyProximity) {
+ /* Register the SAR sensor listener.
+ * If this fails, we will assume worst case (near head) */
+ if (!registerSensorListener()) {
+ Log.e(TAG, "Failed to register sensor listener, setting Sensor to NearHead");
+ /*TODO Need to add a metric to determine how often this happens */
+ mSarInfo.mSensorState = SarInfo.SAR_SENSOR_NEAR_HEAD;
+ }
+ }
}
/**
- * Starts the SAR Manager by initializing the different listeners
+ * Register the phone state listener.
*/
- private void registerListeners() {
- /* First read the configuration for SAR Support */
- mEnableSarTxPowerLimit = mContext.getResources().getBoolean(
- R.bool.config_wifi_framework_enable_voice_call_sar_tx_power_limit);
+ private void registerPhoneStateListener() {
+ Log.i(TAG, "Registering for telephony call state changes");
+ mTelephonyManager.listen(
+ mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
+ }
- /* Only Start listening for events if SAR is enabled */
- if (mEnableSarTxPowerLimit) {
- Log.d(TAG, "Registering Listeners for the SAR Manager");
+ /**
+ * Register the body/hand/head proximity sensor.
+ */
+ private boolean registerSensorListener() {
+ Log.i(TAG, "Registering for Sensor notification Listener");
+ return mSensorListener.register();
+ }
+
+ /**
+ * Update Wifi Client State
+ */
+ public void setClientWifiState(int state) {
+ boolean newIsEnabled;
+ /* No action is taken if SAR is not enabled */
+ if (!mEnableSarTxPowerLimit) {
+ return;
+ }
+
+ if (state == WifiManager.WIFI_STATE_DISABLED) {
+ newIsEnabled = false;
+ } else if (state == WifiManager.WIFI_STATE_ENABLED) {
+ newIsEnabled = true;
+ } else {
+ /* No change so exiting with no action */
+ return;
+ }
- /* Listen for Phone State changes */
- registerPhoneListener();
+ /* Report change to HAL if needed */
+ if (mSarInfo.mIsWifiClientEnabled != newIsEnabled) {
+ mSarInfo.mIsWifiClientEnabled = newIsEnabled;
+ updateSarScenario();
}
}
@@ -104,42 +185,52 @@ public class SarManager {
* Report Cell state event
*/
private void onCellStateChangeEvent(int state) {
- boolean currentCellOn = mCellOn;
-
+ boolean newIsVoiceCall;
switch (state) {
case CALL_STATE_OFFHOOK:
case CALL_STATE_RINGING:
- mCellOn = true;
+ newIsVoiceCall = true;
break;
case CALL_STATE_IDLE:
- mCellOn = false;
+ newIsVoiceCall = false;
break;
default:
Log.e(TAG, "Invalid Cell State: " + state);
+ return;
}
- if (mCellOn != currentCellOn) {
+ /* Report change to HAL if needed */
+ if (mSarInfo.mIsVoiceCall != newIsVoiceCall) {
+ mSarInfo.mIsVoiceCall = newIsVoiceCall;
updateSarScenario();
}
}
/**
- * Update Wifi Client State
+ * Report an event from the SAR sensor
*/
- public void setClientWifiState(int state) {
- /* No action is taken if SAR is not enabled */
- if (!mEnableSarTxPowerLimit) return;
-
- if (state == WifiManager.WIFI_STATE_DISABLED && mWifiStaEnabled) {
- mWifiStaEnabled = false;
- } else if (state == WifiManager.WIFI_STATE_ENABLED && !mWifiStaEnabled) {
- mWifiStaEnabled = true;
+ private void onSarSensorEvent(int sarSensorEvent) {
+ int newSensorState;
+ if (sarSensorEvent == mSarSensorEventFreeSpace) {
+ newSensorState = SarInfo.SAR_SENSOR_FREE_SPACE;
+ } else if (sarSensorEvent == mSarSensorEventNearBody) {
+ newSensorState = SarInfo.SAR_SENSOR_NEAR_BODY;
+ } else if (sarSensorEvent == mSarSensorEventNearHand) {
+ newSensorState = SarInfo.SAR_SENSOR_NEAR_HAND;
+ } else if (sarSensorEvent == mSarSensorEventNearHead) {
+ newSensorState = SarInfo.SAR_SENSOR_NEAR_HEAD;
+ } else {
+ Log.e(TAG, "Invalid SAR sensor event id: " + sarSensorEvent);
+ return;
+ }
- /* Since no wifi interface was up,
- time for SAR scenario to take effect */
- sendTxPowerScenario(mCurrentSarScenario);
+ /* Report change to HAL if needed */
+ if (mSarInfo.mSensorState != newSensorState) {
+ Log.d(TAG, "Setting Sensor state to " + SarInfo.sensorStateToString(newSensorState));
+ mSarInfo.mSensorState = newSensorState;
+ updateSarScenario();
}
}
@@ -155,18 +246,16 @@ public class SarManager {
}
}
- public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- pw.println("*** WiFi SAR Manager Dump ***");
- pw.println("Current SAR Scenario is " + scenarioToString(mCurrentSarScenario));
- }
-
/**
- * Register the phone listener.
+ * dump()
+ * Dumps SarManager state (as well as its SarInfo member variable state)
*/
- private void registerPhoneListener() {
- Log.i(TAG, "Registering for telephony call state changes");
- mTelephonyManager.listen(
- mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ pw.println("*** WiFi SAR Manager Dump ***");
+ pw.println("isSarEnabled: " + mEnableSarTxPowerLimit);
+ pw.println("isSarSensorEnabled: " + mEnableSarBodyProximity);
+ pw.println("");
+ mSarInfo.dump(fd, pw, args);
}
/**
@@ -177,69 +266,96 @@ public class SarManager {
super(looper);
}
+ /**
+ * onCallStateChanged()
+ * This callback is called when a SAR sensor event is received
+ * Note that this runs in the WifiStateMachineHandlerThread
+ * since the corresponding Looper was passed to the WifiPhoneStateListener constructor.
+ */
@Override
public void onCallStateChanged(int state, String incomingNumber) {
Log.d(TAG, "Received Phone State Change: " + state);
/* In case of an unsolicited event */
- if (!mEnableSarTxPowerLimit) return;
-
+ if (!mEnableSarTxPowerLimit) {
+ return;
+ }
onCellStateChangeEvent(state);
}
}
- /**
- * update the Current SAR Scenario based on factors including:
- * - Do we have an ongoing cellular voice call.
- */
- private void updateSarScenario() {
- int newSarScenario;
+ private class SarSensorEventListener implements SensorEventListener {
- if (mCellOn) {
- newSarScenario = WifiNative.TX_POWER_SCENARIO_VOICE_CALL;
- } else {
- newSarScenario = WifiNative.TX_POWER_SCENARIO_NORMAL;
- }
+ private Sensor mSensor;
+
+ /**
+ * 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/WifiInjector.java b/service/java/com/android/server/wifi/WifiInjector.java
index 0e30af841..5a4fe570b 100644
--- a/service/java/com/android/server/wifi/WifiInjector.java
+++ b/service/java/com/android/server/wifi/WifiInjector.java
@@ -20,6 +20,7 @@ import android.annotation.NonNull;
import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.content.Context;
+import android.hardware.SystemSensorManager;
import android.net.NetworkKey;
import android.net.NetworkScoreManager;
import android.net.wifi.IWifiScanner;
@@ -253,7 +254,7 @@ public class WifiInjector {
this, mWifiConfigManager,
mWifiPermissionsUtil, mWifiMetrics, mClock);
mSarManager = new SarManager(mContext, makeTelephonyManager(), wifiStateMachineLooper,
- mWifiNative);
+ mWifiNative, new SystemSensorManager(mContext, wifiStateMachineLooper));
if (mUseRealLogger) {
mWifiDiagnostics = new WifiDiagnostics(
mContext, this, mWifiNative, mBuildProperties,