blob: dd3d38c80f65948a3fbe967681b8673421e70d9c [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
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
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080019import android.app.AlertDialog;
20import android.bluetooth.BluetoothA2dp;
21import android.bluetooth.BluetoothDevice;
The Android Open Source Project10592532009-03-18 17:39:46 -070022import android.bluetooth.BluetoothError;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080023import android.bluetooth.BluetoothHeadset;
24import android.bluetooth.BluetoothIntent;
25import android.content.BroadcastReceiver;
26import android.content.Context;
27import android.content.DialogInterface;
28import android.content.Intent;
29import android.content.IntentFilter;
30import android.content.res.TypedArray;
31import android.graphics.PixelFormat;
32import android.graphics.drawable.Drawable;
33import android.media.AudioManager;
34import android.net.NetworkInfo;
35import android.net.wifi.WifiManager;
Dianne Hackborn627bba72009-03-24 22:32:56 -070036import android.os.Binder;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037import android.os.Handler;
38import android.os.IBinder;
39import android.os.Message;
Dianne Hackborn627bba72009-03-24 22:32:56 -070040import android.os.RemoteException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080041import android.provider.Settings;
42import android.telephony.PhoneStateListener;
43import android.telephony.ServiceState;
Wink Savillee9b06d72009-05-18 21:47:50 -070044import android.telephony.SignalStrength;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080045import android.telephony.TelephonyManager;
46import android.text.format.DateFormat;
47import android.util.Log;
48import android.view.View;
49import android.view.ViewGroup;
50import android.view.WindowManager;
51import android.view.WindowManagerImpl;
52import android.widget.ImageView;
53import android.widget.LinearLayout;
54import android.widget.TextView;
55
Wink Saville767a6622009-04-02 01:37:02 -070056import com.android.internal.R;
57import com.android.internal.app.IBatteryStats;
58import com.android.internal.location.GpsLocationProvider;
59import com.android.internal.telephony.IccCard;
60import com.android.internal.telephony.TelephonyIntents;
Wink Savillee9b06d72009-05-18 21:47:50 -070061import com.android.internal.telephony.cdma.EriInfo;
Wink Saville767a6622009-04-02 01:37:02 -070062import com.android.internal.telephony.cdma.TtyIntent;
63import com.android.server.am.BatteryStatsService;
64
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080065import java.util.Calendar;
66import java.util.TimeZone;
67
68/**
69 * This class contains all of the policy about which icons are installed in the status
70 * bar at boot time. In reality, it should go into the android.policy package, but
71 * putting it here is the first step from extracting it.
72 */
73public class StatusBarPolicy {
74 private static final String TAG = "StatusBarPolicy";
75
76 private static StatusBarPolicy sInstance;
77
78 // message codes for the handler
79 private static final int EVENT_DATA_CONN_STATE_CHANGED = 2;
80 private static final int EVENT_DATA_ACTIVITY = 3;
81 private static final int EVENT_BATTERY_CLOSE = 4;
82
83 // indices into mBatteryThresholds
84 private static final int BATTERY_THRESHOLD_CLOSE_WARNING = 0;
85 private static final int BATTERY_THRESHOLD_WARNING = 1;
86 private static final int BATTERY_THRESHOLD_EMPTY = 2;
87
Dianne Hackborn627bba72009-03-24 22:32:56 -070088 private final Context mContext;
89 private final StatusBarService mService;
90 private final Handler mHandler = new StatusBarHandler();
91 private final IBatteryStats mBatteryStats;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080092
93 // clock
94 private Calendar mCalendar;
95 private IBinder mClockIcon;
96 private IconData mClockData;
97
98 // battery
99 private IBinder mBatteryIcon;
100 private IconData mBatteryData;
101 private boolean mBatteryFirst = true;
102 private boolean mBatteryPlugged;
103 private int mBatteryLevel;
104 private int mBatteryThreshold = 0; // index into mBatteryThresholds
105 private int[] mBatteryThresholds = new int[] { 20, 15, -1 };
106 private AlertDialog mLowBatteryDialog;
107 private TextView mBatteryLevelTextView;
108 private View mBatteryView;
109 private int mBatteryViewSequence;
110 private boolean mBatteryShowLowOnEndCall = false;
111 private static final boolean SHOW_LOW_BATTERY_WARNING = true;
112
113 // phone
114 private TelephonyManager mPhone;
115 private IBinder mPhoneIcon;
Wink Savillee9b06d72009-05-18 21:47:50 -0700116 private IBinder mPhoneEvdoIcon;
Wink Saville767a6622009-04-02 01:37:02 -0700117
118 //***** Signal strength icons
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800119 private IconData mPhoneData;
Wink Savillee9b06d72009-05-18 21:47:50 -0700120 private IconData mPhoneEvdoData;
Wink Saville767a6622009-04-02 01:37:02 -0700121 //GSM/UMTS
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800122 private static final int[] sSignalImages = new int[] {
Wink Savillee9b06d72009-05-18 21:47:50 -0700123 com.android.internal.R.drawable.stat_sys_signal_0,
124 com.android.internal.R.drawable.stat_sys_signal_1,
125 com.android.internal.R.drawable.stat_sys_signal_2,
126 com.android.internal.R.drawable.stat_sys_signal_3,
127 com.android.internal.R.drawable.stat_sys_signal_4
128 };
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800129 private static final int[] sSignalImages_r = new int[] {
Wink Savillee9b06d72009-05-18 21:47:50 -0700130 com.android.internal.R.drawable.stat_sys_r_signal_0,
131 com.android.internal.R.drawable.stat_sys_r_signal_1,
132 com.android.internal.R.drawable.stat_sys_r_signal_2,
133 com.android.internal.R.drawable.stat_sys_r_signal_3,
134 com.android.internal.R.drawable.stat_sys_r_signal_4
135 };
Wink Saville767a6622009-04-02 01:37:02 -0700136 //CDMA
137 private static final int[] sSignalImages_cdma = new int[] {
Wink Savillee9b06d72009-05-18 21:47:50 -0700138 com.android.internal.R.drawable.stat_sys_signal_cdma_0,
139 com.android.internal.R.drawable.stat_sys_signal_cdma_1,
140 com.android.internal.R.drawable.stat_sys_signal_cdma_2,
141 com.android.internal.R.drawable.stat_sys_signal_cdma_3,
142 com.android.internal.R.drawable.stat_sys_signal_cdma_4
Wink Saville767a6622009-04-02 01:37:02 -0700143 };
Wink Savillee9b06d72009-05-18 21:47:50 -0700144 private static final int[] sRoamingIndicatorImages_cdma = new int[] {
145 com.android.internal.R.drawable.stat_sys_roaming_cdma_0, //Standard Roaming Indicator
146 // 1 is Standard Roaming Indicator OFF
147 // TODO T: image never used, remove and put 0 instead?
148 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
149
150 // 2 is Standard Roaming Indicator FLASHING
151 // TODO T: image never used, remove and put 0 instead?
152 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
153
154 // 3-12 Standard ERI
155 com.android.internal.R.drawable.stat_sys_roaming_cdma_0, //3
156 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
157 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
158 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
159 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
160 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
161 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
162 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
163 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
164 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
165
166 // 13-63 Reserved for Standard ERI
167 com.android.internal.R.drawable.stat_sys_roaming_cdma_0, //13
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 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
211 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
212 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
213 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
214 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
215 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
216 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
217 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
218
219 // 64-127 Reserved for Non Standard (Operator Specific) ERI
220 com.android.internal.R.drawable.stat_sys_roaming_cdma_0, //64
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,
232 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
233 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
234 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
235 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
236 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
237 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
238 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
239 com.android.internal.R.drawable.stat_sys_roaming_cdma_0 //83
240
241 // 128-255 Reserved
Wink Saville767a6622009-04-02 01:37:02 -0700242 };
Wink Savillee9b06d72009-05-18 21:47:50 -0700243 // EVDO
244 private static final int[] sSignalImages_evdo = new int[] {
245 com.android.internal.R.drawable.stat_sys_signal_evdo_0,
246 com.android.internal.R.drawable.stat_sys_signal_evdo_1,
247 com.android.internal.R.drawable.stat_sys_signal_evdo_2,
248 com.android.internal.R.drawable.stat_sys_signal_evdo_3,
249 com.android.internal.R.drawable.stat_sys_signal_evdo_4
Wink Saville767a6622009-04-02 01:37:02 -0700250 };
251
252 //***** Data connection icons
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800253 private int[] mDataIconList = sDataNetType_g;
Wink Saville767a6622009-04-02 01:37:02 -0700254 //GSM/UMTS
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800255 private static final int[] sDataNetType_g = new int[] {
256 com.android.internal.R.drawable.stat_sys_data_connected_g,
257 com.android.internal.R.drawable.stat_sys_data_in_g,
258 com.android.internal.R.drawable.stat_sys_data_out_g,
259 com.android.internal.R.drawable.stat_sys_data_inandout_g,
260 };
261 private static final int[] sDataNetType_3g = new int[] {
262 com.android.internal.R.drawable.stat_sys_data_connected_3g,
263 com.android.internal.R.drawable.stat_sys_data_in_3g,
264 com.android.internal.R.drawable.stat_sys_data_out_3g,
265 com.android.internal.R.drawable.stat_sys_data_inandout_3g,
266 };
267 private static final int[] sDataNetType_e = new int[] {
268 com.android.internal.R.drawable.stat_sys_data_connected_e,
269 com.android.internal.R.drawable.stat_sys_data_in_e,
270 com.android.internal.R.drawable.stat_sys_data_out_e,
271 com.android.internal.R.drawable.stat_sys_data_inandout_e,
272 };
Wink Saville767a6622009-04-02 01:37:02 -0700273 //CDMA
274 private static final int[] sDataNetType_evdo = new int[] {
275 com.android.internal.R.drawable.stat_sys_data_connected_evdo,
276 com.android.internal.R.drawable.stat_sys_data_in_evdo,
277 com.android.internal.R.drawable.stat_sys_data_out_evdo,
278 com.android.internal.R.drawable.stat_sys_data_inandout_evdo,
Wink Savillee9b06d72009-05-18 21:47:50 -0700279 com.android.internal.R.drawable.stat_sys_data_dormant_evdo,
Wink Saville767a6622009-04-02 01:37:02 -0700280 };
281 private static final int[] sDataNetType_1xrtt = new int[] {
282 com.android.internal.R.drawable.stat_sys_data_connected_1xrtt,
283 com.android.internal.R.drawable.stat_sys_data_in_1xrtt,
284 com.android.internal.R.drawable.stat_sys_data_out_1xrtt,
285 com.android.internal.R.drawable.stat_sys_data_inandout_1xrtt,
Wink Savillee9b06d72009-05-18 21:47:50 -0700286 com.android.internal.R.drawable.stat_sys_data_dormant_1xrtt,
Wink Saville767a6622009-04-02 01:37:02 -0700287 };
288
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800289 // Assume it's all good unless we hear otherwise. We don't always seem
290 // to get broadcasts that it *is* there.
Wink Saville767a6622009-04-02 01:37:02 -0700291 IccCard.State mSimState = IccCard.State.READY;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800292 int mPhoneState = TelephonyManager.CALL_STATE_IDLE;
293 int mDataState = TelephonyManager.DATA_DISCONNECTED;
294 int mDataActivity = TelephonyManager.DATA_ACTIVITY_NONE;
295 ServiceState mServiceState;
Wink Savillee9b06d72009-05-18 21:47:50 -0700296 SignalStrength mSignalStrength;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800297
298 // data connection
299 private IBinder mDataIcon;
300 private IconData mDataData;
301 private boolean mDataIconVisible;
302
303 // ringer volume
304 private IBinder mVolumeIcon;
305 private IconData mVolumeData;
306 private boolean mVolumeVisible;
Wink Saville767a6622009-04-02 01:37:02 -0700307
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800308 // bluetooth device status
309 private IBinder mBluetoothIcon;
310 private IconData mBluetoothData;
311 private int mBluetoothHeadsetState;
312 private int mBluetoothA2dpState;
313 private boolean mBluetoothEnabled;
314
315 // wifi
316 private static final int[] sWifiSignalImages = new int[] {
317 com.android.internal.R.drawable.stat_sys_wifi_signal_1,
318 com.android.internal.R.drawable.stat_sys_wifi_signal_2,
319 com.android.internal.R.drawable.stat_sys_wifi_signal_3,
320 com.android.internal.R.drawable.stat_sys_wifi_signal_4,
321 };
322 private static final int sWifiTemporarilyNotConnectedImage =
323 com.android.internal.R.drawable.stat_sys_wifi_signal_0;
324
325 private int mLastWifiSignalLevel = -1;
326 private boolean mIsWifiConnected = false;
327 private IBinder mWifiIcon;
328 private IconData mWifiData;
329
330 // gps
331 private IBinder mGpsIcon;
332 private IconData mGpsEnabledIconData;
333 private IconData mGpsFixIconData;
334
335 // alarm clock
336 // Icon lit when clock is set
337 private IBinder mAlarmClockIcon;
338 private IconData mAlarmClockIconData;
339
340 // sync state
341 // If sync is active the SyncActive icon is displayed. If sync is not active but
342 // sync is failing the SyncFailing icon is displayed. Otherwise neither are displayed.
343 private IBinder mSyncActiveIcon;
344 private IBinder mSyncFailingIcon;
345
Wink Saville767a6622009-04-02 01:37:02 -0700346 // TTY mode
347 // Icon lit when TTY mode is enabled
348 private IBinder mTTYModeIcon;
349 private IconData mTTYModeEnableIconData;
350
Wink Savillee9b06d72009-05-18 21:47:50 -0700351 // Cdma Roaming Indicator, ERI
352 private IBinder mCdmaRoamingIndicatorIcon;
353 private IconData mCdmaRoamingIndicatorIconData;
354
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800355 private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
356 @Override
357 public void onReceive(Context context, Intent intent) {
358 String action = intent.getAction();
359 if (action.equals(Intent.ACTION_TIME_TICK)) {
360 updateClock();
361 }
362 else if (action.equals(Intent.ACTION_TIME_CHANGED)) {
363 updateClock();
364 }
365 else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
366 updateClock();
367 }
368 else if (action.equals(Intent.ACTION_TIMEZONE_CHANGED)) {
369 String tz = intent.getStringExtra("time-zone");
370 mCalendar = Calendar.getInstance(TimeZone.getTimeZone(tz));
371 updateClock();
372 }
373 else if (action.equals(Intent.ACTION_ALARM_CHANGED)) {
374 updateAlarm(intent);
375 }
376 else if (action.equals(Intent.ACTION_SYNC_STATE_CHANGED)) {
377 updateSyncState(intent);
378 }
379 else if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
380 updateBattery(intent);
381 }
The Android Open Source Project10592532009-03-18 17:39:46 -0700382 else if (action.equals(BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION) ||
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800383 action.equals(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION) ||
384 action.equals(BluetoothA2dp.SINK_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 }
Wink Saville767a6622009-04-02 01:37:02 -0700403 else if (action.equals(TtyIntent.TTY_ENABLED_CHANGE_ACTION)) {
404 updateTTY(intent);
405 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800406 }
407 };
408
409 private StatusBarPolicy(Context context, StatusBarService service) {
410 mContext = context;
411 mService = service;
Wink Savillee9b06d72009-05-18 21:47:50 -0700412 mSignalStrength = new SignalStrength();
Dianne Hackborn627bba72009-03-24 22:32:56 -0700413 mBatteryStats = BatteryStatsService.getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800414
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);
Wink Savillee9b06d72009-05-18 21:47:50 -0700428 mPhoneData = IconData.makeIcon("phone_signal",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800429 null, com.android.internal.R.drawable.stat_sys_signal_null, 0, 0);
430 mPhoneIcon = service.addIcon(mPhoneData, null);
Wink Savillee9b06d72009-05-18 21:47:50 -0700431
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
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800438 // register for phone state notifications.
439 ((TelephonyManager)mContext.getSystemService(Context.TELEPHONY_SERVICE))
440 .listen(mPhoneStateListener,
441 PhoneStateListener.LISTEN_SERVICE_STATE
Wink Savillee9b06d72009-05-18 21:47:50 -0700442 | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800443 | 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
Wink Saville767a6622009-04-02 01:37:02 -0700458
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
Wink Savillee9b06d72009-05-18 21:47:50 -0700465 // 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
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800471 // 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 mService.setIconVisibility(mBluetoothIcon, mBluetoothEnabled);
485
486 // Gps status
487 mGpsEnabledIconData = IconData.makeIcon("gps",
488 null, com.android.internal.R.drawable.stat_sys_gps_acquiring_anim, 0, 0);
489 mGpsFixIconData = IconData.makeIcon("gps",
490 null, com.android.internal.R.drawable.stat_sys_gps_on, 0, 0);
491 mGpsIcon = service.addIcon(mGpsEnabledIconData, null);
492 service.setIconVisibility(mGpsIcon, false);
493
494 // Alarm clock
495 mAlarmClockIconData = IconData.makeIcon(
496 "alarm_clock",
497 null, com.android.internal.R.drawable.stat_notify_alarm, 0, 0);
498 mAlarmClockIcon = service.addIcon(mAlarmClockIconData, null);
499 service.setIconVisibility(mAlarmClockIcon, false);
500
501 // Sync state
502 mSyncActiveIcon = service.addIcon(IconData.makeIcon("sync_active",
503 null, R.drawable.stat_notify_sync_anim0, 0, 0), null);
504 mSyncFailingIcon = service.addIcon(IconData.makeIcon("sync_failing",
505 null, R.drawable.stat_notify_sync_error, 0, 0), null);
506 service.setIconVisibility(mSyncActiveIcon, false);
507 service.setIconVisibility(mSyncFailingIcon, false);
508
509 // volume
510 mVolumeData = IconData.makeIcon("volume",
511 null, com.android.internal.R.drawable.stat_sys_ringer_silent, 0, 0);
512 mVolumeIcon = service.addIcon(mVolumeData, null);
513 service.setIconVisibility(mVolumeIcon, false);
514 updateVolume();
515
516 IntentFilter filter = new IntentFilter();
517
518 // Register for Intent broadcasts for...
519 filter.addAction(Intent.ACTION_TIME_TICK);
520 filter.addAction(Intent.ACTION_TIME_CHANGED);
521 filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
522 filter.addAction(Intent.ACTION_BATTERY_CHANGED);
523 filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
524 filter.addAction(Intent.ACTION_ALARM_CHANGED);
525 filter.addAction(Intent.ACTION_SYNC_STATE_CHANGED);
526 filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
527 filter.addAction(AudioManager.VIBRATE_SETTING_CHANGED_ACTION);
The Android Open Source Project10592532009-03-18 17:39:46 -0700528 filter.addAction(BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800529 filter.addAction(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION);
530 filter.addAction(BluetoothA2dp.SINK_STATE_CHANGED_ACTION);
531 filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
532 filter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
533 filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
534 filter.addAction(WifiManager.RSSI_CHANGED_ACTION);
535 filter.addAction(GpsLocationProvider.GPS_ENABLED_CHANGE_ACTION);
536 filter.addAction(GpsLocationProvider.GPS_FIX_CHANGE_ACTION);
537 filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
Wink Saville767a6622009-04-02 01:37:02 -0700538 filter.addAction(TtyIntent.TTY_ENABLED_CHANGE_ACTION);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800539 mContext.registerReceiver(mIntentReceiver, filter, null, mHandler);
540 }
541
542 public static void installIcons(Context context, StatusBarService service) {
543 sInstance = new StatusBarPolicy(context, service);
544 }
545
546 private final void updateClock() {
547 mCalendar.setTimeInMillis(System.currentTimeMillis());
548 mClockData.text = DateFormat.getTimeFormat(mContext)
549 .format(mCalendar.getTime());
550 mService.updateIcon(mClockIcon, mClockData, null);
551 }
552
553 private final void updateAlarm(Intent intent) {
554 boolean alarmSet = intent.getBooleanExtra("alarmSet", false);
555 mService.setIconVisibility(mAlarmClockIcon, alarmSet);
556 }
557
558 private final void updateSyncState(Intent intent) {
559 boolean isActive = intent.getBooleanExtra("active", false);
560 boolean isFailing = intent.getBooleanExtra("failing", false);
561 mService.setIconVisibility(mSyncActiveIcon, isActive);
562 // Don't display sync failing icon: BUG 1297963 Set sync error timeout to "never"
563 //mService.setIconVisibility(mSyncFailingIcon, isFailing && !isActive);
564 }
565
566 private void pickNextBatteryLevel(int level) {
567 final int N = mBatteryThresholds.length;
568 for (int i=0; i<N; i++) {
569 if (level >= mBatteryThresholds[i]) {
570 mBatteryThreshold = i;
571 break;
572 }
573 }
574 if (mBatteryThreshold >= N) {
575 mBatteryThreshold = N-1;
576 }
577 }
578
579 private final void updateBattery(Intent intent) {
580 mBatteryData.iconId = intent.getIntExtra("icon-small", 0);
581 mBatteryData.iconLevel = intent.getIntExtra("level", 0);
582 mService.updateIcon(mBatteryIcon, mBatteryData, null);
583
584 boolean plugged = intent.getIntExtra("plugged", 0) != 0;
585 int level = intent.getIntExtra("level", -1);
586 if (false) {
587 Log.d(TAG, "updateBattery level=" + level
588 + " plugged=" + plugged
589 + " mBatteryPlugged=" + mBatteryPlugged
590 + " mBatteryLevel=" + mBatteryLevel
591 + " mBatteryThreshold=" + mBatteryThreshold
592 + " mBatteryFirst=" + mBatteryFirst);
593 }
594
595 boolean oldPlugged = mBatteryPlugged;
596 int oldThreshold = mBatteryThreshold;
597 pickNextBatteryLevel(level);
598
599 mBatteryPlugged = plugged;
600 mBatteryLevel = level;
601
602 if (mBatteryFirst) {
603 mBatteryFirst = false;
604 }
605 /*
606 * No longer showing the battery view because it draws attention away
607 * from the USB storage notification. We could still show it when
608 * connected to a brick, but that could lead to the user into thinking
609 * the device does not charge when plugged into USB (since he/she would
610 * not see the same battery screen on USB as he sees on brick).
611 */
612 /* else {
613 if (plugged && !oldPlugged) {
614 showBatteryView();
615 }
616 }
617 */
618 if (false) {
619 Log.d(TAG, "plugged=" + plugged + " oldPlugged=" + oldPlugged + " level=" + level
620 + " mBatteryThreshold=" + mBatteryThreshold + " oldThreshold=" + oldThreshold);
621 }
622 if (!plugged
623 && ((oldPlugged && level < mBatteryThresholds[BATTERY_THRESHOLD_WARNING])
624 || (mBatteryThreshold > oldThreshold
625 && mBatteryThreshold > BATTERY_THRESHOLD_WARNING))) {
626 // Broadcast the low battery warning
627 mContext.sendBroadcast(new Intent(Intent.ACTION_BATTERY_LOW));
628
629 if (SHOW_LOW_BATTERY_WARNING) {
630 if (false) {
631 Log.d(TAG, "mPhoneState=" + mPhoneState
632 + " mLowBatteryDialog=" + mLowBatteryDialog
633 + " mBatteryShowLowOnEndCall=" + mBatteryShowLowOnEndCall);
634 }
635
636 if (mPhoneState == TelephonyManager.CALL_STATE_IDLE) {
637 showLowBatteryWarning();
638 } else {
639 mBatteryShowLowOnEndCall = true;
640 }
641 }
642 } else if (mBatteryThreshold == BATTERY_THRESHOLD_CLOSE_WARNING) {
643 if (SHOW_LOW_BATTERY_WARNING) {
644 if (mLowBatteryDialog != null) {
645 mLowBatteryDialog.dismiss();
646 mBatteryShowLowOnEndCall = false;
647 }
648 }
649 }
650 }
651
652 private void showBatteryView() {
653 closeLastBatteryView();
654 if (mLowBatteryDialog != null) {
655 mLowBatteryDialog.dismiss();
656 }
657
658 int level = mBatteryLevel;
659
660 View v = View.inflate(mContext, com.android.internal.R.layout.battery_status, null);
661 mBatteryView = v;
662 int pixelFormat = PixelFormat.TRANSLUCENT;
663 Drawable bg = v.getBackground();
664 if (bg != null) {
665 pixelFormat = bg.getOpacity();
666 }
667
668 WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
669 ViewGroup.LayoutParams.WRAP_CONTENT,
670 ViewGroup.LayoutParams.WRAP_CONTENT,
671 WindowManager.LayoutParams.TYPE_TOAST,
672 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
673 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
674 | WindowManager.LayoutParams.FLAG_BLUR_BEHIND
675 | WindowManager.LayoutParams.FLAG_DIM_BEHIND,
676 pixelFormat);
677
678 // Get the dim amount from the theme
679 TypedArray a = mContext.obtainStyledAttributes(
680 com.android.internal.R.styleable.Theme);
681 lp.dimAmount = a.getFloat(android.R.styleable.Theme_backgroundDimAmount, 0.5f);
682 a.recycle();
Wink Saville767a6622009-04-02 01:37:02 -0700683
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800684 lp.setTitle("Battery");
685
686 TextView levelTextView = (TextView)v.findViewById(com.android.internal.R.id.level_percent);
687 levelTextView.setText(mContext.getString(
688 com.android.internal.R.string.battery_status_text_percent_format, level));
689
690 setBatteryLevel(v, com.android.internal.R.id.spacer, 100-level, 0, 0);
691 setBatteryLevel(v, com.android.internal.R.id.level, level,
692 com.android.internal.R.drawable.battery_charge_fill, level);
693
694 WindowManagerImpl.getDefault().addView(v, lp);
695
696 scheduleCloseBatteryView();
697 }
698
699 private void setBatteryLevel(View parent, int id, int height, int background, int level) {
700 ImageView v = (ImageView)parent.findViewById(id);
701 LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)v.getLayoutParams();
702 lp.weight = height;
703 if (background != 0) {
704 v.setBackgroundResource(background);
705 Drawable bkg = v.getBackground();
706 bkg.setLevel(level);
707 }
708 }
709
710 private void showLowBatteryWarning() {
711 closeLastBatteryView();
712
713 int level = mBatteryThresholds[mBatteryThreshold > 1 ? mBatteryThreshold - 1 : 0];
714 CharSequence levelText = mContext.getString(
715 com.android.internal.R.string.battery_low_percent_format, level);
716
717 if (mBatteryLevelTextView != null) {
718 mBatteryLevelTextView.setText(levelText);
719 } else {
720 View v = View.inflate(mContext, com.android.internal.R.layout.battery_low, null);
721 mBatteryLevelTextView=(TextView)v.findViewById(com.android.internal.R.id.level_percent);
722
723 mBatteryLevelTextView.setText(levelText);
724
725 AlertDialog.Builder b = new AlertDialog.Builder(mContext);
726 b.setCancelable(true);
727 b.setTitle(com.android.internal.R.string.battery_low_title);
728 b.setView(v);
729 b.setIcon(android.R.drawable.ic_dialog_alert);
730 b.setPositiveButton(android.R.string.ok, null);
Dianne Hackborn3d74bb42009-06-19 10:35:21 -0700731
732 final Intent intent = new Intent(Intent.ACTION_POWER_USAGE_SUMMARY);
733 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
734 | Intent.FLAG_ACTIVITY_MULTIPLE_TASK
735 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
736 | Intent.FLAG_ACTIVITY_NO_HISTORY);
737 if (intent.resolveActivity(mContext.getPackageManager()) != null) {
738 b.setNegativeButton(com.android.internal.R.string.battery_low_why,
739 new DialogInterface.OnClickListener() {
740 public void onClick(DialogInterface dialog, int which) {
741 mContext.startActivity(intent);
742 if (mLowBatteryDialog != null) {
743 mLowBatteryDialog.dismiss();
744 }
745 }
746 });
747 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800748
749 AlertDialog d = b.create();
750 d.setOnDismissListener(mLowBatteryListener);
751 d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
752 d.show();
753 mLowBatteryDialog = d;
754 }
755 }
756
757 private final void updateCallState(int state) {
758 mPhoneState = state;
759 if (false) {
760 Log.d(TAG, "mPhoneState=" + mPhoneState
761 + " mLowBatteryDialog=" + mLowBatteryDialog
762 + " mBatteryShowLowOnEndCall=" + mBatteryShowLowOnEndCall);
763 }
764 if (mPhoneState == TelephonyManager.CALL_STATE_IDLE) {
765 if (mBatteryShowLowOnEndCall) {
766 if (!mBatteryPlugged) {
767 showLowBatteryWarning();
768 }
769 mBatteryShowLowOnEndCall = false;
770 }
771 } else {
772 if (mLowBatteryDialog != null) {
773 mLowBatteryDialog.dismiss();
774 mBatteryShowLowOnEndCall = true;
775 }
776 }
777 }
778
779 private DialogInterface.OnDismissListener mLowBatteryListener
780 = new DialogInterface.OnDismissListener() {
781 public void onDismiss(DialogInterface dialog) {
782 mLowBatteryDialog = null;
783 mBatteryLevelTextView = null;
784 }
785 };
786
787 private void scheduleCloseBatteryView() {
788 Message m = mHandler.obtainMessage(EVENT_BATTERY_CLOSE);
789 m.arg1 = (++mBatteryViewSequence);
790 mHandler.sendMessageDelayed(m, 3000);
791 }
792
793 private void closeLastBatteryView() {
794 if (mBatteryView != null) {
795 //mBatteryView.debug();
796 WindowManagerImpl.getDefault().removeView(mBatteryView);
797 mBatteryView = null;
798 }
799 }
800
801 private PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
802 @Override
Wink Savillee9b06d72009-05-18 21:47:50 -0700803 public void onSignalStrengthsChanged(SignalStrength signalStrength) {
804 mSignalStrength = signalStrength;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800805 updateSignalStrength();
806 }
807
808 @Override
809 public void onServiceStateChanged(ServiceState state) {
810 mServiceState = state;
811 updateSignalStrength();
Wink Savillee9b06d72009-05-18 21:47:50 -0700812 updateCdmaRoamingIcon();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800813 updateDataIcon();
814 }
815
816 @Override
817 public void onCallStateChanged(int state, String incomingNumber) {
818 updateCallState(state);
819 }
820
821 @Override
822 public void onDataConnectionStateChanged(int state) {
823 mDataState = state;
824 updateDataNetType();
825 updateDataIcon();
826 }
827
828 @Override
829 public void onDataActivity(int direction) {
830 mDataActivity = direction;
831 updateDataIcon();
832 }
833 };
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800834
835 private final void updateSimState(Intent intent) {
Wink Saville767a6622009-04-02 01:37:02 -0700836 String stateExtra = intent.getStringExtra(IccCard.INTENT_KEY_ICC_STATE);
837 if (IccCard.INTENT_VALUE_ICC_ABSENT.equals(stateExtra)) {
838 mSimState = IccCard.State.ABSENT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800839 }
Wink Saville767a6622009-04-02 01:37:02 -0700840 else if (IccCard.INTENT_VALUE_ICC_READY.equals(stateExtra)) {
841 mSimState = IccCard.State.READY;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800842 }
Wink Saville767a6622009-04-02 01:37:02 -0700843 else if (IccCard.INTENT_VALUE_ICC_LOCKED.equals(stateExtra)) {
844 final String lockedReason = intent.getStringExtra(IccCard.INTENT_KEY_LOCKED_REASON);
845 if (IccCard.INTENT_VALUE_LOCKED_ON_PIN.equals(lockedReason)) {
846 mSimState = IccCard.State.PIN_REQUIRED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800847 }
Wink Saville767a6622009-04-02 01:37:02 -0700848 else if (IccCard.INTENT_VALUE_LOCKED_ON_PUK.equals(lockedReason)) {
849 mSimState = IccCard.State.PUK_REQUIRED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800850 }
851 else {
Wink Saville767a6622009-04-02 01:37:02 -0700852 mSimState = IccCard.State.NETWORK_LOCKED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800853 }
854 } else {
Wink Saville767a6622009-04-02 01:37:02 -0700855 mSimState = IccCard.State.UNKNOWN;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800856 }
857 updateDataIcon();
858 }
859
Wink Savillee9b06d72009-05-18 21:47:50 -0700860 private boolean isCdma() {
Wink Savillef3152382009-06-01 14:39:20 -0700861 return ((mPhone != null) && (mPhone.getPhoneType() == TelephonyManager.PHONE_TYPE_CDMA));
Wink Savillee9b06d72009-05-18 21:47:50 -0700862 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800863
Wink Savillee9b06d72009-05-18 21:47:50 -0700864 private boolean hasService() {
865 if (mServiceState != null) {
866 switch (mServiceState.getState()) {
867 case ServiceState.STATE_OUT_OF_SERVICE:
868 case ServiceState.STATE_POWER_OFF:
869 return false;
870 default:
871 return true;
872 }
873 } else {
874 return false;
875 }
876 }
877
878 private final void updateSignalStrength() {
879 int iconLevel = -1;
880 int evdoIconLevel = -1;
881 int[] iconList;
882 int[] evdoIconList;
883
884 if (!hasService()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800885 //Log.d(TAG, "updateSignalStrength: no service");
886 if (Settings.System.getInt(mContext.getContentResolver(),
887 Settings.System.AIRPLANE_MODE_ON, 0) == 1) {
888 mPhoneData.iconId = com.android.internal.R.drawable.stat_sys_signal_flightmode;
889 } else {
890 mPhoneData.iconId = com.android.internal.R.drawable.stat_sys_signal_null;
891 }
892 mService.updateIcon(mPhoneIcon, mPhoneData, null);
Wink Savillee9b06d72009-05-18 21:47:50 -0700893 mService.setIconVisibility(mPhoneEvdoIcon,false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800894 return;
895 }
896
Wink Savillee9b06d72009-05-18 21:47:50 -0700897 if (!isCdma()) {
898 int asu = mSignalStrength.getGsmSignalStrength();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800899
Wink Savillee9b06d72009-05-18 21:47:50 -0700900 // ASU ranges from 0 to 31 - TS 27.007 Sec 8.5
901 // asu = 0 (-113dB or less) is very weak
902 // signal, its better to show 0 bars to the user in such cases.
903 // asu = 99 is a special case, where the signal strength is unknown.
904 if (asu <= 0 || asu == 99) iconLevel = 0;
905 else if (asu >= 16) iconLevel = 4;
906 else if (asu >= 8) iconLevel = 3;
907 else if (asu >= 4) iconLevel = 2;
908 else iconLevel = 1;
909
910 if (mPhone.isNetworkRoaming()) {
911 iconList = sSignalImages_r;
912 } else {
913 iconList = sSignalImages;
Wink Saville767a6622009-04-02 01:37:02 -0700914 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800915 } else {
Wink Savillee9b06d72009-05-18 21:47:50 -0700916 iconList = this.sSignalImages_cdma;
917
918 int cdmaDbm = mSignalStrength.getCdmaDbm();
919 int cdmaEcio = mSignalStrength.getCdmaEcio();
920 int levelDbm = 0;
921 int levelEcio = 0;
922
923 if (cdmaDbm >= -75) levelDbm = 4;
924 else if (cdmaDbm >= -85) levelDbm = 3;
925 else if (cdmaDbm >= -95) levelDbm = 2;
926 else if (cdmaDbm >= -100) levelDbm = 1;
927 else levelDbm = 0;
928
929 // Ec/Io are in dB*10
930 if (cdmaEcio >= -90) levelEcio = 4;
931 else if (cdmaEcio >= -110) levelEcio = 3;
932 else if (cdmaEcio >= -130) levelEcio = 2;
933 else if (cdmaEcio >= -150) levelEcio = 1;
934 else levelEcio = 0;
935
936 iconLevel = (levelDbm < levelEcio) ? levelDbm : levelEcio;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800937 }
Wink Saville767a6622009-04-02 01:37:02 -0700938
Wink Savillee9b06d72009-05-18 21:47:50 -0700939 if ((mServiceState.getRadioTechnology() == ServiceState.RADIO_TECHNOLOGY_EVDO_0)
940 || (mServiceState.getRadioTechnology() == ServiceState.RADIO_TECHNOLOGY_EVDO_A)) {
941 // Use Evdo icon
942 evdoIconList = this.sSignalImages_evdo;
943
944 int evdoEcio = mSignalStrength.getEvdoEcio();
945 int evdoSnr = mSignalStrength.getEvdoSnr();
946 int levelEvdoEcio = 0;
947 int levelEvdoSnr = 0;
948
949 // Ec/Io are in dB*10
950 if (evdoEcio >= -650) levelEvdoEcio = 4;
951 else if (evdoEcio >= -750) levelEvdoEcio = 3;
952 else if (evdoEcio >= -900) levelEvdoEcio = 2;
953 else if (evdoEcio >= -1050) levelEvdoEcio = 1;
954 else levelEvdoEcio = 0;
955
956 if (evdoSnr > 7) levelEvdoSnr = 4;
957 else if (evdoSnr > 5) levelEvdoSnr = 3;
958 else if (evdoSnr > 3) levelEvdoSnr = 2;
959 else if (evdoSnr > 1) levelEvdoSnr = 1;
960 else levelEvdoSnr = 0;
961
962 evdoIconLevel = (levelEvdoEcio < levelEvdoSnr) ? levelEvdoEcio : levelEvdoSnr;
963
964 mPhoneEvdoData.iconId = evdoIconList[evdoIconLevel];
965 mService.updateIcon(mPhoneEvdoIcon, mPhoneEvdoData, null);
966 mService.setIconVisibility(mPhoneEvdoIcon,true);
967 } else {
968 mService.setIconVisibility(mPhoneEvdoIcon,false);
969 }
970
971 mPhoneData.iconId = iconList[iconLevel];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800972 mService.updateIcon(mPhoneIcon, mPhoneData, null);
973 }
974
975 private final void updateDataNetType() {
Wink Saville767a6622009-04-02 01:37:02 -0700976 int net = mPhone.getNetworkType();
Wink Saville767a6622009-04-02 01:37:02 -0700977
978 switch (net) {
Wink Saville767a6622009-04-02 01:37:02 -0700979 case TelephonyManager.NETWORK_TYPE_EDGE:
980 mDataIconList = sDataNetType_e;
981 break;
982 case TelephonyManager.NETWORK_TYPE_UMTS:
983 mDataIconList = sDataNetType_3g;
984 break;
985 case TelephonyManager.NETWORK_TYPE_CDMA:
986 // display 1xRTT for IS95A/B
987 mDataIconList = this.sDataNetType_1xrtt;
988 break;
989 case TelephonyManager.NETWORK_TYPE_1xRTT:
990 mDataIconList = this.sDataNetType_1xrtt;
991 break;
992 case TelephonyManager.NETWORK_TYPE_EVDO_0: //fall through
993 case TelephonyManager.NETWORK_TYPE_EVDO_A:
994 mDataIconList = sDataNetType_evdo;
995 break;
996 default:
997 mDataIconList = sDataNetType_g;
998 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800999 }
1000 }
1001
1002 private final void updateDataIcon() {
1003 int iconId;
1004 boolean visible = true;
1005
Wink Savillee9b06d72009-05-18 21:47:50 -07001006 if (!isCdma()) {
1007 // GSM case, we have to check also the sim state
1008 if (mSimState == IccCard.State.READY || mSimState == IccCard.State.UNKNOWN) {
1009 if (hasService() && mDataState == TelephonyManager.DATA_CONNECTED) {
1010 switch (mDataActivity) {
1011 case TelephonyManager.DATA_ACTIVITY_IN:
1012 iconId = mDataIconList[1];
1013 break;
1014 case TelephonyManager.DATA_ACTIVITY_OUT:
1015 iconId = mDataIconList[2];
1016 break;
1017 case TelephonyManager.DATA_ACTIVITY_INOUT:
1018 iconId = mDataIconList[3];
1019 break;
1020 default:
1021 iconId = mDataIconList[0];
1022 break;
1023 }
1024 mDataData.iconId = iconId;
1025 mService.updateIcon(mDataIcon, mDataData, null);
1026 } else {
1027 visible = false;
1028 }
1029 } else {
1030 mDataData.iconId = com.android.internal.R.drawable.stat_sys_no_sim;
1031 mService.updateIcon(mDataIcon, mDataData, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001032 }
Wink Savillee9b06d72009-05-18 21:47:50 -07001033 } else {
1034 // CDMA case, mDataActivity can be also DATA_ACTIVITY_DORMANT
1035 if (hasService() && mDataState == TelephonyManager.DATA_CONNECTED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001036 switch (mDataActivity) {
1037 case TelephonyManager.DATA_ACTIVITY_IN:
Wink Savillee9b06d72009-05-18 21:47:50 -07001038 iconId = mDataIconList[1];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001039 break;
1040 case TelephonyManager.DATA_ACTIVITY_OUT:
Wink Savillee9b06d72009-05-18 21:47:50 -07001041 iconId = mDataIconList[2];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001042 break;
1043 case TelephonyManager.DATA_ACTIVITY_INOUT:
Wink Savillee9b06d72009-05-18 21:47:50 -07001044 iconId = mDataIconList[3];
1045 break;
1046 case TelephonyManager.DATA_ACTIVITY_DORMANT:
1047 iconId = mDataIconList[4];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001048 break;
1049 default:
Wink Savillee9b06d72009-05-18 21:47:50 -07001050 iconId = mDataIconList[0];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001051 break;
1052 }
1053 mDataData.iconId = iconId;
1054 mService.updateIcon(mDataIcon, mDataData, null);
1055 } else {
1056 visible = false;
1057 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001058 }
Wink Savillee9b06d72009-05-18 21:47:50 -07001059
Dianne Hackborn627bba72009-03-24 22:32:56 -07001060 long ident = Binder.clearCallingIdentity();
1061 try {
Wink Saville767a6622009-04-02 01:37:02 -07001062 mBatteryStats.notePhoneDataConnectionState(mPhone.getNetworkType(), visible);
Dianne Hackborn627bba72009-03-24 22:32:56 -07001063 } catch (RemoteException e) {
1064 } finally {
1065 Binder.restoreCallingIdentity(ident);
1066 }
Wink Savillee9b06d72009-05-18 21:47:50 -07001067
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001068 if (mDataIconVisible != visible) {
1069 mService.setIconVisibility(mDataIcon, visible);
1070 mDataIconVisible = visible;
1071 }
1072 }
1073
1074 private final void updateVolume() {
1075 AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
1076 final int ringerMode = audioManager.getRingerMode();
1077 final boolean visible = ringerMode == AudioManager.RINGER_MODE_SILENT ||
Wink Savillee9b06d72009-05-18 21:47:50 -07001078 ringerMode == AudioManager.RINGER_MODE_VIBRATE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001079 final int iconId = audioManager.shouldVibrate(AudioManager.VIBRATE_TYPE_RINGER)
1080 ? com.android.internal.R.drawable.stat_sys_ringer_vibrate
1081 : com.android.internal.R.drawable.stat_sys_ringer_silent;
1082
1083 if (visible) {
1084 mVolumeData.iconId = iconId;
1085 mService.updateIcon(mVolumeIcon, mVolumeData, null);
1086 }
1087 if (visible != mVolumeVisible) {
1088 mService.setIconVisibility(mVolumeIcon, visible);
1089 mVolumeVisible = visible;
1090 }
1091 }
1092
1093 private final void updateBluetooth(Intent intent) {
1094 int iconId = com.android.internal.R.drawable.stat_sys_data_bluetooth;
1095
1096 String action = intent.getAction();
The Android Open Source Project10592532009-03-18 17:39:46 -07001097 if (action.equals(BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION)) {
1098 int state = intent.getIntExtra(BluetoothIntent.BLUETOOTH_STATE,
1099 BluetoothError.ERROR);
1100 mBluetoothEnabled = state == BluetoothDevice.BLUETOOTH_STATE_ON;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001101 } else if (action.equals(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION)) {
1102 mBluetoothHeadsetState = intent.getIntExtra(BluetoothIntent.HEADSET_STATE,
1103 BluetoothHeadset.STATE_ERROR);
1104 } else if (action.equals(BluetoothA2dp.SINK_STATE_CHANGED_ACTION)) {
1105 mBluetoothA2dpState = intent.getIntExtra(BluetoothA2dp.SINK_STATE,
1106 BluetoothA2dp.STATE_DISCONNECTED);
1107 } else {
1108 return;
1109 }
Wink Savillee9b06d72009-05-18 21:47:50 -07001110
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001111 if (mBluetoothHeadsetState == BluetoothHeadset.STATE_CONNECTED ||
1112 mBluetoothA2dpState == BluetoothA2dp.STATE_CONNECTED ||
1113 mBluetoothA2dpState == BluetoothA2dp.STATE_PLAYING) {
1114 iconId = com.android.internal.R.drawable.stat_sys_data_bluetooth_connected;
1115 }
1116
1117 mBluetoothData.iconId = iconId;
1118 mService.updateIcon(mBluetoothIcon, mBluetoothData, null);
1119 mService.setIconVisibility(mBluetoothIcon, mBluetoothEnabled);
1120 }
1121
1122 private final void updateWifi(Intent intent) {
1123 final String action = intent.getAction();
1124 if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
Wink Savillee9b06d72009-05-18 21:47:50 -07001125
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001126 final boolean enabled = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
1127 WifiManager.WIFI_STATE_UNKNOWN) == WifiManager.WIFI_STATE_ENABLED;
Wink Savillee9b06d72009-05-18 21:47:50 -07001128
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001129 if (!enabled) {
1130 // If disabled, hide the icon. (We show icon when connected.)
1131 mService.setIconVisibility(mWifiIcon, false);
1132 }
Wink Savillee9b06d72009-05-18 21:47:50 -07001133
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001134 } else if (action.equals(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION)) {
1135 final boolean enabled = intent.getBooleanExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED,
1136 false);
1137 if (!enabled) {
1138 mService.setIconVisibility(mWifiIcon, false);
1139 }
1140 } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
1141
Wink Savillee9b06d72009-05-18 21:47:50 -07001142 final NetworkInfo networkInfo = (NetworkInfo)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001143 intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
Wink Savillee9b06d72009-05-18 21:47:50 -07001144
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001145 int iconId;
1146 if (networkInfo != null && networkInfo.isConnected()) {
1147 mIsWifiConnected = true;
1148 if (mLastWifiSignalLevel == -1) {
1149 iconId = sWifiSignalImages[0];
1150 } else {
1151 iconId = sWifiSignalImages[mLastWifiSignalLevel];
1152 }
Wink Saville767a6622009-04-02 01:37:02 -07001153
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001154 // Show the icon since wi-fi is connected
1155 mService.setIconVisibility(mWifiIcon, true);
Wink Saville767a6622009-04-02 01:37:02 -07001156
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001157 } else {
1158 mLastWifiSignalLevel = -1;
1159 mIsWifiConnected = false;
1160 iconId = sWifiSignalImages[0];
1161
1162 // Hide the icon since we're not connected
1163 mService.setIconVisibility(mWifiIcon, false);
1164 }
1165
1166 mWifiData.iconId = iconId;
1167 mService.updateIcon(mWifiIcon, mWifiData, null);
1168 } else if (action.equals(WifiManager.RSSI_CHANGED_ACTION)) {
1169 final int newRssi = intent.getIntExtra(WifiManager.EXTRA_NEW_RSSI, -200);
1170 int newSignalLevel = WifiManager.calculateSignalLevel(newRssi,
1171 sWifiSignalImages.length);
1172 if (newSignalLevel != mLastWifiSignalLevel) {
1173 mLastWifiSignalLevel = newSignalLevel;
1174 if (mIsWifiConnected) {
1175 mWifiData.iconId = sWifiSignalImages[newSignalLevel];
1176 } else {
1177 mWifiData.iconId = sWifiTemporarilyNotConnectedImage;
1178 }
1179 mService.updateIcon(mWifiIcon, mWifiData, null);
1180 }
1181 }
1182 }
1183
1184 private final void updateGps(Intent intent) {
1185 final String action = intent.getAction();
1186 final boolean enabled = intent.getBooleanExtra(GpsLocationProvider.EXTRA_ENABLED, false);
1187
1188 if (action.equals(GpsLocationProvider.GPS_FIX_CHANGE_ACTION) && enabled) {
1189 // GPS is getting fixes
1190 mService.updateIcon(mGpsIcon, mGpsFixIconData, null);
Wink Savillee9b06d72009-05-18 21:47:50 -07001191 mService.setIconVisibility(mGpsIcon, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001192 } else if (action.equals(GpsLocationProvider.GPS_ENABLED_CHANGE_ACTION) && !enabled) {
1193 // GPS is off
Wink Savillee9b06d72009-05-18 21:47:50 -07001194 mService.setIconVisibility(mGpsIcon, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001195 } else {
1196 // GPS is on, but not receiving fixes
1197 mService.updateIcon(mGpsIcon, mGpsEnabledIconData, null);
Wink Savillee9b06d72009-05-18 21:47:50 -07001198 mService.setIconVisibility(mGpsIcon, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001199 }
1200 }
1201
Wink Savillee9b06d72009-05-18 21:47:50 -07001202 private final void updateTTY(Intent intent) {
Wink Saville767a6622009-04-02 01:37:02 -07001203 final String action = intent.getAction();
1204 final boolean enabled = intent.getBooleanExtra(TtyIntent.TTY_ENABLED, false);
1205
1206 Log.i(TAG, "updateTTY: enabled: " + enabled);
1207
1208 if (enabled) {
1209 // TTY is on
1210 Log.i(TAG, "updateTTY: set TTY on");
1211 mService.updateIcon(mTTYModeIcon, mTTYModeEnableIconData, null);
Wink Savillee9b06d72009-05-18 21:47:50 -07001212 mService.setIconVisibility(mTTYModeIcon, true);
Wink Saville767a6622009-04-02 01:37:02 -07001213 } else {
1214 // TTY is off
1215 Log.i(TAG, "updateTTY: set TTY off");
Wink Savillee9b06d72009-05-18 21:47:50 -07001216 mService.setIconVisibility(mTTYModeIcon, false);
Wink Saville767a6622009-04-02 01:37:02 -07001217 }
1218 }
1219
Wink Savillee9b06d72009-05-18 21:47:50 -07001220 private final void updateCdmaRoamingIcon() {
1221 if (!hasService()) {
1222 mService.setIconVisibility(mCdmaRoamingIndicatorIcon, false);
Wink Savillef3152382009-06-01 14:39:20 -07001223 return;
Wink Savillee9b06d72009-05-18 21:47:50 -07001224 }
1225
1226 if (!isCdma()) {
1227 mService.setIconVisibility(mCdmaRoamingIndicatorIcon, false);
Wink Savillef3152382009-06-01 14:39:20 -07001228 return;
Wink Savillee9b06d72009-05-18 21:47:50 -07001229 }
1230
1231 int[] iconList = sRoamingIndicatorImages_cdma;
1232 int iconIndex = mPhone.getCdmaEriIconIndex();
1233 int iconMode = mPhone.getCdmaEriIconMode();
1234
1235 if (iconIndex == -1) {
1236 Log.e(TAG, "getCdmaEriIconIndex returned null, skipping ERI icon update");
1237 return;
1238 }
1239
1240 if (iconMode == -1) {
1241 Log.e(TAG, "getCdmeEriIconMode returned null, skipping ERI icon update");
1242 return;
1243 }
1244
1245 if (iconIndex == EriInfo.ROAMING_INDICATOR_OFF) {
1246 Log.d(TAG, "Cdma ROAMING_INDICATOR_OFF, removing ERI icon");
1247 mService.setIconVisibility(mCdmaRoamingIndicatorIcon, false);
1248 return;
1249 }
1250
1251 switch (iconMode) {
1252 case EriInfo.ROAMING_ICON_MODE_NORMAL:
1253 mCdmaRoamingIndicatorIconData.iconId = iconList[iconIndex];
1254 mService.updateIcon(mCdmaRoamingIndicatorIcon, mCdmaRoamingIndicatorIconData, null);
1255 mService.setIconVisibility(mCdmaRoamingIndicatorIcon, true);
1256 break;
1257 case EriInfo.ROAMING_ICON_MODE_FLASH:
Wink Savillef3152382009-06-01 14:39:20 -07001258 mCdmaRoamingIndicatorIconData.iconId =
1259 com.android.internal.R.drawable.stat_sys_roaming_cdma_flash;
Wink Savillee9b06d72009-05-18 21:47:50 -07001260 mService.updateIcon(mCdmaRoamingIndicatorIcon, mCdmaRoamingIndicatorIconData, null);
Wink Savillef3152382009-06-01 14:39:20 -07001261 mService.setIconVisibility(mCdmaRoamingIndicatorIcon, true);
Wink Savillee9b06d72009-05-18 21:47:50 -07001262 break;
1263
1264 }
1265 mService.updateIcon(mPhoneIcon, mPhoneData, null);
1266 }
1267
1268
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001269 private class StatusBarHandler extends Handler {
1270 @Override
1271 public void handleMessage(Message msg) {
1272 switch (msg.what) {
1273 case EVENT_BATTERY_CLOSE:
1274 if (msg.arg1 == mBatteryViewSequence) {
1275 closeLastBatteryView();
1276 }
1277 break;
1278 }
1279 }
1280 }
1281}