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