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