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