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