HeadsetPhoneState.java revision 13e1a71bf0cf955ac39390fd96fd3f04e1954ef6
1/* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.bluetooth.hfp; 18 19import android.content.Context; 20import android.telephony.PhoneStateListener; 21import android.telephony.ServiceState; 22import android.telephony.SignalStrength; 23import android.telephony.TelephonyManager; 24import android.telephony.SubscriptionManager; 25import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener; 26import android.util.Log; 27import android.bluetooth.BluetoothDevice; 28 29 30// Note: 31// All methods in this class are not thread safe, donot call them from 32// multiple threads. Call them from the HeadsetPhoneStateMachine message 33// handler only. 34class HeadsetPhoneState { 35 private static final String TAG = "HeadsetPhoneState"; 36 37 private HeadsetStateMachine mStateMachine; 38 private TelephonyManager mTelephonyManager; 39 private ServiceState mServiceState; 40 41 // HFP 1.6 CIND service 42 private int mService = HeadsetHalConstants.NETWORK_STATE_NOT_AVAILABLE; 43 44 // Number of active (foreground) calls 45 private int mNumActive = 0; 46 47 // Current Call Setup State 48 private int mCallState = HeadsetHalConstants.CALL_STATE_IDLE; 49 50 // Number of held (background) calls 51 private int mNumHeld = 0; 52 53 // HFP 1.6 CIND signal 54 private int mSignal = 0; 55 56 // HFP 1.6 CIND roam 57 private int mRoam = HeadsetHalConstants.SERVICE_TYPE_HOME; 58 59 // HFP 1.6 CIND battchg 60 private int mBatteryCharge = 0; 61 62 private int mSpeakerVolume = 0; 63 64 private int mMicVolume = 0; 65 66 private boolean mListening = false; 67 68 // when HFP Service Level Connection is established 69 private boolean mSlcReady = false; 70 71 private Context mContext = null; 72 73 private PhoneStateListener mPhoneStateListener = null; 74 75 private SubscriptionManager mSubMgr; 76 77 private OnSubscriptionsChangedListener mOnSubscriptionsChangedListener = 78 new OnSubscriptionsChangedListener() { 79 @Override 80 public void onSubscriptionsChanged() { 81 listenForPhoneState(false); 82 listenForPhoneState(true); 83 } 84 }; 85 86 87 HeadsetPhoneState(Context context, HeadsetStateMachine stateMachine) { 88 mStateMachine = stateMachine; 89 mTelephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); 90 mContext = context; 91 92 // Register for SubscriptionInfo list changes which is guaranteed 93 // to invoke onSubscriptionInfoChanged and which in turns calls 94 // loadInBackgroud. 95 mSubMgr = SubscriptionManager.from(mContext); 96 mSubMgr.registerOnSubscriptionsChangedListener(mOnSubscriptionsChangedListener); 97 } 98 99 public void cleanup() { 100 listenForPhoneState(false); 101 mSubMgr.unregisterOnSubscriptionsChangedListener(mOnSubscriptionsChangedListener); 102 103 mTelephonyManager = null; 104 mStateMachine = null; 105 } 106 107 void listenForPhoneState(boolean start) { 108 109 mSlcReady = start; 110 111 if (start) { 112 startListenForPhoneState(); 113 } else { 114 stopListenForPhoneState(); 115 } 116 117 } 118 119 private void startListenForPhoneState() { 120 if (!mListening && mSlcReady) { 121 122 int subId = SubscriptionManager.getDefaultSubId(); 123 124 if (SubscriptionManager.isValidSubId(subId)) { 125 mPhoneStateListener = getPhoneStateListener(subId); 126 127 mTelephonyManager.listen(mPhoneStateListener, 128 PhoneStateListener.LISTEN_SERVICE_STATE | 129 PhoneStateListener.LISTEN_SIGNAL_STRENGTHS); 130 mListening = true; 131 } 132 } 133 } 134 135 private void stopListenForPhoneState() { 136 if (mListening) { 137 138 mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE); 139 mListening = false; 140 } 141 } 142 143 int getService() { 144 return mService; 145 } 146 147 int getNumActiveCall() { 148 return mNumActive; 149 } 150 151 void setNumActiveCall(int numActive) { 152 mNumActive = numActive; 153 } 154 155 int getCallState() { 156 return mCallState; 157 } 158 159 void setCallState(int callState) { 160 mCallState = callState; 161 } 162 163 int getNumHeldCall() { 164 return mNumHeld; 165 } 166 167 void setNumHeldCall(int numHeldCall) { 168 mNumHeld = numHeldCall; 169 } 170 171 int getSignal() { 172 return mSignal; 173 } 174 175 int getRoam() { 176 return mRoam; 177 } 178 179 void setRoam(int roam) { 180 mRoam = roam; 181 } 182 183 void setBatteryCharge(int batteryLevel) { 184 if (mBatteryCharge != batteryLevel) { 185 mBatteryCharge = batteryLevel; 186 sendDeviceStateChanged(); 187 } 188 } 189 190 int getBatteryCharge() { 191 return mBatteryCharge; 192 } 193 194 void setSpeakerVolume(int volume) { 195 mSpeakerVolume = volume; 196 } 197 198 int getSpeakerVolume() { 199 return mSpeakerVolume; 200 } 201 202 void setMicVolume(int volume) { 203 mMicVolume = volume; 204 } 205 206 int getMicVolume() { 207 return mMicVolume; 208 } 209 210 boolean isInCall() { 211 return (mNumActive >= 1); 212 } 213 214 void sendDeviceStateChanged() 215 { 216 // When out of service, send signal strength as 0. Some devices don't 217 // use the service indicator, but only the signal indicator 218 int signal = mService == HeadsetHalConstants.NETWORK_STATE_AVAILABLE ? mSignal : 0; 219 220 Log.d(TAG, "sendDeviceStateChanged. mService="+ mService + 221 " mSignal=" + signal +" mRoam="+ mRoam + 222 " mBatteryCharge=" + mBatteryCharge); 223 HeadsetStateMachine sm = mStateMachine; 224 if (sm != null) { 225 sm.sendMessage(HeadsetStateMachine.DEVICE_STATE_CHANGED, 226 new HeadsetDeviceState(mService, mRoam, signal, mBatteryCharge)); 227 } 228 } 229 230 private PhoneStateListener getPhoneStateListener(int subId) { 231 PhoneStateListener mPhoneStateListener = new PhoneStateListener(subId) { 232 @Override 233 public void onServiceStateChanged(ServiceState serviceState) { 234 235 mServiceState = serviceState; 236 mService = (serviceState.getState() == ServiceState.STATE_IN_SERVICE) ? 237 HeadsetHalConstants.NETWORK_STATE_AVAILABLE : 238 HeadsetHalConstants.NETWORK_STATE_NOT_AVAILABLE; 239 setRoam(serviceState.getRoaming() ? HeadsetHalConstants.SERVICE_TYPE_ROAMING 240 : HeadsetHalConstants.SERVICE_TYPE_HOME); 241 242 sendDeviceStateChanged(); 243 } 244 245 @Override 246 public void onSignalStrengthsChanged(SignalStrength signalStrength) { 247 248 int prevSignal = mSignal; 249 if (mService == HeadsetHalConstants.NETWORK_STATE_NOT_AVAILABLE) { 250 mSignal = 0; 251 } else if (signalStrength.isGsm()) { 252 mSignal = gsmAsuToSignal(signalStrength); 253 } else { 254 mSignal = cdmaDbmEcioToSignal(signalStrength); 255 } 256 257 // network signal strength is scaled to BT 1-5 levels. 258 // This results in a lot of duplicate messages, hence this check 259 if (prevSignal != mSignal) { 260 sendDeviceStateChanged(); 261 } 262 } 263 264 /* convert [0,31] ASU signal strength to the [0,5] expected by 265 * bluetooth devices. Scale is similar to status bar policy 266 */ 267 private int gsmAsuToSignal(SignalStrength signalStrength) { 268 int asu = signalStrength.getGsmSignalStrength(); 269 if (asu >= 16) return 5; 270 else if (asu >= 8) return 4; 271 else if (asu >= 4) return 3; 272 else if (asu >= 2) return 2; 273 else if (asu >= 1) return 1; 274 else return 0; 275 } 276 277 /** 278 * Convert the cdma / evdo db levels to appropriate icon level. 279 * The scale is similar to the one used in status bar policy. 280 * 281 * @param signalStrength 282 * @return the icon level 283 */ 284 private int cdmaDbmEcioToSignal(SignalStrength signalStrength) { 285 int levelDbm = 0; 286 int levelEcio = 0; 287 int cdmaIconLevel = 0; 288 int evdoIconLevel = 0; 289 int cdmaDbm = signalStrength.getCdmaDbm(); 290 int cdmaEcio = signalStrength.getCdmaEcio(); 291 292 if (cdmaDbm >= -75) levelDbm = 4; 293 else if (cdmaDbm >= -85) levelDbm = 3; 294 else if (cdmaDbm >= -95) levelDbm = 2; 295 else if (cdmaDbm >= -100) levelDbm = 1; 296 else levelDbm = 0; 297 298 // Ec/Io are in dB*10 299 if (cdmaEcio >= -90) levelEcio = 4; 300 else if (cdmaEcio >= -110) levelEcio = 3; 301 else if (cdmaEcio >= -130) levelEcio = 2; 302 else if (cdmaEcio >= -150) levelEcio = 1; 303 else levelEcio = 0; 304 305 cdmaIconLevel = (levelDbm < levelEcio) ? levelDbm : levelEcio; 306 307 // STOPSHIP: Change back to getRilVoiceRadioTechnology 308 if (mServiceState != null && 309 (mServiceState.getRadioTechnology() == 310 ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_0 || 311 mServiceState.getRadioTechnology() == 312 ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_A)) { 313 int evdoEcio = signalStrength.getEvdoEcio(); 314 int evdoSnr = signalStrength.getEvdoSnr(); 315 int levelEvdoEcio = 0; 316 int levelEvdoSnr = 0; 317 318 // Ec/Io are in dB*10 319 if (evdoEcio >= -650) levelEvdoEcio = 4; 320 else if (evdoEcio >= -750) levelEvdoEcio = 3; 321 else if (evdoEcio >= -900) levelEvdoEcio = 2; 322 else if (evdoEcio >= -1050) levelEvdoEcio = 1; 323 else levelEvdoEcio = 0; 324 325 if (evdoSnr > 7) levelEvdoSnr = 4; 326 else if (evdoSnr > 5) levelEvdoSnr = 3; 327 else if (evdoSnr > 3) levelEvdoSnr = 2; 328 else if (evdoSnr > 1) levelEvdoSnr = 1; 329 else levelEvdoSnr = 0; 330 331 evdoIconLevel = (levelEvdoEcio < levelEvdoSnr) ? levelEvdoEcio : levelEvdoSnr; 332 } 333 // TODO(): There is a bug open regarding what should be sent. 334 return (cdmaIconLevel > evdoIconLevel) ? cdmaIconLevel : evdoIconLevel; 335 } 336 }; 337 return mPhoneStateListener; 338 } 339 340} 341 342class HeadsetDeviceState { 343 int mService; 344 int mRoam; 345 int mSignal; 346 int mBatteryCharge; 347 348 HeadsetDeviceState(int service, int roam, int signal, int batteryCharge) { 349 mService = service; 350 mRoam = roam; 351 mSignal = signal; 352 mBatteryCharge = batteryCharge; 353 } 354} 355 356class HeadsetCallState { 357 int mNumActive; 358 int mNumHeld; 359 int mCallState; 360 String mNumber; 361 int mType; 362 363 public HeadsetCallState(int numActive, int numHeld, int callState, String number, int type) { 364 mNumActive = numActive; 365 mNumHeld = numHeld; 366 mCallState = callState; 367 mNumber = number; 368 mType = type; 369 } 370} 371 372class HeadsetClccResponse { 373 int mIndex; 374 int mDirection; 375 int mStatus; 376 int mMode; 377 boolean mMpty; 378 String mNumber; 379 int mType; 380 381 public HeadsetClccResponse(int index, int direction, int status, int mode, boolean mpty, 382 String number, int type) { 383 mIndex = index; 384 mDirection = direction; 385 mStatus = status; 386 mMode = mode; 387 mMpty = mpty; 388 mNumber = number; 389 mType = type; 390 } 391} 392 393class HeadsetVendorSpecificResultCode { 394 BluetoothDevice mDevice; 395 String mCommand; 396 String mArg; 397 398 public HeadsetVendorSpecificResultCode(BluetoothDevice device, String command, String arg) { 399 mDevice = device; 400 mCommand = command; 401 mArg = arg; 402 } 403} 404