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