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