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