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             setRoam(serviceState.getRoaming() ? HeadsetHalConstants.SERVICE_TYPE_ROAMING
    182                                               : HeadsetHalConstants.SERVICE_TYPE_HOME);
    183             sendDeviceStateChanged();
    184         }
    185 
    186         @Override
    187         public void onSignalStrengthsChanged(SignalStrength signalStrength) {
    188             int prevSignal = mSignal;
    189             if (signalStrength.isGsm()) {
    190                 mSignal = gsmAsuToSignal(signalStrength);
    191             } else {
    192                 mSignal = cdmaDbmEcioToSignal(signalStrength);
    193             }
    194             // network signal strength is scaled to BT 1-5 levels.
    195             // This results in a lot of duplicate messages, hence this check
    196             if (prevSignal != mSignal)
    197                 sendDeviceStateChanged();
    198         }
    199 
    200         /* convert [0,31] ASU signal strength to the [0,5] expected by
    201          * bluetooth devices. Scale is similar to status bar policy
    202          */
    203         private int gsmAsuToSignal(SignalStrength signalStrength) {
    204             int asu = signalStrength.getGsmSignalStrength();
    205             if      (asu >= 16) return 5;
    206             else if (asu >= 8)  return 4;
    207             else if (asu >= 4)  return 3;
    208             else if (asu >= 2)  return 2;
    209             else if (asu >= 1)  return 1;
    210             else                return 0;
    211         }
    212 
    213         /**
    214          * Convert the cdma / evdo db levels to appropriate icon level.
    215          * The scale is similar to the one used in status bar policy.
    216          *
    217          * @param signalStrength
    218          * @return the icon level
    219          */
    220         private int cdmaDbmEcioToSignal(SignalStrength signalStrength) {
    221             int levelDbm = 0;
    222             int levelEcio = 0;
    223             int cdmaIconLevel = 0;
    224             int evdoIconLevel = 0;
    225             int cdmaDbm = signalStrength.getCdmaDbm();
    226             int cdmaEcio = signalStrength.getCdmaEcio();
    227 
    228             if (cdmaDbm >= -75) levelDbm = 4;
    229             else if (cdmaDbm >= -85) levelDbm = 3;
    230             else if (cdmaDbm >= -95) levelDbm = 2;
    231             else if (cdmaDbm >= -100) levelDbm = 1;
    232             else levelDbm = 0;
    233 
    234             // Ec/Io are in dB*10
    235             if (cdmaEcio >= -90) levelEcio = 4;
    236             else if (cdmaEcio >= -110) levelEcio = 3;
    237             else if (cdmaEcio >= -130) levelEcio = 2;
    238             else if (cdmaEcio >= -150) levelEcio = 1;
    239             else levelEcio = 0;
    240 
    241             cdmaIconLevel = (levelDbm < levelEcio) ? levelDbm : levelEcio;
    242 
    243             // STOPSHIP: Change back to getRilVoiceRadioTechnology
    244             if (mServiceState != null &&
    245                   (mServiceState.getRadioTechnology() ==
    246                       ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_0 ||
    247                    mServiceState.getRadioTechnology() ==
    248                        ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_A)) {
    249                   int evdoEcio = signalStrength.getEvdoEcio();
    250                   int evdoSnr = signalStrength.getEvdoSnr();
    251                   int levelEvdoEcio = 0;
    252                   int levelEvdoSnr = 0;
    253 
    254                   // Ec/Io are in dB*10
    255                   if (evdoEcio >= -650) levelEvdoEcio = 4;
    256                   else if (evdoEcio >= -750) levelEvdoEcio = 3;
    257                   else if (evdoEcio >= -900) levelEvdoEcio = 2;
    258                   else if (evdoEcio >= -1050) levelEvdoEcio = 1;
    259                   else levelEvdoEcio = 0;
    260 
    261                   if (evdoSnr > 7) levelEvdoSnr = 4;
    262                   else if (evdoSnr > 5) levelEvdoSnr = 3;
    263                   else if (evdoSnr > 3) levelEvdoSnr = 2;
    264                   else if (evdoSnr > 1) levelEvdoSnr = 1;
    265                   else levelEvdoSnr = 0;
    266 
    267                   evdoIconLevel = (levelEvdoEcio < levelEvdoSnr) ? levelEvdoEcio : levelEvdoSnr;
    268             }
    269             // TODO(): There is a bug open regarding what should be sent.
    270             return (cdmaIconLevel > evdoIconLevel) ?  cdmaIconLevel : evdoIconLevel;
    271         }
    272     };
    273 
    274 }
    275 
    276 class HeadsetDeviceState {
    277     int mService;
    278     int mRoam;
    279     int mSignal;
    280     int mBatteryCharge;
    281 
    282     HeadsetDeviceState(int service, int roam, int signal, int batteryCharge) {
    283         mService = service;
    284         mRoam = roam;
    285         mSignal = signal;
    286         mBatteryCharge = batteryCharge;
    287     }
    288 }
    289 
    290 class HeadsetCallState {
    291     int mNumActive;
    292     int mNumHeld;
    293     int mCallState;
    294     String mNumber;
    295     int mType;
    296 
    297     public HeadsetCallState(int numActive, int numHeld, int callState, String number, int type) {
    298         mNumActive = numActive;
    299         mNumHeld = numHeld;
    300         mCallState = callState;
    301         mNumber = number;
    302         mType = type;
    303     }
    304 }
    305 
    306 class HeadsetClccResponse {
    307     int mIndex;
    308     int mDirection;
    309     int mStatus;
    310     int mMode;
    311     boolean mMpty;
    312     String mNumber;
    313     int mType;
    314 
    315     public HeadsetClccResponse(int index, int direction, int status, int mode, boolean mpty,
    316                                String number, int type) {
    317         mIndex = index;
    318         mDirection = direction;
    319         mStatus = status;
    320         mMode = mode;
    321         mMpty = mpty;
    322         mNumber = number;
    323         mType = type;
    324     }
    325 }
    326 
    327 class HeadsetVendorSpecificResultCode {
    328     String mCommand;
    329     String mArg;
    330 
    331     public HeadsetVendorSpecificResultCode(String command, String arg) {
    332         mCommand = command;
    333         mArg = arg;
    334     }
    335 }
    336