StatusBarPolicy.java revision 347c5a22a915df5aa180573573adf6b2213a35dc
1/*
2 * Copyright (C) 2008 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.server.status;
18
19import android.app.AlertDialog;
20import android.bluetooth.BluetoothA2dp;
21import android.bluetooth.BluetoothAdapter;
22import android.bluetooth.BluetoothError;
23import android.bluetooth.BluetoothHeadset;
24import android.bluetooth.BluetoothIntent;
25import android.bluetooth.BluetoothPbap;
26import android.content.BroadcastReceiver;
27import android.content.Context;
28import android.content.DialogInterface;
29import android.content.Intent;
30import android.content.IntentFilter;
31import android.content.res.TypedArray;
32import android.graphics.PixelFormat;
33import android.graphics.drawable.Drawable;
34import android.media.AudioManager;
35import android.net.NetworkInfo;
36import android.net.wifi.WifiManager;
37import android.os.Binder;
38import android.os.Handler;
39import android.os.IBinder;
40import android.os.Message;
41import android.os.RemoteException;
42import android.provider.Settings;
43import android.telephony.PhoneStateListener;
44import android.telephony.ServiceState;
45import android.telephony.SignalStrength;
46import android.telephony.TelephonyManager;
47import android.text.format.DateFormat;
48import android.util.Log;
49import android.view.View;
50import android.view.ViewGroup;
51import android.view.WindowManager;
52import android.view.WindowManagerImpl;
53import android.widget.ImageView;
54import android.widget.LinearLayout;
55import android.widget.TextView;
56
57import com.android.internal.R;
58import com.android.internal.app.IBatteryStats;
59import com.android.internal.location.GpsLocationProvider;
60import com.android.internal.telephony.IccCard;
61import com.android.internal.telephony.TelephonyIntents;
62import com.android.internal.telephony.cdma.EriInfo;
63import com.android.internal.telephony.cdma.TtyIntent;
64import com.android.server.am.BatteryStatsService;
65
66import java.util.Calendar;
67import java.util.TimeZone;
68
69/**
70 * This class contains all of the policy about which icons are installed in the status
71 * bar at boot time.  In reality, it should go into the android.policy package, but
72 * putting it here is the first step from extracting it.
73 */
74public class StatusBarPolicy {
75    private static final String TAG = "StatusBarPolicy";
76
77    private static StatusBarPolicy sInstance;
78
79    // message codes for the handler
80    private static final int EVENT_BATTERY_CLOSE = 4;
81
82    private final Context mContext;
83    private final StatusBarService mService;
84    private final Handler mHandler = new StatusBarHandler();
85    private final IBatteryStats mBatteryStats;
86
87    // clock
88    private Calendar mCalendar;
89    private IBinder mClockIcon;
90    private IconData mClockData;
91
92    // battery
93    private IBinder mBatteryIcon;
94    private IconData mBatteryData;
95    private boolean mBatteryFirst = true;
96    private boolean mBatteryPlugged;
97    private int mBatteryLevel;
98    private AlertDialog mLowBatteryDialog;
99    private TextView mBatteryLevelTextView;
100    private View mBatteryView;
101    private int mBatteryViewSequence;
102    private boolean mBatteryShowLowOnEndCall = false;
103    private static final boolean SHOW_LOW_BATTERY_WARNING = true;
104
105    // phone
106    private TelephonyManager mPhone;
107    private IBinder mPhoneIcon;
108
109    //***** Signal strength icons
110    private IconData mPhoneData;
111    //GSM/UMTS
112    private static final int[] sSignalImages = new int[] {
113        com.android.internal.R.drawable.stat_sys_signal_0,
114        com.android.internal.R.drawable.stat_sys_signal_1,
115        com.android.internal.R.drawable.stat_sys_signal_2,
116        com.android.internal.R.drawable.stat_sys_signal_3,
117        com.android.internal.R.drawable.stat_sys_signal_4
118    };
119    private static final int[] sSignalImages_r = new int[] {
120        com.android.internal.R.drawable.stat_sys_r_signal_0,
121        com.android.internal.R.drawable.stat_sys_r_signal_1,
122        com.android.internal.R.drawable.stat_sys_r_signal_2,
123        com.android.internal.R.drawable.stat_sys_r_signal_3,
124        com.android.internal.R.drawable.stat_sys_r_signal_4
125    };
126    private static final int[] sRoamingIndicatorImages_cdma = new int[] {
127        com.android.internal.R.drawable.stat_sys_roaming_cdma_0, //Standard Roaming Indicator
128        // 1 is Standard Roaming Indicator OFF
129        // TODO T: image never used, remove and put 0 instead?
130        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
131
132        // 2 is Standard Roaming Indicator FLASHING
133        // TODO T: image never used, remove and put 0 instead?
134        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
135
136        // 3-12 Standard ERI
137        com.android.internal.R.drawable.stat_sys_roaming_cdma_0, //3
138        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
139        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
140        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
141        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
142        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
143        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
144        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
145        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
146        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
147
148        // 13-63 Reserved for Standard ERI
149        com.android.internal.R.drawable.stat_sys_roaming_cdma_0, //13
150        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
151        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
152        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
153        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
154        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
155        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
156        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
157        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
158        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
159        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
160        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
161        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
162        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
163        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
164        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
165        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
166        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
167        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
168        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
169        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
170        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
171        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
172        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
173        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
174        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
175        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
176        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
177        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
178        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
179        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
180        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
181        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
182        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
183        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
184        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
185        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
186        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
187        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
188        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
189        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
190        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
191        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
192        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
193        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
194        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
195        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
196        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
197        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
198        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
199        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
200
201        // 64-127 Reserved for Non Standard (Operator Specific) ERI
202        com.android.internal.R.drawable.stat_sys_roaming_cdma_0, //64
203        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
204        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
205        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
206        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
207        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
208        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
209        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
210        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
211        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
212        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
213        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
214        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
215        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
216        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
217        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
218        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
219        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
220        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
221        com.android.internal.R.drawable.stat_sys_roaming_cdma_0 //83
222
223        // 128-255 Reserved
224    };
225
226    //***** Data connection icons
227    private int[] mDataIconList = sDataNetType_g;
228    //GSM/UMTS
229    private static final int[] sDataNetType_g = new int[] {
230            com.android.internal.R.drawable.stat_sys_data_connected_g,
231            com.android.internal.R.drawable.stat_sys_data_in_g,
232            com.android.internal.R.drawable.stat_sys_data_out_g,
233            com.android.internal.R.drawable.stat_sys_data_inandout_g,
234        };
235    private static final int[] sDataNetType_3g = new int[] {
236            com.android.internal.R.drawable.stat_sys_data_connected_3g,
237            com.android.internal.R.drawable.stat_sys_data_in_3g,
238            com.android.internal.R.drawable.stat_sys_data_out_3g,
239            com.android.internal.R.drawable.stat_sys_data_inandout_3g,
240        };
241    private static final int[] sDataNetType_e = new int[] {
242            com.android.internal.R.drawable.stat_sys_data_connected_e,
243            com.android.internal.R.drawable.stat_sys_data_in_e,
244            com.android.internal.R.drawable.stat_sys_data_out_e,
245            com.android.internal.R.drawable.stat_sys_data_inandout_e,
246        };
247    //3.5G
248    private static final int[] sDataNetType_h = new int[] {
249            com.android.internal.R.drawable.stat_sys_data_connected_h,
250            com.android.internal.R.drawable.stat_sys_data_in_h,
251            com.android.internal.R.drawable.stat_sys_data_out_h,
252            com.android.internal.R.drawable.stat_sys_data_inandout_h,
253    };
254
255    //CDMA
256    private static final int[] sDataNetType_evdo = new int[] {
257        com.android.internal.R.drawable.stat_sys_data_connected_evdo,
258        com.android.internal.R.drawable.stat_sys_data_in_evdo,
259        com.android.internal.R.drawable.stat_sys_data_out_evdo,
260        com.android.internal.R.drawable.stat_sys_data_inandout_evdo,
261        com.android.internal.R.drawable.stat_sys_data_dormant_evdo,
262    };
263    private static final int[] sDataNetType_1xrtt = new int[] {
264        com.android.internal.R.drawable.stat_sys_data_connected_1xrtt,
265        com.android.internal.R.drawable.stat_sys_data_in_1xrtt,
266        com.android.internal.R.drawable.stat_sys_data_out_1xrtt,
267        com.android.internal.R.drawable.stat_sys_data_inandout_1xrtt,
268        com.android.internal.R.drawable.stat_sys_data_dormant_1xrtt,
269    };
270
271    // Assume it's all good unless we hear otherwise.  We don't always seem
272    // to get broadcasts that it *is* there.
273    IccCard.State mSimState = IccCard.State.READY;
274    int mPhoneState = TelephonyManager.CALL_STATE_IDLE;
275    int mDataState = TelephonyManager.DATA_DISCONNECTED;
276    int mDataActivity = TelephonyManager.DATA_ACTIVITY_NONE;
277    ServiceState mServiceState;
278    SignalStrength mSignalStrength;
279
280    // data connection
281    private IBinder mDataIcon;
282    private IconData mDataData;
283    private boolean mDataIconVisible;
284
285    // ringer volume
286    private IBinder mVolumeIcon;
287    private IconData mVolumeData;
288    private boolean mVolumeVisible;
289
290    // bluetooth device status
291    private IBinder mBluetoothIcon;
292    private IconData mBluetoothData;
293    private int mBluetoothHeadsetState;
294    private int mBluetoothA2dpState;
295    private int mBluetoothPbapState;
296    private boolean mBluetoothEnabled;
297
298    // wifi
299    private static final int[] sWifiSignalImages = new int[] {
300            com.android.internal.R.drawable.stat_sys_wifi_signal_1,
301            com.android.internal.R.drawable.stat_sys_wifi_signal_2,
302            com.android.internal.R.drawable.stat_sys_wifi_signal_3,
303            com.android.internal.R.drawable.stat_sys_wifi_signal_4,
304        };
305    private static final int sWifiTemporarilyNotConnectedImage =
306            com.android.internal.R.drawable.stat_sys_wifi_signal_0;
307
308    private int mLastWifiSignalLevel = -1;
309    private boolean mIsWifiConnected = false;
310    private IBinder mWifiIcon;
311    private IconData mWifiData;
312
313    // gps
314    private IBinder mGpsIcon;
315    private IconData mGpsEnabledIconData;
316    private IconData mGpsFixIconData;
317
318    // alarm clock
319    // Icon lit when clock is set
320    private IBinder mAlarmClockIcon;
321    private IconData mAlarmClockIconData;
322
323    // sync state
324    // If sync is active the SyncActive icon is displayed. If sync is not active but
325    // sync is failing the SyncFailing icon is displayed. Otherwise neither are displayed.
326    private IBinder mSyncActiveIcon;
327    private IBinder mSyncFailingIcon;
328
329    // TTY mode
330    // Icon lit when TTY mode is enabled
331    private IBinder mTTYModeIcon;
332    private IconData mTTYModeEnableIconData;
333
334    // Cdma Roaming Indicator, ERI
335    private IBinder mCdmaRoamingIndicatorIcon;
336    private IconData mCdmaRoamingIndicatorIconData;
337
338    private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
339        @Override
340        public void onReceive(Context context, Intent intent) {
341            String action = intent.getAction();
342            if (action.equals(Intent.ACTION_TIME_TICK)) {
343                updateClock();
344            }
345            else if (action.equals(Intent.ACTION_TIME_CHANGED)) {
346                updateClock();
347            }
348            else if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
349                updateBattery(intent);
350            }
351            else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
352                updateClock();
353            }
354            else if (action.equals(Intent.ACTION_TIMEZONE_CHANGED)) {
355                String tz = intent.getStringExtra("time-zone");
356                mCalendar = Calendar.getInstance(TimeZone.getTimeZone(tz));
357                updateClock();
358            }
359            else if (action.equals(Intent.ACTION_ALARM_CHANGED)) {
360                updateAlarm(intent);
361            }
362            else if (action.equals(Intent.ACTION_SYNC_STATE_CHANGED)) {
363                updateSyncState(intent);
364            }
365            else if (action.equals(Intent.ACTION_BATTERY_LOW)) {
366                onBatteryLow(intent);
367            }
368            else if (action.equals(Intent.ACTION_BATTERY_OKAY)
369                    || action.equals(Intent.ACTION_POWER_CONNECTED)) {
370                onBatteryOkay(intent);
371            }
372            else if (action.equals(BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION) ||
373                    action.equals(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION) ||
374                    action.equals(BluetoothA2dp.SINK_STATE_CHANGED_ACTION) ||
375                    action.equals(BluetoothPbap.PBAP_STATE_CHANGED_ACTION)) {
376                updateBluetooth(intent);
377            }
378            else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION) ||
379                    action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION) ||
380                    action.equals(WifiManager.RSSI_CHANGED_ACTION)) {
381                updateWifi(intent);
382            }
383            else if (action.equals(GpsLocationProvider.GPS_ENABLED_CHANGE_ACTION) ||
384                    action.equals(GpsLocationProvider.GPS_FIX_CHANGE_ACTION)) {
385                updateGps(intent);
386            }
387            else if (action.equals(AudioManager.RINGER_MODE_CHANGED_ACTION) ||
388                    action.equals(AudioManager.VIBRATE_SETTING_CHANGED_ACTION)) {
389                updateVolume();
390            }
391            else if (action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) {
392                updateSimState(intent);
393            }
394            else if (action.equals(TtyIntent.TTY_ENABLED_CHANGE_ACTION)) {
395                updateTTY(intent);
396            }
397        }
398    };
399
400    private StatusBarPolicy(Context context, StatusBarService service) {
401        mContext = context;
402        mService = service;
403        mSignalStrength = new SignalStrength();
404        mBatteryStats = BatteryStatsService.getService();
405
406        // clock
407        mCalendar = Calendar.getInstance(TimeZone.getDefault());
408        mClockData = IconData.makeText("clock", "");
409        mClockIcon = service.addIcon(mClockData, null);
410        updateClock();
411
412        // battery
413        mBatteryData = IconData.makeIcon("battery",
414                null, com.android.internal.R.drawable.stat_sys_battery_unknown, 0, 0);
415        mBatteryIcon = service.addIcon(mBatteryData, null);
416
417        // phone_signal
418        mPhone = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
419        mPhoneData = IconData.makeIcon("phone_signal",
420                null, com.android.internal.R.drawable.stat_sys_signal_null, 0, 0);
421        mPhoneIcon = service.addIcon(mPhoneData, null);
422
423        // register for phone state notifications.
424        ((TelephonyManager)mContext.getSystemService(Context.TELEPHONY_SERVICE))
425                .listen(mPhoneStateListener,
426                          PhoneStateListener.LISTEN_SERVICE_STATE
427                        | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS
428                        | PhoneStateListener.LISTEN_CALL_STATE
429                        | PhoneStateListener.LISTEN_DATA_CONNECTION_STATE
430                        | PhoneStateListener.LISTEN_DATA_ACTIVITY);
431
432        // data_connection
433        mDataData = IconData.makeIcon("data_connection",
434                null, com.android.internal.R.drawable.stat_sys_data_connected_g, 0, 0);
435        mDataIcon = service.addIcon(mDataData, null);
436        service.setIconVisibility(mDataIcon, false);
437
438        // wifi
439        mWifiData = IconData.makeIcon("wifi", null, sWifiSignalImages[0], 0, 0);
440        mWifiIcon = service.addIcon(mWifiData, null);
441        service.setIconVisibility(mWifiIcon, false);
442        // wifi will get updated by the sticky intents
443
444        // TTY status
445        mTTYModeEnableIconData = IconData.makeIcon("tty",
446                null, com.android.internal.R.drawable.stat_sys_tty_mode, 0, 0);
447        mTTYModeIcon = service.addIcon(mTTYModeEnableIconData, null);
448        service.setIconVisibility(mTTYModeIcon, false);
449
450        // Cdma Roaming Indicator, ERI
451        mCdmaRoamingIndicatorIconData = IconData.makeIcon("cdma_eri",
452                null, com.android.internal.R.drawable.stat_sys_roaming_cdma_0, 0, 0);
453        mCdmaRoamingIndicatorIcon = service.addIcon(mCdmaRoamingIndicatorIconData, null);
454        service.setIconVisibility(mCdmaRoamingIndicatorIcon, false);
455
456        // bluetooth status
457        mBluetoothData = IconData.makeIcon("bluetooth",
458                null, com.android.internal.R.drawable.stat_sys_data_bluetooth, 0, 0);
459        mBluetoothIcon = service.addIcon(mBluetoothData, null);
460        BluetoothAdapter adapter =
461                (BluetoothAdapter) mContext.getSystemService(Context.BLUETOOTH_SERVICE);
462        if (adapter != null) {
463            mBluetoothEnabled = adapter.isEnabled();
464        } else {
465            mBluetoothEnabled = false;
466        }
467        mBluetoothA2dpState = BluetoothA2dp.STATE_DISCONNECTED;
468        mBluetoothHeadsetState = BluetoothHeadset.STATE_DISCONNECTED;
469        mBluetoothPbapState = BluetoothPbap.STATE_DISCONNECTED;
470        mService.setIconVisibility(mBluetoothIcon, mBluetoothEnabled);
471
472        // Gps status
473        mGpsEnabledIconData = IconData.makeIcon("gps",
474                null, com.android.internal.R.drawable.stat_sys_gps_acquiring_anim, 0, 0);
475        mGpsFixIconData = IconData.makeIcon("gps",
476                null, com.android.internal.R.drawable.stat_sys_gps_on, 0, 0);
477        mGpsIcon = service.addIcon(mGpsEnabledIconData, null);
478        service.setIconVisibility(mGpsIcon, false);
479
480        // Alarm clock
481        mAlarmClockIconData = IconData.makeIcon(
482                "alarm_clock",
483                null, com.android.internal.R.drawable.stat_notify_alarm, 0, 0);
484        mAlarmClockIcon = service.addIcon(mAlarmClockIconData, null);
485        service.setIconVisibility(mAlarmClockIcon, false);
486
487        // Sync state
488        mSyncActiveIcon = service.addIcon(IconData.makeIcon("sync_active",
489                null, R.drawable.stat_notify_sync_anim0, 0, 0), null);
490        mSyncFailingIcon = service.addIcon(IconData.makeIcon("sync_failing",
491                null, R.drawable.stat_notify_sync_error, 0, 0), null);
492        service.setIconVisibility(mSyncActiveIcon, false);
493        service.setIconVisibility(mSyncFailingIcon, false);
494
495        // volume
496        mVolumeData = IconData.makeIcon("volume",
497                null, com.android.internal.R.drawable.stat_sys_ringer_silent, 0, 0);
498        mVolumeIcon = service.addIcon(mVolumeData, null);
499        service.setIconVisibility(mVolumeIcon, false);
500        updateVolume();
501
502        IntentFilter filter = new IntentFilter();
503
504        // Register for Intent broadcasts for...
505        filter.addAction(Intent.ACTION_TIME_TICK);
506        filter.addAction(Intent.ACTION_TIME_CHANGED);
507        filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
508        filter.addAction(Intent.ACTION_BATTERY_CHANGED);
509        filter.addAction(Intent.ACTION_BATTERY_LOW);
510        filter.addAction(Intent.ACTION_BATTERY_OKAY);
511        filter.addAction(Intent.ACTION_POWER_CONNECTED);
512        filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
513        filter.addAction(Intent.ACTION_ALARM_CHANGED);
514        filter.addAction(Intent.ACTION_SYNC_STATE_CHANGED);
515        filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
516        filter.addAction(AudioManager.VIBRATE_SETTING_CHANGED_ACTION);
517        filter.addAction(BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION);
518        filter.addAction(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION);
519        filter.addAction(BluetoothA2dp.SINK_STATE_CHANGED_ACTION);
520        filter.addAction(BluetoothPbap.PBAP_STATE_CHANGED_ACTION);
521        filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
522        filter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
523        filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
524        filter.addAction(WifiManager.RSSI_CHANGED_ACTION);
525        filter.addAction(GpsLocationProvider.GPS_ENABLED_CHANGE_ACTION);
526        filter.addAction(GpsLocationProvider.GPS_FIX_CHANGE_ACTION);
527        filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
528        filter.addAction(TtyIntent.TTY_ENABLED_CHANGE_ACTION);
529        mContext.registerReceiver(mIntentReceiver, filter, null, mHandler);
530    }
531
532    public static void installIcons(Context context, StatusBarService service) {
533        sInstance = new StatusBarPolicy(context, service);
534    }
535
536    private final void updateClock() {
537        mCalendar.setTimeInMillis(System.currentTimeMillis());
538        mClockData.text = DateFormat.getTimeFormat(mContext)
539                .format(mCalendar.getTime());
540        mService.updateIcon(mClockIcon, mClockData, null);
541    }
542
543    private final void updateAlarm(Intent intent) {
544        boolean alarmSet = intent.getBooleanExtra("alarmSet", false);
545        mService.setIconVisibility(mAlarmClockIcon, alarmSet);
546    }
547
548    private final void updateSyncState(Intent intent) {
549        boolean isActive = intent.getBooleanExtra("active", false);
550        boolean isFailing = intent.getBooleanExtra("failing", false);
551        mService.setIconVisibility(mSyncActiveIcon, isActive);
552        // Don't display sync failing icon: BUG 1297963 Set sync error timeout to "never"
553        //mService.setIconVisibility(mSyncFailingIcon, isFailing && !isActive);
554    }
555
556    private final void updateBattery(Intent intent) {
557        mBatteryData.iconId = intent.getIntExtra("icon-small", 0);
558        mBatteryData.iconLevel = intent.getIntExtra("level", 0);
559        mService.updateIcon(mBatteryIcon, mBatteryData, null);
560
561        boolean plugged = intent.getIntExtra("plugged", 0) != 0;
562        int level = intent.getIntExtra("level", -1);
563        if (false) {
564            Log.d(TAG, "updateBattery level=" + level
565                    + " plugged=" + plugged
566                    + " mBatteryPlugged=" + mBatteryPlugged
567                    + " mBatteryLevel=" + mBatteryLevel
568                    + " mBatteryFirst=" + mBatteryFirst);
569        }
570
571        boolean oldPlugged = mBatteryPlugged;
572
573        mBatteryPlugged = plugged;
574        mBatteryLevel = level;
575
576        if (mBatteryFirst) {
577            mBatteryFirst = false;
578        }
579        /*
580         * No longer showing the battery view because it draws attention away
581         * from the USB storage notification. We could still show it when
582         * connected to a brick, but that could lead to the user into thinking
583         * the device does not charge when plugged into USB (since he/she would
584         * not see the same battery screen on USB as he sees on brick).
585         */
586        /* else {
587            if (plugged && !oldPlugged) {
588                showBatteryView();
589            }
590        }
591        */
592        if (false) {
593            Log.d(TAG, "plugged=" + plugged + " oldPlugged=" + oldPlugged + " level=" + level);
594        }
595    }
596
597    private void onBatteryLow(Intent intent) {
598        if (SHOW_LOW_BATTERY_WARNING) {
599            if (false) {
600                Log.d(TAG, "mPhoneState=" + mPhoneState
601                      + " mLowBatteryDialog=" + mLowBatteryDialog
602                      + " mBatteryShowLowOnEndCall=" + mBatteryShowLowOnEndCall);
603            }
604
605            if (mPhoneState == TelephonyManager.CALL_STATE_IDLE) {
606                showLowBatteryWarning();
607            } else {
608                mBatteryShowLowOnEndCall = true;
609            }
610        }
611    }
612
613    private void onBatteryOkay(Intent intent) {
614        if (mLowBatteryDialog != null
615                && SHOW_LOW_BATTERY_WARNING) {
616            mLowBatteryDialog.dismiss();
617            mBatteryShowLowOnEndCall = false;
618        }
619    }
620
621    private void showBatteryView() {
622        closeLastBatteryView();
623        if (mLowBatteryDialog != null) {
624            mLowBatteryDialog.dismiss();
625        }
626
627        int level = mBatteryLevel;
628
629        View v = View.inflate(mContext, com.android.internal.R.layout.battery_status, null);
630        mBatteryView = v;
631        int pixelFormat = PixelFormat.TRANSLUCENT;
632        Drawable bg = v.getBackground();
633        if (bg != null) {
634            pixelFormat = bg.getOpacity();
635        }
636
637        WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
638                ViewGroup.LayoutParams.WRAP_CONTENT,
639                ViewGroup.LayoutParams.WRAP_CONTENT,
640                WindowManager.LayoutParams.TYPE_TOAST,
641                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
642                    | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
643                    | WindowManager.LayoutParams.FLAG_BLUR_BEHIND
644                    | WindowManager.LayoutParams.FLAG_DIM_BEHIND,
645                pixelFormat);
646
647        // Get the dim amount from the theme
648        TypedArray a = mContext.obtainStyledAttributes(
649                com.android.internal.R.styleable.Theme);
650        lp.dimAmount = a.getFloat(android.R.styleable.Theme_backgroundDimAmount, 0.5f);
651        a.recycle();
652
653        lp.setTitle("Battery");
654
655        TextView levelTextView = (TextView)v.findViewById(com.android.internal.R.id.level_percent);
656        levelTextView.setText(mContext.getString(
657                    com.android.internal.R.string.battery_status_text_percent_format, level));
658
659        setBatteryLevel(v, com.android.internal.R.id.spacer, 100-level, 0, 0);
660        setBatteryLevel(v, com.android.internal.R.id.level, level,
661                com.android.internal.R.drawable.battery_charge_fill, level);
662
663        WindowManagerImpl.getDefault().addView(v, lp);
664
665        scheduleCloseBatteryView();
666    }
667
668    private void setBatteryLevel(View parent, int id, int height, int background, int level) {
669        ImageView v = (ImageView)parent.findViewById(id);
670        LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)v.getLayoutParams();
671        lp.weight = height;
672        if (background != 0) {
673            v.setBackgroundResource(background);
674            Drawable bkg = v.getBackground();
675            bkg.setLevel(level);
676        }
677    }
678
679    private void showLowBatteryWarning() {
680        closeLastBatteryView();
681
682        /* Show exact battery level.
683         * Add 1 because the text says "less than X%".
684         */
685        CharSequence levelText = mContext.getString(
686                    com.android.internal.R.string.battery_low_percent_format, mBatteryLevel + 1);
687
688        if (mBatteryLevelTextView != null) {
689            mBatteryLevelTextView.setText(levelText);
690        } else {
691            View v = View.inflate(mContext, com.android.internal.R.layout.battery_low, null);
692            mBatteryLevelTextView=(TextView)v.findViewById(com.android.internal.R.id.level_percent);
693
694            mBatteryLevelTextView.setText(levelText);
695
696            AlertDialog.Builder b = new AlertDialog.Builder(mContext);
697                b.setCancelable(true);
698                b.setTitle(com.android.internal.R.string.battery_low_title);
699                b.setView(v);
700                b.setIcon(android.R.drawable.ic_dialog_alert);
701                b.setPositiveButton(android.R.string.ok, null);
702
703                final Intent intent = new Intent(Intent.ACTION_POWER_USAGE_SUMMARY);
704                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
705                        | Intent.FLAG_ACTIVITY_MULTIPLE_TASK
706                        | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
707                        | Intent.FLAG_ACTIVITY_NO_HISTORY);
708                if (intent.resolveActivity(mContext.getPackageManager()) != null) {
709                    b.setNegativeButton(com.android.internal.R.string.battery_low_why,
710                            new DialogInterface.OnClickListener() {
711                        public void onClick(DialogInterface dialog, int which) {
712                            mContext.startActivity(intent);
713                            if (mLowBatteryDialog != null) {
714                                mLowBatteryDialog.dismiss();
715                            }
716                        }
717                    });
718                }
719
720            AlertDialog d = b.create();
721            d.setOnDismissListener(mLowBatteryListener);
722            d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
723            d.show();
724            mLowBatteryDialog = d;
725        }
726    }
727
728    private final void updateCallState(int state) {
729        mPhoneState = state;
730        if (false) {
731            Log.d(TAG, "mPhoneState=" + mPhoneState
732                    + " mLowBatteryDialog=" + mLowBatteryDialog
733                    + " mBatteryShowLowOnEndCall=" + mBatteryShowLowOnEndCall);
734        }
735        if (mPhoneState == TelephonyManager.CALL_STATE_IDLE) {
736            if (mBatteryShowLowOnEndCall) {
737                if (!mBatteryPlugged) {
738                    showLowBatteryWarning();
739                }
740                mBatteryShowLowOnEndCall = false;
741            }
742        } else {
743            if (mLowBatteryDialog != null) {
744                mLowBatteryDialog.dismiss();
745                mBatteryShowLowOnEndCall = true;
746            }
747        }
748    }
749
750    private DialogInterface.OnDismissListener mLowBatteryListener
751            = new DialogInterface.OnDismissListener() {
752        public void onDismiss(DialogInterface dialog) {
753            mLowBatteryDialog = null;
754            mBatteryLevelTextView = null;
755        }
756    };
757
758    private void scheduleCloseBatteryView() {
759        Message m = mHandler.obtainMessage(EVENT_BATTERY_CLOSE);
760        m.arg1 = (++mBatteryViewSequence);
761        mHandler.sendMessageDelayed(m, 3000);
762    }
763
764    private void closeLastBatteryView() {
765        if (mBatteryView != null) {
766            //mBatteryView.debug();
767            WindowManagerImpl.getDefault().removeView(mBatteryView);
768            mBatteryView = null;
769        }
770    }
771
772    private PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
773        @Override
774        public void onSignalStrengthsChanged(SignalStrength signalStrength) {
775            mSignalStrength = signalStrength;
776            updateSignalStrength();
777        }
778
779        @Override
780        public void onServiceStateChanged(ServiceState state) {
781            mServiceState = state;
782            updateSignalStrength();
783            updateCdmaRoamingIcon();
784            updateDataIcon();
785        }
786
787        @Override
788        public void onCallStateChanged(int state, String incomingNumber) {
789            updateCallState(state);
790            // In cdma, if a voice call is made, RSSI should switch to 1x.
791            if (isCdma()) {
792                updateSignalStrength();
793            }
794        }
795
796        @Override
797        public void onDataConnectionStateChanged(int state) {
798            mDataState = state;
799            updateDataNetType();
800            updateDataIcon();
801        }
802
803        @Override
804        public void onDataActivity(int direction) {
805            mDataActivity = direction;
806            updateDataIcon();
807        }
808    };
809
810    private final void updateSimState(Intent intent) {
811        String stateExtra = intent.getStringExtra(IccCard.INTENT_KEY_ICC_STATE);
812        if (IccCard.INTENT_VALUE_ICC_ABSENT.equals(stateExtra)) {
813            mSimState = IccCard.State.ABSENT;
814        }
815        else if (IccCard.INTENT_VALUE_ICC_READY.equals(stateExtra)) {
816            mSimState = IccCard.State.READY;
817        }
818        else if (IccCard.INTENT_VALUE_ICC_LOCKED.equals(stateExtra)) {
819            final String lockedReason = intent.getStringExtra(IccCard.INTENT_KEY_LOCKED_REASON);
820            if (IccCard.INTENT_VALUE_LOCKED_ON_PIN.equals(lockedReason)) {
821                mSimState = IccCard.State.PIN_REQUIRED;
822            }
823            else if (IccCard.INTENT_VALUE_LOCKED_ON_PUK.equals(lockedReason)) {
824                mSimState = IccCard.State.PUK_REQUIRED;
825            }
826            else {
827                mSimState = IccCard.State.NETWORK_LOCKED;
828            }
829        } else {
830            mSimState = IccCard.State.UNKNOWN;
831        }
832        updateDataIcon();
833    }
834
835    private boolean isCdma() {
836        return ((mPhone != null) && (mPhone.getPhoneType() == TelephonyManager.PHONE_TYPE_CDMA));
837    }
838
839    private boolean isEvdo() {
840        return ( (mServiceState != null)
841                 && ((mServiceState.getRadioTechnology()
842                        == ServiceState.RADIO_TECHNOLOGY_EVDO_0)
843                     || (mServiceState.getRadioTechnology()
844                        == ServiceState.RADIO_TECHNOLOGY_EVDO_A)));
845    }
846
847    private boolean hasService() {
848        if (mServiceState != null) {
849            switch (mServiceState.getState()) {
850                case ServiceState.STATE_OUT_OF_SERVICE:
851                case ServiceState.STATE_POWER_OFF:
852                    return false;
853                default:
854                    return true;
855            }
856        } else {
857            return false;
858        }
859    }
860
861    private final void updateSignalStrength() {
862        int iconLevel = -1;
863        int[] iconList;
864
865        if (!hasService()) {
866            //Log.d(TAG, "updateSignalStrength: no service");
867            if (Settings.System.getInt(mContext.getContentResolver(),
868                    Settings.System.AIRPLANE_MODE_ON, 0) == 1) {
869                mPhoneData.iconId = com.android.internal.R.drawable.stat_sys_signal_flightmode;
870            } else {
871                mPhoneData.iconId = com.android.internal.R.drawable.stat_sys_signal_null;
872            }
873            mService.updateIcon(mPhoneIcon, mPhoneData, null);
874            return;
875        }
876
877        if (!isCdma()) {
878            int asu = mSignalStrength.getGsmSignalStrength();
879
880            // ASU ranges from 0 to 31 - TS 27.007 Sec 8.5
881            // asu = 0 (-113dB or less) is very weak
882            // signal, its better to show 0 bars to the user in such cases.
883            // asu = 99 is a special case, where the signal strength is unknown.
884            if (asu <= 0 || asu == 99) iconLevel = 0;
885            else if (asu >= 16) iconLevel = 4;
886            else if (asu >= 8)  iconLevel = 3;
887            else if (asu >= 4)  iconLevel = 2;
888            else iconLevel = 1;
889
890            if (mPhone.isNetworkRoaming()) {
891                iconList = sSignalImages_r;
892            } else {
893                iconList = sSignalImages;
894            }
895        } else {
896            iconList = this.sSignalImages;
897
898            // If 3G(EV) and 1x network are available than 3G should be
899            // displayed, displayed RSSI should be from the EV side.
900            // If a voice call is made then RSSI should switch to 1x.
901            if ((mPhoneState == TelephonyManager.CALL_STATE_IDLE) && isEvdo()){
902                iconLevel = getEvdoLevel();
903                if (false) {
904                    Log.d(TAG, "use Evdo level=" + iconLevel + " to replace Cdma Level=" + getCdmaLevel());
905                }
906            } else {
907                iconLevel = getCdmaLevel();
908            }
909        }
910        mPhoneData.iconId = iconList[iconLevel];
911        mService.updateIcon(mPhoneIcon, mPhoneData, null);
912    }
913
914    private int getCdmaLevel() {
915        final int cdmaDbm = mSignalStrength.getCdmaDbm();
916        final int cdmaEcio = mSignalStrength.getCdmaEcio();
917        int levelDbm = 0;
918        int levelEcio = 0;
919
920        if (cdmaDbm >= -75) levelDbm = 4;
921        else if (cdmaDbm >= -85) levelDbm = 3;
922        else if (cdmaDbm >= -95) levelDbm = 2;
923        else if (cdmaDbm >= -100) levelDbm = 1;
924        else levelDbm = 0;
925
926        // Ec/Io are in dB*10
927        if (cdmaEcio >= -90) levelEcio = 4;
928        else if (cdmaEcio >= -110) levelEcio = 3;
929        else if (cdmaEcio >= -130) levelEcio = 2;
930        else if (cdmaEcio >= -150) levelEcio = 1;
931        else levelEcio = 0;
932
933        return (levelDbm < levelEcio) ? levelDbm : levelEcio;
934    }
935
936    private int getEvdoLevel() {
937        int evdoDbm = mSignalStrength.getEvdoDbm();
938        int evdoSnr = mSignalStrength.getEvdoSnr();
939        int levelEvdoDbm = 0;
940        int levelEvdoSnr = 0;
941
942        if (evdoDbm >= -65) levelEvdoDbm = 4;
943        else if (evdoDbm >= -75) levelEvdoDbm = 3;
944        else if (evdoDbm >= -90) levelEvdoDbm = 2;
945        else if (evdoDbm >= -105) levelEvdoDbm = 1;
946        else levelEvdoDbm = 0;
947
948        if (evdoSnr > 7) levelEvdoSnr = 4;
949        else if (evdoSnr > 5) levelEvdoSnr = 3;
950        else if (evdoSnr > 3) levelEvdoSnr = 2;
951        else if (evdoSnr > 1) levelEvdoSnr = 1;
952        else levelEvdoSnr = 0;
953
954        return (levelEvdoDbm < levelEvdoSnr) ? levelEvdoDbm : levelEvdoSnr;
955    }
956
957    private final void updateDataNetType() {
958        int net = mPhone.getNetworkType();
959
960        switch (net) {
961        case TelephonyManager.NETWORK_TYPE_EDGE:
962            mDataIconList = sDataNetType_e;
963            break;
964        case TelephonyManager.NETWORK_TYPE_UMTS:
965            mDataIconList = sDataNetType_3g;
966            break;
967        case TelephonyManager.NETWORK_TYPE_HSDPA:
968        case TelephonyManager.NETWORK_TYPE_HSUPA:
969        case TelephonyManager.NETWORK_TYPE_HSPA:
970            mDataIconList = sDataNetType_h;
971            break;
972        case TelephonyManager.NETWORK_TYPE_CDMA:
973            // display 1xRTT for IS95A/B
974            mDataIconList = this.sDataNetType_1xrtt;
975            break;
976        case TelephonyManager.NETWORK_TYPE_1xRTT:
977            mDataIconList = this.sDataNetType_1xrtt;
978            break;
979        case TelephonyManager.NETWORK_TYPE_EVDO_0: //fall through
980        case TelephonyManager.NETWORK_TYPE_EVDO_A:
981            mDataIconList = sDataNetType_evdo;
982            break;
983        default:
984            mDataIconList = sDataNetType_g;
985        break;
986        }
987    }
988
989    private final void updateDataIcon() {
990        int iconId;
991        boolean visible = true;
992
993        if (!isCdma()) {
994            // GSM case, we have to check also the sim state
995            if (mSimState == IccCard.State.READY || mSimState == IccCard.State.UNKNOWN) {
996                if (hasService() && mDataState == TelephonyManager.DATA_CONNECTED) {
997                    switch (mDataActivity) {
998                        case TelephonyManager.DATA_ACTIVITY_IN:
999                            iconId = mDataIconList[1];
1000                            break;
1001                        case TelephonyManager.DATA_ACTIVITY_OUT:
1002                            iconId = mDataIconList[2];
1003                            break;
1004                        case TelephonyManager.DATA_ACTIVITY_INOUT:
1005                            iconId = mDataIconList[3];
1006                            break;
1007                        default:
1008                            iconId = mDataIconList[0];
1009                            break;
1010                    }
1011                    mDataData.iconId = iconId;
1012                    mService.updateIcon(mDataIcon, mDataData, null);
1013                } else {
1014                    visible = false;
1015                }
1016            } else {
1017                mDataData.iconId = com.android.internal.R.drawable.stat_sys_no_sim;
1018                mService.updateIcon(mDataIcon, mDataData, null);
1019            }
1020        } else {
1021            // CDMA case, mDataActivity can be also DATA_ACTIVITY_DORMANT
1022            if (hasService() && mDataState == TelephonyManager.DATA_CONNECTED) {
1023                switch (mDataActivity) {
1024                    case TelephonyManager.DATA_ACTIVITY_IN:
1025                        iconId = mDataIconList[1];
1026                        break;
1027                    case TelephonyManager.DATA_ACTIVITY_OUT:
1028                        iconId = mDataIconList[2];
1029                        break;
1030                    case TelephonyManager.DATA_ACTIVITY_INOUT:
1031                        iconId = mDataIconList[3];
1032                        break;
1033                    case TelephonyManager.DATA_ACTIVITY_DORMANT:
1034                        iconId = mDataIconList[4];
1035                        break;
1036                    default:
1037                        iconId = mDataIconList[0];
1038                        break;
1039                }
1040                mDataData.iconId = iconId;
1041                mService.updateIcon(mDataIcon, mDataData, null);
1042            } else {
1043                visible = false;
1044            }
1045        }
1046
1047        long ident = Binder.clearCallingIdentity();
1048        try {
1049            mBatteryStats.notePhoneDataConnectionState(mPhone.getNetworkType(), visible);
1050        } catch (RemoteException e) {
1051        } finally {
1052            Binder.restoreCallingIdentity(ident);
1053        }
1054
1055        if (mDataIconVisible != visible) {
1056            mService.setIconVisibility(mDataIcon, visible);
1057            mDataIconVisible = visible;
1058        }
1059    }
1060
1061    private final void updateVolume() {
1062        AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
1063        final int ringerMode = audioManager.getRingerMode();
1064        final boolean visible = ringerMode == AudioManager.RINGER_MODE_SILENT ||
1065                ringerMode == AudioManager.RINGER_MODE_VIBRATE;
1066        final int iconId = audioManager.shouldVibrate(AudioManager.VIBRATE_TYPE_RINGER)
1067                ? com.android.internal.R.drawable.stat_sys_ringer_vibrate
1068                : com.android.internal.R.drawable.stat_sys_ringer_silent;
1069
1070        if (visible) {
1071            mVolumeData.iconId = iconId;
1072            mService.updateIcon(mVolumeIcon, mVolumeData, null);
1073        }
1074        if (visible != mVolumeVisible) {
1075            mService.setIconVisibility(mVolumeIcon, visible);
1076            mVolumeVisible = visible;
1077        }
1078    }
1079
1080    private final void updateBluetooth(Intent intent) {
1081        int iconId = com.android.internal.R.drawable.stat_sys_data_bluetooth;
1082
1083        String action = intent.getAction();
1084        if (action.equals(BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION)) {
1085            int state = intent.getIntExtra(BluetoothIntent.BLUETOOTH_STATE,
1086                                           BluetoothError.ERROR);
1087            mBluetoothEnabled = state == BluetoothAdapter.BLUETOOTH_STATE_ON;
1088        } else if (action.equals(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION)) {
1089            mBluetoothHeadsetState = intent.getIntExtra(BluetoothIntent.HEADSET_STATE,
1090                    BluetoothHeadset.STATE_ERROR);
1091        } else if (action.equals(BluetoothA2dp.SINK_STATE_CHANGED_ACTION)) {
1092            mBluetoothA2dpState = intent.getIntExtra(BluetoothA2dp.SINK_STATE,
1093                    BluetoothA2dp.STATE_DISCONNECTED);
1094        } else if (action.equals(BluetoothPbap.PBAP_STATE_CHANGED_ACTION)) {
1095            mBluetoothPbapState = intent.getIntExtra(BluetoothPbap.PBAP_STATE,
1096                    BluetoothPbap.STATE_DISCONNECTED);
1097        } else {
1098            return;
1099        }
1100
1101        if (mBluetoothHeadsetState == BluetoothHeadset.STATE_CONNECTED ||
1102                mBluetoothA2dpState == BluetoothA2dp.STATE_CONNECTED ||
1103                mBluetoothA2dpState == BluetoothA2dp.STATE_PLAYING ||
1104                mBluetoothPbapState == BluetoothPbap.STATE_CONNECTED) {
1105            iconId = com.android.internal.R.drawable.stat_sys_data_bluetooth_connected;
1106        }
1107
1108        mBluetoothData.iconId = iconId;
1109        mService.updateIcon(mBluetoothIcon, mBluetoothData, null);
1110        mService.setIconVisibility(mBluetoothIcon, mBluetoothEnabled);
1111    }
1112
1113    private final void updateWifi(Intent intent) {
1114        final String action = intent.getAction();
1115        if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
1116
1117            final boolean enabled = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
1118                    WifiManager.WIFI_STATE_UNKNOWN) == WifiManager.WIFI_STATE_ENABLED;
1119
1120            if (!enabled) {
1121                // If disabled, hide the icon. (We show icon when connected.)
1122                mService.setIconVisibility(mWifiIcon, false);
1123            }
1124
1125        } else if (action.equals(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION)) {
1126            final boolean enabled = intent.getBooleanExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED,
1127                                                           false);
1128            if (!enabled) {
1129                mService.setIconVisibility(mWifiIcon, false);
1130            }
1131        } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
1132
1133            final NetworkInfo networkInfo = (NetworkInfo)
1134                    intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
1135
1136            int iconId;
1137            if (networkInfo != null && networkInfo.isConnected()) {
1138                mIsWifiConnected = true;
1139                if (mLastWifiSignalLevel == -1) {
1140                    iconId = sWifiSignalImages[0];
1141                } else {
1142                    iconId = sWifiSignalImages[mLastWifiSignalLevel];
1143                }
1144
1145                // Show the icon since wi-fi is connected
1146                mService.setIconVisibility(mWifiIcon, true);
1147
1148            } else {
1149                mLastWifiSignalLevel = -1;
1150                mIsWifiConnected = false;
1151                iconId = sWifiSignalImages[0];
1152
1153                // Hide the icon since we're not connected
1154                mService.setIconVisibility(mWifiIcon, false);
1155            }
1156
1157            mWifiData.iconId = iconId;
1158            mService.updateIcon(mWifiIcon, mWifiData, null);
1159        } else if (action.equals(WifiManager.RSSI_CHANGED_ACTION)) {
1160            final int newRssi = intent.getIntExtra(WifiManager.EXTRA_NEW_RSSI, -200);
1161            int newSignalLevel = WifiManager.calculateSignalLevel(newRssi,
1162                                                                  sWifiSignalImages.length);
1163            if (newSignalLevel != mLastWifiSignalLevel) {
1164                mLastWifiSignalLevel = newSignalLevel;
1165                if (mIsWifiConnected) {
1166                    mWifiData.iconId = sWifiSignalImages[newSignalLevel];
1167                } else {
1168                    mWifiData.iconId = sWifiTemporarilyNotConnectedImage;
1169                }
1170                mService.updateIcon(mWifiIcon, mWifiData, null);
1171            }
1172        }
1173    }
1174
1175    private final void updateGps(Intent intent) {
1176        final String action = intent.getAction();
1177        final boolean enabled = intent.getBooleanExtra(GpsLocationProvider.EXTRA_ENABLED, false);
1178
1179        if (action.equals(GpsLocationProvider.GPS_FIX_CHANGE_ACTION) && enabled) {
1180            // GPS is getting fixes
1181            mService.updateIcon(mGpsIcon, mGpsFixIconData, null);
1182            mService.setIconVisibility(mGpsIcon, true);
1183        } else if (action.equals(GpsLocationProvider.GPS_ENABLED_CHANGE_ACTION) && !enabled) {
1184            // GPS is off
1185            mService.setIconVisibility(mGpsIcon, false);
1186        } else {
1187            // GPS is on, but not receiving fixes
1188            mService.updateIcon(mGpsIcon, mGpsEnabledIconData, null);
1189            mService.setIconVisibility(mGpsIcon, true);
1190        }
1191    }
1192
1193    private final void updateTTY(Intent intent) {
1194        final String action = intent.getAction();
1195        final boolean enabled = intent.getBooleanExtra(TtyIntent.TTY_ENABLED, false);
1196
1197        Log.i(TAG, "updateTTY: enabled: " + enabled);
1198
1199        if (enabled) {
1200            // TTY is on
1201            Log.i(TAG, "updateTTY: set TTY on");
1202            mService.updateIcon(mTTYModeIcon, mTTYModeEnableIconData, null);
1203            mService.setIconVisibility(mTTYModeIcon, true);
1204        } else {
1205            // TTY is off
1206            Log.i(TAG, "updateTTY: set TTY off");
1207            mService.setIconVisibility(mTTYModeIcon, false);
1208        }
1209    }
1210
1211    private final void updateCdmaRoamingIcon() {
1212        if (!hasService()) {
1213            mService.setIconVisibility(mCdmaRoamingIndicatorIcon, false);
1214            return;
1215        }
1216
1217        if (!isCdma()) {
1218            mService.setIconVisibility(mCdmaRoamingIndicatorIcon, false);
1219            return;
1220        }
1221
1222        int[] iconList = sRoamingIndicatorImages_cdma;
1223        int iconIndex = mPhone.getCdmaEriIconIndex();
1224        int iconMode = mPhone.getCdmaEriIconMode();
1225
1226        if (iconIndex == -1) {
1227            Log.e(TAG, "getCdmaEriIconIndex returned null, skipping ERI icon update");
1228            return;
1229        }
1230
1231        if (iconMode == -1) {
1232            Log.e(TAG, "getCdmeEriIconMode returned null, skipping ERI icon update");
1233            return;
1234        }
1235
1236        if (iconIndex == EriInfo.ROAMING_INDICATOR_OFF) {
1237            Log.d(TAG, "Cdma ROAMING_INDICATOR_OFF, removing ERI icon");
1238            mService.setIconVisibility(mCdmaRoamingIndicatorIcon, false);
1239            return;
1240        }
1241
1242        switch (iconMode) {
1243            case EriInfo.ROAMING_ICON_MODE_NORMAL:
1244                mCdmaRoamingIndicatorIconData.iconId = iconList[iconIndex];
1245                mService.updateIcon(mCdmaRoamingIndicatorIcon, mCdmaRoamingIndicatorIconData, null);
1246                mService.setIconVisibility(mCdmaRoamingIndicatorIcon, true);
1247                break;
1248            case EriInfo.ROAMING_ICON_MODE_FLASH:
1249                mCdmaRoamingIndicatorIconData.iconId =
1250                        com.android.internal.R.drawable.stat_sys_roaming_cdma_flash;
1251                mService.updateIcon(mCdmaRoamingIndicatorIcon, mCdmaRoamingIndicatorIconData, null);
1252                mService.setIconVisibility(mCdmaRoamingIndicatorIcon, true);
1253                break;
1254
1255        }
1256        mService.updateIcon(mPhoneIcon, mPhoneData, null);
1257    }
1258
1259
1260    private class StatusBarHandler extends Handler {
1261        @Override
1262        public void handleMessage(Message msg) {
1263            switch (msg.what) {
1264            case EVENT_BATTERY_CLOSE:
1265                if (msg.arg1 == mBatteryViewSequence) {
1266                    closeLastBatteryView();
1267                }
1268                break;
1269            }
1270        }
1271    }
1272}
1273