HeadsetPhoneState.java revision cdc8ec8d84c7f16b851238da0d80b51335c4ea07
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
17package com.android.bluetooth.hfp;
18
19import android.content.Context;
20import android.telephony.PhoneStateListener;
21import android.telephony.ServiceState;
22import android.telephony.SignalStrength;
23import android.telephony.TelephonyManager;
24import 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.
30class 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
276class 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
290class 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
306class 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
327class HeadsetVendorSpecificResultCode {
328    String mCommand;
329    String mArg;
330
331    public HeadsetVendorSpecificResultCode(String command, String arg) {
332        mCommand = command;
333        mArg = arg;
334    }
335}
336