HeadsetPhoneState.java revision 69d4ca45a25e86823fbdb754ca6a3995f8131d59
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.util.Log; 25import android.bluetooth.BluetoothDevice; 26 27 28// Note: 29// All methods in this class are not thread safe, donot call them from 30// multiple threads. Call them from the HeadsetPhoneStateMachine message 31// handler only. 32class HeadsetPhoneState { 33 private static final String TAG = "HeadsetPhoneState"; 34 35 private HeadsetStateMachine mStateMachine; 36 private TelephonyManager mTelephonyManager; 37 private ServiceState mServiceState; 38 39 // HFP 1.6 CIND service 40 private int mService = HeadsetHalConstants.NETWORK_STATE_NOT_AVAILABLE; 41 42 // Number of active (foreground) calls 43 private int mNumActive = 0; 44 45 // Current Call Setup State 46 private int mCallState = HeadsetHalConstants.CALL_STATE_IDLE; 47 48 // Number of held (background) calls 49 private int mNumHeld = 0; 50 51 // HFP 1.6 CIND signal 52 private int mSignal = 0; 53 54 // HFP 1.6 CIND roam 55 private int mRoam = HeadsetHalConstants.SERVICE_TYPE_HOME; 56 57 // HFP 1.6 CIND battchg 58 private int mBatteryCharge = 0; 59 60 private int mSpeakerVolume = 0; 61 62 private int mMicVolume = 0; 63 64 private boolean mListening = false; 65 66 HeadsetPhoneState(Context context, HeadsetStateMachine stateMachine) { 67 mStateMachine = stateMachine; 68 mTelephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); 69 } 70 71 public void cleanup() { 72 listenForPhoneState(false); 73 mTelephonyManager = null; 74 mStateMachine = null; 75 } 76 77 void listenForPhoneState(boolean start) { 78 if (start) { 79 if (!mListening) { 80 mTelephonyManager.listen(mPhoneStateListener, 81 PhoneStateListener.LISTEN_SERVICE_STATE | 82 PhoneStateListener.LISTEN_SIGNAL_STRENGTHS); 83 mListening = true; 84 } 85 } else { 86 if (mListening) { 87 mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE); 88 mListening = false; 89 } 90 } 91 } 92 93 int getService() { 94 return mService; 95 } 96 97 int getNumActiveCall() { 98 return mNumActive; 99 } 100 101 void setNumActiveCall(int numActive) { 102 mNumActive = numActive; 103 } 104 105 int getCallState() { 106 return mCallState; 107 } 108 109 void setCallState(int callState) { 110 mCallState = callState; 111 } 112 113 int getNumHeldCall() { 114 return mNumHeld; 115 } 116 117 void setNumHeldCall(int numHeldCall) { 118 mNumHeld = numHeldCall; 119 } 120 121 int getSignal() { 122 return mSignal; 123 } 124 125 int getRoam() { 126 return mRoam; 127 } 128 129 void setRoam(int roam) { 130 mRoam = roam; 131 } 132 133 void setBatteryCharge(int batteryLevel) { 134 if (mBatteryCharge != batteryLevel) { 135 mBatteryCharge = batteryLevel; 136 sendDeviceStateChanged(); 137 } 138 } 139 140 int getBatteryCharge() { 141 return mBatteryCharge; 142 } 143 144 void setSpeakerVolume(int volume) { 145 mSpeakerVolume = volume; 146 } 147 148 int getSpeakerVolume() { 149 return mSpeakerVolume; 150 } 151 152 void setMicVolume(int volume) { 153 mMicVolume = volume; 154 } 155 156 int getMicVolume() { 157 return mMicVolume; 158 } 159 160 boolean isInCall() { 161 return (mNumActive >= 1); 162 } 163 164 void sendDeviceStateChanged() 165 { 166 Log.d(TAG, "sendDeviceStateChanged. mService="+ mService + 167 " mSignal="+mSignal +" mRoam="+mRoam + 168 " mBatteryCharge=" + mBatteryCharge); 169 HeadsetStateMachine sm = mStateMachine; 170 if (sm != null) { 171 sm.sendMessage(HeadsetStateMachine.DEVICE_STATE_CHANGED, 172 new HeadsetDeviceState(mService, mRoam, mSignal, mBatteryCharge)); 173 } 174 } 175 176 private PhoneStateListener mPhoneStateListener = new PhoneStateListener() { 177 @Override 178 public void onServiceStateChanged(ServiceState serviceState) { 179 mServiceState = serviceState; 180 mService = (serviceState.getState() == ServiceState.STATE_IN_SERVICE) ? 181 HeadsetHalConstants.NETWORK_STATE_AVAILABLE : 182 HeadsetHalConstants.NETWORK_STATE_NOT_AVAILABLE; 183 setRoam(serviceState.getRoaming() ? HeadsetHalConstants.SERVICE_TYPE_ROAMING 184 : HeadsetHalConstants.SERVICE_TYPE_HOME); 185 sendDeviceStateChanged(); 186 } 187 188 @Override 189 public void onSignalStrengthsChanged(SignalStrength signalStrength) { 190 int prevSignal = mSignal; 191 if (mService == HeadsetHalConstants.NETWORK_STATE_NOT_AVAILABLE) 192 mSignal = 0; 193 else if (signalStrength.isGsm()) { 194 mSignal = gsmAsuToSignal(signalStrength); 195 } else { 196 mSignal = cdmaDbmEcioToSignal(signalStrength); 197 } 198 // network signal strength is scaled to BT 1-5 levels. 199 // This results in a lot of duplicate messages, hence this check 200 if (prevSignal != mSignal) 201 sendDeviceStateChanged(); 202 } 203 204 /* convert [0,31] ASU signal strength to the [0,5] expected by 205 * bluetooth devices. Scale is similar to status bar policy 206 */ 207 private int gsmAsuToSignal(SignalStrength signalStrength) { 208 int asu = signalStrength.getGsmSignalStrength(); 209 if (asu >= 16) return 5; 210 else if (asu >= 8) return 4; 211 else if (asu >= 4) return 3; 212 else if (asu >= 2) return 2; 213 else if (asu >= 1) return 1; 214 else return 0; 215 } 216 217 /** 218 * Convert the cdma / evdo db levels to appropriate icon level. 219 * The scale is similar to the one used in status bar policy. 220 * 221 * @param signalStrength 222 * @return the icon level 223 */ 224 private int cdmaDbmEcioToSignal(SignalStrength signalStrength) { 225 int levelDbm = 0; 226 int levelEcio = 0; 227 int cdmaIconLevel = 0; 228 int evdoIconLevel = 0; 229 int cdmaDbm = signalStrength.getCdmaDbm(); 230 int cdmaEcio = signalStrength.getCdmaEcio(); 231 232 if (cdmaDbm >= -75) levelDbm = 4; 233 else if (cdmaDbm >= -85) levelDbm = 3; 234 else if (cdmaDbm >= -95) levelDbm = 2; 235 else if (cdmaDbm >= -100) levelDbm = 1; 236 else levelDbm = 0; 237 238 // Ec/Io are in dB*10 239 if (cdmaEcio >= -90) levelEcio = 4; 240 else if (cdmaEcio >= -110) levelEcio = 3; 241 else if (cdmaEcio >= -130) levelEcio = 2; 242 else if (cdmaEcio >= -150) levelEcio = 1; 243 else levelEcio = 0; 244 245 cdmaIconLevel = (levelDbm < levelEcio) ? levelDbm : levelEcio; 246 247 // STOPSHIP: Change back to getRilVoiceRadioTechnology 248 if (mServiceState != null && 249 (mServiceState.getRadioTechnology() == 250 ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_0 || 251 mServiceState.getRadioTechnology() == 252 ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_A)) { 253 int evdoEcio = signalStrength.getEvdoEcio(); 254 int evdoSnr = signalStrength.getEvdoSnr(); 255 int levelEvdoEcio = 0; 256 int levelEvdoSnr = 0; 257 258 // Ec/Io are in dB*10 259 if (evdoEcio >= -650) levelEvdoEcio = 4; 260 else if (evdoEcio >= -750) levelEvdoEcio = 3; 261 else if (evdoEcio >= -900) levelEvdoEcio = 2; 262 else if (evdoEcio >= -1050) levelEvdoEcio = 1; 263 else levelEvdoEcio = 0; 264 265 if (evdoSnr > 7) levelEvdoSnr = 4; 266 else if (evdoSnr > 5) levelEvdoSnr = 3; 267 else if (evdoSnr > 3) levelEvdoSnr = 2; 268 else if (evdoSnr > 1) levelEvdoSnr = 1; 269 else levelEvdoSnr = 0; 270 271 evdoIconLevel = (levelEvdoEcio < levelEvdoSnr) ? levelEvdoEcio : levelEvdoSnr; 272 } 273 // TODO(): There is a bug open regarding what should be sent. 274 return (cdmaIconLevel > evdoIconLevel) ? cdmaIconLevel : evdoIconLevel; 275 } 276 }; 277 278} 279 280class HeadsetDeviceState { 281 int mService; 282 int mRoam; 283 int mSignal; 284 int mBatteryCharge; 285 286 HeadsetDeviceState(int service, int roam, int signal, int batteryCharge) { 287 mService = service; 288 mRoam = roam; 289 mSignal = signal; 290 mBatteryCharge = batteryCharge; 291 } 292} 293 294class HeadsetCallState { 295 int mNumActive; 296 int mNumHeld; 297 int mCallState; 298 String mNumber; 299 int mType; 300 301 public HeadsetCallState(int numActive, int numHeld, int callState, String number, int type) { 302 mNumActive = numActive; 303 mNumHeld = numHeld; 304 mCallState = callState; 305 mNumber = number; 306 mType = type; 307 } 308} 309 310class HeadsetClccResponse { 311 int mIndex; 312 int mDirection; 313 int mStatus; 314 int mMode; 315 boolean mMpty; 316 String mNumber; 317 int mType; 318 319 public HeadsetClccResponse(int index, int direction, int status, int mode, boolean mpty, 320 String number, int type) { 321 mIndex = index; 322 mDirection = direction; 323 mStatus = status; 324 mMode = mode; 325 mMpty = mpty; 326 mNumber = number; 327 mType = type; 328 } 329} 330 331class HeadsetVendorSpecificResultCode { 332 BluetoothDevice mDevice; 333 String mCommand; 334 String mArg; 335 336 public HeadsetVendorSpecificResultCode(BluetoothDevice device, String command, String arg) { 337 mDevice = device; 338 mCommand = command; 339 mArg = arg; 340 } 341} 342