blob: c663e544b807ab23626108fc8cff2a0754069c1e [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;
Nick Pellybd022f42009-08-14 18:33:38 -070021import android.bluetooth.BluetoothAdapter;
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;
Jiafa Liu3f416732009-07-02 16:36:02 +080025import android.bluetooth.BluetoothPbap;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080026import 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;
Dianne Hackborn4840e142009-03-24 22:40:29 -070037import android.os.Binder;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080038import android.os.Handler;
39import android.os.IBinder;
40import android.os.Message;
Dianne Hackborn4840e142009-03-24 22:40:29 -070041import android.os.RemoteException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080042import android.provider.Settings;
43import android.telephony.PhoneStateListener;
44import android.telephony.ServiceState;
Wink Savillee9b06d72009-05-18 21:47:50 -070045import android.telephony.SignalStrength;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080046import 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
Wink Saville04e71b32009-04-02 11:00:54 -070057import 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;
Wink Savillee9b06d72009-05-18 21:47:50 -070062import com.android.internal.telephony.cdma.EriInfo;
Wink Saville04e71b32009-04-02 11:00:54 -070063import com.android.internal.telephony.cdma.TtyIntent;
64import com.android.server.am.BatteryStatsService;
65
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080066import 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
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080080 private static final int EVENT_BATTERY_CLOSE = 4;
81
Dianne Hackborn4840e142009-03-24 22:40:29 -070082 private final Context mContext;
83 private final StatusBarService mService;
84 private final Handler mHandler = new StatusBarHandler();
85 private final IBatteryStats mBatteryStats;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080086
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;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080098 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;
Wink Saville04e71b32009-04-02 11:00:54 -0700108
109 //***** Signal strength icons
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800110 private IconData mPhoneData;
Wink Saville04e71b32009-04-02 11:00:54 -0700111 //GSM/UMTS
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800112 private static final int[] sSignalImages = new int[] {
Wink Savillee9b06d72009-05-18 21:47:50 -0700113 com.android.internal.R.drawable.stat_sys_signal_0,
114 com.android.internal.R.drawable.stat_sys_signal_1,
115 com.android.internal.R.drawable.stat_sys_signal_2,
116 com.android.internal.R.drawable.stat_sys_signal_3,
117 com.android.internal.R.drawable.stat_sys_signal_4
118 };
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800119 private static final int[] sSignalImages_r = new int[] {
Wink Savillee9b06d72009-05-18 21:47:50 -0700120 com.android.internal.R.drawable.stat_sys_r_signal_0,
121 com.android.internal.R.drawable.stat_sys_r_signal_1,
122 com.android.internal.R.drawable.stat_sys_r_signal_2,
123 com.android.internal.R.drawable.stat_sys_r_signal_3,
124 com.android.internal.R.drawable.stat_sys_r_signal_4
125 };
Wink Savillee9b06d72009-05-18 21:47:50 -0700126 private static final int[] sRoamingIndicatorImages_cdma = new int[] {
127 com.android.internal.R.drawable.stat_sys_roaming_cdma_0, //Standard Roaming Indicator
128 // 1 is Standard Roaming Indicator OFF
129 // TODO T: image never used, remove and put 0 instead?
130 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
131
132 // 2 is Standard Roaming Indicator FLASHING
133 // TODO T: image never used, remove and put 0 instead?
134 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
135
136 // 3-12 Standard ERI
137 com.android.internal.R.drawable.stat_sys_roaming_cdma_0, //3
138 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
139 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
140 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
141 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
142 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
143 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
144 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
145 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
146 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
147
148 // 13-63 Reserved for Standard ERI
149 com.android.internal.R.drawable.stat_sys_roaming_cdma_0, //13
150 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
151 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
152 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
153 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
154 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
155 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
156 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
157 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
158 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
159 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
160 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
161 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
162 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
163 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
164 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
165 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
166 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
167 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
168 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
169 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
170 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
171 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
172 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
173 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
174 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
175 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
176 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
177 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
178 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
179 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
180 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
181 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
182 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
183 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
184 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
185 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
186 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
187 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
188 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
189 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
190 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
191 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
192 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
193 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
194 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
195 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
196 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
197 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
198 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
199 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
200
201 // 64-127 Reserved for Non Standard (Operator Specific) ERI
202 com.android.internal.R.drawable.stat_sys_roaming_cdma_0, //64
203 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
204 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
205 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
206 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
207 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
208 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
209 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
210 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
211 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
212 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
213 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
214 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
215 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
216 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
217 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
218 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
219 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
220 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
221 com.android.internal.R.drawable.stat_sys_roaming_cdma_0 //83
222
223 // 128-255 Reserved
Wink Saville04e71b32009-04-02 11:00:54 -0700224 };
Wink Saville04e71b32009-04-02 11:00:54 -0700225
226 //***** Data connection icons
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800227 private int[] mDataIconList = sDataNetType_g;
Wink Saville04e71b32009-04-02 11:00:54 -0700228 //GSM/UMTS
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800229 private static final int[] sDataNetType_g = new int[] {
230 com.android.internal.R.drawable.stat_sys_data_connected_g,
231 com.android.internal.R.drawable.stat_sys_data_in_g,
232 com.android.internal.R.drawable.stat_sys_data_out_g,
233 com.android.internal.R.drawable.stat_sys_data_inandout_g,
234 };
235 private static final int[] sDataNetType_3g = new int[] {
236 com.android.internal.R.drawable.stat_sys_data_connected_3g,
237 com.android.internal.R.drawable.stat_sys_data_in_3g,
238 com.android.internal.R.drawable.stat_sys_data_out_3g,
239 com.android.internal.R.drawable.stat_sys_data_inandout_3g,
240 };
241 private static final int[] sDataNetType_e = new int[] {
242 com.android.internal.R.drawable.stat_sys_data_connected_e,
243 com.android.internal.R.drawable.stat_sys_data_in_e,
244 com.android.internal.R.drawable.stat_sys_data_out_e,
245 com.android.internal.R.drawable.stat_sys_data_inandout_e,
246 };
Li Zheebe66342009-08-14 19:22:16 +0800247 //3.5G
248 private static final int[] sDataNetType_h = new int[] {
249 com.android.internal.R.drawable.stat_sys_data_connected_h,
250 com.android.internal.R.drawable.stat_sys_data_in_h,
251 com.android.internal.R.drawable.stat_sys_data_out_h,
252 com.android.internal.R.drawable.stat_sys_data_inandout_h,
253 };
254
Wink Saville04e71b32009-04-02 11:00:54 -0700255 //CDMA
johnwang9f87cb22009-08-25 15:25:37 -0700256 // Use 3G icons for EVDO data and 1x icons for 1XRTT data
257 private static final int[] sDataNetType_1x = new int[] {
258 com.android.internal.R.drawable.stat_sys_data_connected_1x,
259 com.android.internal.R.drawable.stat_sys_data_in_1x,
260 com.android.internal.R.drawable.stat_sys_data_out_1x,
261 com.android.internal.R.drawable.stat_sys_data_inandout_1x,
Wink Saville04e71b32009-04-02 11:00:54 -0700262 };
263
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800264 // Assume it's all good unless we hear otherwise. We don't always seem
265 // to get broadcasts that it *is* there.
Wink Saville04e71b32009-04-02 11:00:54 -0700266 IccCard.State mSimState = IccCard.State.READY;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800267 int mPhoneState = TelephonyManager.CALL_STATE_IDLE;
268 int mDataState = TelephonyManager.DATA_DISCONNECTED;
269 int mDataActivity = TelephonyManager.DATA_ACTIVITY_NONE;
270 ServiceState mServiceState;
Wink Savillee9b06d72009-05-18 21:47:50 -0700271 SignalStrength mSignalStrength;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800272
273 // data connection
274 private IBinder mDataIcon;
275 private IconData mDataData;
276 private boolean mDataIconVisible;
277
278 // ringer volume
279 private IBinder mVolumeIcon;
280 private IconData mVolumeData;
281 private boolean mVolumeVisible;
Wink Saville04e71b32009-04-02 11:00:54 -0700282
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800283 // bluetooth device status
284 private IBinder mBluetoothIcon;
285 private IconData mBluetoothData;
286 private int mBluetoothHeadsetState;
287 private int mBluetoothA2dpState;
Jiafa Liu3f416732009-07-02 16:36:02 +0800288 private int mBluetoothPbapState;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800289 private boolean mBluetoothEnabled;
290
291 // wifi
292 private static final int[] sWifiSignalImages = new int[] {
293 com.android.internal.R.drawable.stat_sys_wifi_signal_1,
294 com.android.internal.R.drawable.stat_sys_wifi_signal_2,
295 com.android.internal.R.drawable.stat_sys_wifi_signal_3,
296 com.android.internal.R.drawable.stat_sys_wifi_signal_4,
297 };
298 private static final int sWifiTemporarilyNotConnectedImage =
299 com.android.internal.R.drawable.stat_sys_wifi_signal_0;
300
301 private int mLastWifiSignalLevel = -1;
302 private boolean mIsWifiConnected = false;
303 private IBinder mWifiIcon;
304 private IconData mWifiData;
305
306 // gps
307 private IBinder mGpsIcon;
308 private IconData mGpsEnabledIconData;
309 private IconData mGpsFixIconData;
310
311 // alarm clock
312 // Icon lit when clock is set
313 private IBinder mAlarmClockIcon;
314 private IconData mAlarmClockIconData;
315
316 // sync state
317 // If sync is active the SyncActive icon is displayed. If sync is not active but
318 // sync is failing the SyncFailing icon is displayed. Otherwise neither are displayed.
319 private IBinder mSyncActiveIcon;
320 private IBinder mSyncFailingIcon;
321
Wink Saville04e71b32009-04-02 11:00:54 -0700322 // TTY mode
323 // Icon lit when TTY mode is enabled
324 private IBinder mTTYModeIcon;
325 private IconData mTTYModeEnableIconData;
326
Wink Savillee9b06d72009-05-18 21:47:50 -0700327 // Cdma Roaming Indicator, ERI
328 private IBinder mCdmaRoamingIndicatorIcon;
329 private IconData mCdmaRoamingIndicatorIconData;
330
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800331 private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
332 @Override
333 public void onReceive(Context context, Intent intent) {
334 String action = intent.getAction();
335 if (action.equals(Intent.ACTION_TIME_TICK)) {
336 updateClock();
337 }
338 else if (action.equals(Intent.ACTION_TIME_CHANGED)) {
339 updateClock();
340 }
Dianne Hackborn8ec5b832009-07-01 21:19:35 -0700341 else if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
342 updateBattery(intent);
343 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800344 else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
345 updateClock();
346 }
347 else if (action.equals(Intent.ACTION_TIMEZONE_CHANGED)) {
348 String tz = intent.getStringExtra("time-zone");
349 mCalendar = Calendar.getInstance(TimeZone.getTimeZone(tz));
350 updateClock();
351 }
352 else if (action.equals(Intent.ACTION_ALARM_CHANGED)) {
353 updateAlarm(intent);
354 }
355 else if (action.equals(Intent.ACTION_SYNC_STATE_CHANGED)) {
356 updateSyncState(intent);
357 }
Mihai Predaa82842f2009-04-29 15:05:56 +0200358 else if (action.equals(Intent.ACTION_BATTERY_LOW)) {
359 onBatteryLow(intent);
360 }
Mike Lockwood69eb0bf2009-08-01 23:02:28 -0400361 else if (action.equals(Intent.ACTION_BATTERY_OKAY)
362 || action.equals(Intent.ACTION_POWER_CONNECTED)) {
Dianne Hackborn8ec5b832009-07-01 21:19:35 -0700363 onBatteryOkay(intent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800364 }
Nick Pellyde893f52009-09-08 13:15:33 -0700365 else if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED) ||
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800366 action.equals(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION) ||
Jiafa Liu3f416732009-07-02 16:36:02 +0800367 action.equals(BluetoothA2dp.SINK_STATE_CHANGED_ACTION) ||
368 action.equals(BluetoothPbap.PBAP_STATE_CHANGED_ACTION)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800369 updateBluetooth(intent);
370 }
371 else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION) ||
372 action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION) ||
373 action.equals(WifiManager.RSSI_CHANGED_ACTION)) {
374 updateWifi(intent);
375 }
376 else if (action.equals(GpsLocationProvider.GPS_ENABLED_CHANGE_ACTION) ||
377 action.equals(GpsLocationProvider.GPS_FIX_CHANGE_ACTION)) {
378 updateGps(intent);
379 }
380 else if (action.equals(AudioManager.RINGER_MODE_CHANGED_ACTION) ||
381 action.equals(AudioManager.VIBRATE_SETTING_CHANGED_ACTION)) {
382 updateVolume();
383 }
384 else if (action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) {
385 updateSimState(intent);
386 }
Wink Saville04e71b32009-04-02 11:00:54 -0700387 else if (action.equals(TtyIntent.TTY_ENABLED_CHANGE_ACTION)) {
388 updateTTY(intent);
389 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800390 }
391 };
392
393 private StatusBarPolicy(Context context, StatusBarService service) {
394 mContext = context;
395 mService = service;
Wink Savillee9b06d72009-05-18 21:47:50 -0700396 mSignalStrength = new SignalStrength();
Dianne Hackborn4840e142009-03-24 22:40:29 -0700397 mBatteryStats = BatteryStatsService.getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800398
399 // clock
400 mCalendar = Calendar.getInstance(TimeZone.getDefault());
401 mClockData = IconData.makeText("clock", "");
402 mClockIcon = service.addIcon(mClockData, null);
403 updateClock();
404
405 // battery
406 mBatteryData = IconData.makeIcon("battery",
407 null, com.android.internal.R.drawable.stat_sys_battery_unknown, 0, 0);
408 mBatteryIcon = service.addIcon(mBatteryData, null);
409
410 // phone_signal
411 mPhone = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
Wink Savillee9b06d72009-05-18 21:47:50 -0700412 mPhoneData = IconData.makeIcon("phone_signal",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800413 null, com.android.internal.R.drawable.stat_sys_signal_null, 0, 0);
414 mPhoneIcon = service.addIcon(mPhoneData, null);
Wink Savillee9b06d72009-05-18 21:47:50 -0700415
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800416 // register for phone state notifications.
417 ((TelephonyManager)mContext.getSystemService(Context.TELEPHONY_SERVICE))
418 .listen(mPhoneStateListener,
419 PhoneStateListener.LISTEN_SERVICE_STATE
Wink Savillee9b06d72009-05-18 21:47:50 -0700420 | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800421 | PhoneStateListener.LISTEN_CALL_STATE
422 | PhoneStateListener.LISTEN_DATA_CONNECTION_STATE
423 | PhoneStateListener.LISTEN_DATA_ACTIVITY);
424
425 // data_connection
426 mDataData = IconData.makeIcon("data_connection",
427 null, com.android.internal.R.drawable.stat_sys_data_connected_g, 0, 0);
428 mDataIcon = service.addIcon(mDataData, null);
429 service.setIconVisibility(mDataIcon, false);
430
431 // wifi
432 mWifiData = IconData.makeIcon("wifi", null, sWifiSignalImages[0], 0, 0);
433 mWifiIcon = service.addIcon(mWifiData, null);
434 service.setIconVisibility(mWifiIcon, false);
435 // wifi will get updated by the sticky intents
Wink Saville04e71b32009-04-02 11:00:54 -0700436
437 // TTY status
438 mTTYModeEnableIconData = IconData.makeIcon("tty",
439 null, com.android.internal.R.drawable.stat_sys_tty_mode, 0, 0);
440 mTTYModeIcon = service.addIcon(mTTYModeEnableIconData, null);
441 service.setIconVisibility(mTTYModeIcon, false);
442
Wink Savillee9b06d72009-05-18 21:47:50 -0700443 // Cdma Roaming Indicator, ERI
444 mCdmaRoamingIndicatorIconData = IconData.makeIcon("cdma_eri",
445 null, com.android.internal.R.drawable.stat_sys_roaming_cdma_0, 0, 0);
446 mCdmaRoamingIndicatorIcon = service.addIcon(mCdmaRoamingIndicatorIconData, null);
447 service.setIconVisibility(mCdmaRoamingIndicatorIcon, false);
448
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800449 // bluetooth status
450 mBluetoothData = IconData.makeIcon("bluetooth",
451 null, com.android.internal.R.drawable.stat_sys_data_bluetooth, 0, 0);
452 mBluetoothIcon = service.addIcon(mBluetoothData, null);
Nick Pellybd022f42009-08-14 18:33:38 -0700453 BluetoothAdapter adapter =
454 (BluetoothAdapter) mContext.getSystemService(Context.BLUETOOTH_SERVICE);
455 if (adapter != null) {
456 mBluetoothEnabled = adapter.isEnabled();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800457 } else {
458 mBluetoothEnabled = false;
459 }
460 mBluetoothA2dpState = BluetoothA2dp.STATE_DISCONNECTED;
461 mBluetoothHeadsetState = BluetoothHeadset.STATE_DISCONNECTED;
Jiafa Liu3f416732009-07-02 16:36:02 +0800462 mBluetoothPbapState = BluetoothPbap.STATE_DISCONNECTED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800463 mService.setIconVisibility(mBluetoothIcon, mBluetoothEnabled);
464
465 // Gps status
466 mGpsEnabledIconData = IconData.makeIcon("gps",
467 null, com.android.internal.R.drawable.stat_sys_gps_acquiring_anim, 0, 0);
468 mGpsFixIconData = IconData.makeIcon("gps",
469 null, com.android.internal.R.drawable.stat_sys_gps_on, 0, 0);
470 mGpsIcon = service.addIcon(mGpsEnabledIconData, null);
johnwang347c5a22009-08-24 22:11:11 -0700471 service.setIconVisibility(mGpsIcon, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800472
473 // Alarm clock
474 mAlarmClockIconData = IconData.makeIcon(
475 "alarm_clock",
476 null, com.android.internal.R.drawable.stat_notify_alarm, 0, 0);
477 mAlarmClockIcon = service.addIcon(mAlarmClockIconData, null);
478 service.setIconVisibility(mAlarmClockIcon, false);
479
480 // Sync state
481 mSyncActiveIcon = service.addIcon(IconData.makeIcon("sync_active",
482 null, R.drawable.stat_notify_sync_anim0, 0, 0), null);
483 mSyncFailingIcon = service.addIcon(IconData.makeIcon("sync_failing",
484 null, R.drawable.stat_notify_sync_error, 0, 0), null);
485 service.setIconVisibility(mSyncActiveIcon, false);
486 service.setIconVisibility(mSyncFailingIcon, false);
487
488 // volume
489 mVolumeData = IconData.makeIcon("volume",
490 null, com.android.internal.R.drawable.stat_sys_ringer_silent, 0, 0);
491 mVolumeIcon = service.addIcon(mVolumeData, null);
492 service.setIconVisibility(mVolumeIcon, false);
493 updateVolume();
johnwang347c5a22009-08-24 22:11:11 -0700494
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800495 IntentFilter filter = new IntentFilter();
496
497 // Register for Intent broadcasts for...
498 filter.addAction(Intent.ACTION_TIME_TICK);
499 filter.addAction(Intent.ACTION_TIME_CHANGED);
500 filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
501 filter.addAction(Intent.ACTION_BATTERY_CHANGED);
Mihai Predaa82842f2009-04-29 15:05:56 +0200502 filter.addAction(Intent.ACTION_BATTERY_LOW);
Dianne Hackborn8ec5b832009-07-01 21:19:35 -0700503 filter.addAction(Intent.ACTION_BATTERY_OKAY);
Mike Lockwood69eb0bf2009-08-01 23:02:28 -0400504 filter.addAction(Intent.ACTION_POWER_CONNECTED);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800505 filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
506 filter.addAction(Intent.ACTION_ALARM_CHANGED);
507 filter.addAction(Intent.ACTION_SYNC_STATE_CHANGED);
508 filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
509 filter.addAction(AudioManager.VIBRATE_SETTING_CHANGED_ACTION);
Nick Pellyde893f52009-09-08 13:15:33 -0700510 filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800511 filter.addAction(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION);
512 filter.addAction(BluetoothA2dp.SINK_STATE_CHANGED_ACTION);
Jiafa Liu3f416732009-07-02 16:36:02 +0800513 filter.addAction(BluetoothPbap.PBAP_STATE_CHANGED_ACTION);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800514 filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
515 filter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
516 filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
517 filter.addAction(WifiManager.RSSI_CHANGED_ACTION);
518 filter.addAction(GpsLocationProvider.GPS_ENABLED_CHANGE_ACTION);
519 filter.addAction(GpsLocationProvider.GPS_FIX_CHANGE_ACTION);
520 filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
Wink Saville04e71b32009-04-02 11:00:54 -0700521 filter.addAction(TtyIntent.TTY_ENABLED_CHANGE_ACTION);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800522 mContext.registerReceiver(mIntentReceiver, filter, null, mHandler);
523 }
524
525 public static void installIcons(Context context, StatusBarService service) {
526 sInstance = new StatusBarPolicy(context, service);
527 }
528
529 private final void updateClock() {
530 mCalendar.setTimeInMillis(System.currentTimeMillis());
531 mClockData.text = DateFormat.getTimeFormat(mContext)
532 .format(mCalendar.getTime());
533 mService.updateIcon(mClockIcon, mClockData, null);
534 }
535
536 private final void updateAlarm(Intent intent) {
537 boolean alarmSet = intent.getBooleanExtra("alarmSet", false);
538 mService.setIconVisibility(mAlarmClockIcon, alarmSet);
539 }
540
541 private final void updateSyncState(Intent intent) {
542 boolean isActive = intent.getBooleanExtra("active", false);
543 boolean isFailing = intent.getBooleanExtra("failing", false);
544 mService.setIconVisibility(mSyncActiveIcon, isActive);
545 // Don't display sync failing icon: BUG 1297963 Set sync error timeout to "never"
546 //mService.setIconVisibility(mSyncFailingIcon, isFailing && !isActive);
547 }
548
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800549 private final void updateBattery(Intent intent) {
550 mBatteryData.iconId = intent.getIntExtra("icon-small", 0);
551 mBatteryData.iconLevel = intent.getIntExtra("level", 0);
552 mService.updateIcon(mBatteryIcon, mBatteryData, null);
553
554 boolean plugged = intent.getIntExtra("plugged", 0) != 0;
555 int level = intent.getIntExtra("level", -1);
556 if (false) {
557 Log.d(TAG, "updateBattery level=" + level
558 + " plugged=" + plugged
559 + " mBatteryPlugged=" + mBatteryPlugged
560 + " mBatteryLevel=" + mBatteryLevel
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800561 + " mBatteryFirst=" + mBatteryFirst);
562 }
563
564 boolean oldPlugged = mBatteryPlugged;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800565
566 mBatteryPlugged = plugged;
567 mBatteryLevel = level;
568
569 if (mBatteryFirst) {
570 mBatteryFirst = false;
571 }
572 /*
573 * No longer showing the battery view because it draws attention away
574 * from the USB storage notification. We could still show it when
575 * connected to a brick, but that could lead to the user into thinking
576 * the device does not charge when plugged into USB (since he/she would
577 * not see the same battery screen on USB as he sees on brick).
578 */
579 /* else {
580 if (plugged && !oldPlugged) {
581 showBatteryView();
582 }
583 }
584 */
585 if (false) {
Mihai Predaa82842f2009-04-29 15:05:56 +0200586 Log.d(TAG, "plugged=" + plugged + " oldPlugged=" + oldPlugged + " level=" + level);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800587 }
Mihai Predaa82842f2009-04-29 15:05:56 +0200588 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800589
Mihai Predaa82842f2009-04-29 15:05:56 +0200590 private void onBatteryLow(Intent intent) {
591 if (SHOW_LOW_BATTERY_WARNING) {
592 if (false) {
593 Log.d(TAG, "mPhoneState=" + mPhoneState
594 + " mLowBatteryDialog=" + mLowBatteryDialog
595 + " mBatteryShowLowOnEndCall=" + mBatteryShowLowOnEndCall);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800596 }
Mihai Predaa82842f2009-04-29 15:05:56 +0200597
598 if (mPhoneState == TelephonyManager.CALL_STATE_IDLE) {
599 showLowBatteryWarning();
600 } else {
601 mBatteryShowLowOnEndCall = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800602 }
603 }
604 }
605
Dianne Hackborn8ec5b832009-07-01 21:19:35 -0700606 private void onBatteryOkay(Intent intent) {
607 if (mLowBatteryDialog != null
608 && SHOW_LOW_BATTERY_WARNING) {
609 mLowBatteryDialog.dismiss();
610 mBatteryShowLowOnEndCall = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800611 }
612 }
613
johnwang347c5a22009-08-24 22:11:11 -0700614 private void showBatteryView() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800615 closeLastBatteryView();
616 if (mLowBatteryDialog != null) {
617 mLowBatteryDialog.dismiss();
618 }
619
620 int level = mBatteryLevel;
621
622 View v = View.inflate(mContext, com.android.internal.R.layout.battery_status, null);
623 mBatteryView = v;
624 int pixelFormat = PixelFormat.TRANSLUCENT;
625 Drawable bg = v.getBackground();
626 if (bg != null) {
627 pixelFormat = bg.getOpacity();
628 }
629
630 WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
631 ViewGroup.LayoutParams.WRAP_CONTENT,
632 ViewGroup.LayoutParams.WRAP_CONTENT,
633 WindowManager.LayoutParams.TYPE_TOAST,
634 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
635 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
636 | WindowManager.LayoutParams.FLAG_BLUR_BEHIND
637 | WindowManager.LayoutParams.FLAG_DIM_BEHIND,
638 pixelFormat);
639
640 // Get the dim amount from the theme
641 TypedArray a = mContext.obtainStyledAttributes(
642 com.android.internal.R.styleable.Theme);
643 lp.dimAmount = a.getFloat(android.R.styleable.Theme_backgroundDimAmount, 0.5f);
644 a.recycle();
Wink Saville04e71b32009-04-02 11:00:54 -0700645
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800646 lp.setTitle("Battery");
647
648 TextView levelTextView = (TextView)v.findViewById(com.android.internal.R.id.level_percent);
649 levelTextView.setText(mContext.getString(
650 com.android.internal.R.string.battery_status_text_percent_format, level));
651
652 setBatteryLevel(v, com.android.internal.R.id.spacer, 100-level, 0, 0);
653 setBatteryLevel(v, com.android.internal.R.id.level, level,
654 com.android.internal.R.drawable.battery_charge_fill, level);
655
656 WindowManagerImpl.getDefault().addView(v, lp);
657
658 scheduleCloseBatteryView();
659 }
660
661 private void setBatteryLevel(View parent, int id, int height, int background, int level) {
662 ImageView v = (ImageView)parent.findViewById(id);
663 LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)v.getLayoutParams();
664 lp.weight = height;
665 if (background != 0) {
666 v.setBackgroundResource(background);
667 Drawable bkg = v.getBackground();
668 bkg.setLevel(level);
669 }
670 }
671
672 private void showLowBatteryWarning() {
673 closeLastBatteryView();
674
Mihai Predaa82842f2009-04-29 15:05:56 +0200675 /* Show exact battery level.
676 * Add 1 because the text says "less than X%".
677 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800678 CharSequence levelText = mContext.getString(
Mihai Predaa82842f2009-04-29 15:05:56 +0200679 com.android.internal.R.string.battery_low_percent_format, mBatteryLevel + 1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800680
681 if (mBatteryLevelTextView != null) {
682 mBatteryLevelTextView.setText(levelText);
683 } else {
684 View v = View.inflate(mContext, com.android.internal.R.layout.battery_low, null);
685 mBatteryLevelTextView=(TextView)v.findViewById(com.android.internal.R.id.level_percent);
686
687 mBatteryLevelTextView.setText(levelText);
688
689 AlertDialog.Builder b = new AlertDialog.Builder(mContext);
690 b.setCancelable(true);
691 b.setTitle(com.android.internal.R.string.battery_low_title);
692 b.setView(v);
693 b.setIcon(android.R.drawable.ic_dialog_alert);
694 b.setPositiveButton(android.R.string.ok, null);
johnwang347c5a22009-08-24 22:11:11 -0700695
Dianne Hackborn3d74bb42009-06-19 10:35:21 -0700696 final Intent intent = new Intent(Intent.ACTION_POWER_USAGE_SUMMARY);
697 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
698 | Intent.FLAG_ACTIVITY_MULTIPLE_TASK
699 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
700 | Intent.FLAG_ACTIVITY_NO_HISTORY);
701 if (intent.resolveActivity(mContext.getPackageManager()) != null) {
702 b.setNegativeButton(com.android.internal.R.string.battery_low_why,
703 new DialogInterface.OnClickListener() {
704 public void onClick(DialogInterface dialog, int which) {
705 mContext.startActivity(intent);
706 if (mLowBatteryDialog != null) {
707 mLowBatteryDialog.dismiss();
708 }
709 }
710 });
711 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800712
713 AlertDialog d = b.create();
714 d.setOnDismissListener(mLowBatteryListener);
715 d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
716 d.show();
717 mLowBatteryDialog = d;
718 }
719 }
720
721 private final void updateCallState(int state) {
722 mPhoneState = state;
723 if (false) {
724 Log.d(TAG, "mPhoneState=" + mPhoneState
725 + " mLowBatteryDialog=" + mLowBatteryDialog
726 + " mBatteryShowLowOnEndCall=" + mBatteryShowLowOnEndCall);
727 }
728 if (mPhoneState == TelephonyManager.CALL_STATE_IDLE) {
729 if (mBatteryShowLowOnEndCall) {
730 if (!mBatteryPlugged) {
731 showLowBatteryWarning();
732 }
733 mBatteryShowLowOnEndCall = false;
734 }
735 } else {
736 if (mLowBatteryDialog != null) {
737 mLowBatteryDialog.dismiss();
738 mBatteryShowLowOnEndCall = true;
739 }
740 }
741 }
742
743 private DialogInterface.OnDismissListener mLowBatteryListener
744 = new DialogInterface.OnDismissListener() {
745 public void onDismiss(DialogInterface dialog) {
746 mLowBatteryDialog = null;
747 mBatteryLevelTextView = null;
748 }
749 };
750
751 private void scheduleCloseBatteryView() {
752 Message m = mHandler.obtainMessage(EVENT_BATTERY_CLOSE);
753 m.arg1 = (++mBatteryViewSequence);
754 mHandler.sendMessageDelayed(m, 3000);
755 }
756
757 private void closeLastBatteryView() {
758 if (mBatteryView != null) {
759 //mBatteryView.debug();
760 WindowManagerImpl.getDefault().removeView(mBatteryView);
761 mBatteryView = null;
762 }
763 }
764
765 private PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
766 @Override
Wink Savillee9b06d72009-05-18 21:47:50 -0700767 public void onSignalStrengthsChanged(SignalStrength signalStrength) {
768 mSignalStrength = signalStrength;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800769 updateSignalStrength();
770 }
771
772 @Override
773 public void onServiceStateChanged(ServiceState state) {
774 mServiceState = state;
775 updateSignalStrength();
Wink Savillee9b06d72009-05-18 21:47:50 -0700776 updateCdmaRoamingIcon();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800777 updateDataIcon();
778 }
779
780 @Override
781 public void onCallStateChanged(int state, String incomingNumber) {
782 updateCallState(state);
johnwang347c5a22009-08-24 22:11:11 -0700783 // In cdma, if a voice call is made, RSSI should switch to 1x.
784 if (isCdma()) {
785 updateSignalStrength();
786 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800787 }
788
789 @Override
790 public void onDataConnectionStateChanged(int state) {
791 mDataState = state;
792 updateDataNetType();
793 updateDataIcon();
794 }
795
796 @Override
797 public void onDataActivity(int direction) {
798 mDataActivity = direction;
799 updateDataIcon();
800 }
801 };
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800802
803 private final void updateSimState(Intent intent) {
Wink Saville04e71b32009-04-02 11:00:54 -0700804 String stateExtra = intent.getStringExtra(IccCard.INTENT_KEY_ICC_STATE);
805 if (IccCard.INTENT_VALUE_ICC_ABSENT.equals(stateExtra)) {
806 mSimState = IccCard.State.ABSENT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800807 }
Wink Saville04e71b32009-04-02 11:00:54 -0700808 else if (IccCard.INTENT_VALUE_ICC_READY.equals(stateExtra)) {
809 mSimState = IccCard.State.READY;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800810 }
Wink Saville04e71b32009-04-02 11:00:54 -0700811 else if (IccCard.INTENT_VALUE_ICC_LOCKED.equals(stateExtra)) {
812 final String lockedReason = intent.getStringExtra(IccCard.INTENT_KEY_LOCKED_REASON);
813 if (IccCard.INTENT_VALUE_LOCKED_ON_PIN.equals(lockedReason)) {
814 mSimState = IccCard.State.PIN_REQUIRED;
johnwang347c5a22009-08-24 22:11:11 -0700815 }
Wink Saville04e71b32009-04-02 11:00:54 -0700816 else if (IccCard.INTENT_VALUE_LOCKED_ON_PUK.equals(lockedReason)) {
817 mSimState = IccCard.State.PUK_REQUIRED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800818 }
819 else {
Wink Saville04e71b32009-04-02 11:00:54 -0700820 mSimState = IccCard.State.NETWORK_LOCKED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800821 }
822 } else {
Wink Saville04e71b32009-04-02 11:00:54 -0700823 mSimState = IccCard.State.UNKNOWN;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800824 }
825 updateDataIcon();
826 }
827
Wink Savillee9b06d72009-05-18 21:47:50 -0700828 private boolean isCdma() {
Wink Savillef3152382009-06-01 14:39:20 -0700829 return ((mPhone != null) && (mPhone.getPhoneType() == TelephonyManager.PHONE_TYPE_CDMA));
Wink Savillee9b06d72009-05-18 21:47:50 -0700830 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800831
johnwang347c5a22009-08-24 22:11:11 -0700832 private boolean isEvdo() {
833 return ( (mServiceState != null)
834 && ((mServiceState.getRadioTechnology()
835 == ServiceState.RADIO_TECHNOLOGY_EVDO_0)
836 || (mServiceState.getRadioTechnology()
837 == ServiceState.RADIO_TECHNOLOGY_EVDO_A)));
838 }
839
Wink Savillee9b06d72009-05-18 21:47:50 -0700840 private boolean hasService() {
841 if (mServiceState != null) {
842 switch (mServiceState.getState()) {
843 case ServiceState.STATE_OUT_OF_SERVICE:
844 case ServiceState.STATE_POWER_OFF:
845 return false;
846 default:
847 return true;
848 }
849 } else {
850 return false;
851 }
852 }
853
854 private final void updateSignalStrength() {
855 int iconLevel = -1;
Wink Savillee9b06d72009-05-18 21:47:50 -0700856 int[] iconList;
Wink Savillee9b06d72009-05-18 21:47:50 -0700857
858 if (!hasService()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800859 //Log.d(TAG, "updateSignalStrength: no service");
860 if (Settings.System.getInt(mContext.getContentResolver(),
861 Settings.System.AIRPLANE_MODE_ON, 0) == 1) {
862 mPhoneData.iconId = com.android.internal.R.drawable.stat_sys_signal_flightmode;
863 } else {
864 mPhoneData.iconId = com.android.internal.R.drawable.stat_sys_signal_null;
865 }
866 mService.updateIcon(mPhoneIcon, mPhoneData, null);
867 return;
868 }
869
Wink Savillee9b06d72009-05-18 21:47:50 -0700870 if (!isCdma()) {
871 int asu = mSignalStrength.getGsmSignalStrength();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800872
Wink Savillee9b06d72009-05-18 21:47:50 -0700873 // ASU ranges from 0 to 31 - TS 27.007 Sec 8.5
874 // asu = 0 (-113dB or less) is very weak
875 // signal, its better to show 0 bars to the user in such cases.
876 // asu = 99 is a special case, where the signal strength is unknown.
877 if (asu <= 0 || asu == 99) iconLevel = 0;
878 else if (asu >= 16) iconLevel = 4;
879 else if (asu >= 8) iconLevel = 3;
880 else if (asu >= 4) iconLevel = 2;
881 else iconLevel = 1;
882
883 if (mPhone.isNetworkRoaming()) {
884 iconList = sSignalImages_r;
885 } else {
886 iconList = sSignalImages;
Wink Saville04e71b32009-04-02 11:00:54 -0700887 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800888 } else {
johnwang347c5a22009-08-24 22:11:11 -0700889 iconList = this.sSignalImages;
Wink Savillee9b06d72009-05-18 21:47:50 -0700890
johnwang347c5a22009-08-24 22:11:11 -0700891 // If 3G(EV) and 1x network are available than 3G should be
892 // displayed, displayed RSSI should be from the EV side.
893 // If a voice call is made then RSSI should switch to 1x.
894 if ((mPhoneState == TelephonyManager.CALL_STATE_IDLE) && isEvdo()){
895 iconLevel = getEvdoLevel();
896 if (false) {
897 Log.d(TAG, "use Evdo level=" + iconLevel + " to replace Cdma Level=" + getCdmaLevel());
898 }
899 } else {
900 iconLevel = getCdmaLevel();
901 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800902 }
Wink Savillee9b06d72009-05-18 21:47:50 -0700903 mPhoneData.iconId = iconList[iconLevel];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800904 mService.updateIcon(mPhoneIcon, mPhoneData, null);
905 }
906
johnwang347c5a22009-08-24 22:11:11 -0700907 private int getCdmaLevel() {
908 final int cdmaDbm = mSignalStrength.getCdmaDbm();
909 final int cdmaEcio = mSignalStrength.getCdmaEcio();
910 int levelDbm = 0;
911 int levelEcio = 0;
912
913 if (cdmaDbm >= -75) levelDbm = 4;
914 else if (cdmaDbm >= -85) levelDbm = 3;
915 else if (cdmaDbm >= -95) levelDbm = 2;
916 else if (cdmaDbm >= -100) levelDbm = 1;
917 else levelDbm = 0;
918
919 // Ec/Io are in dB*10
920 if (cdmaEcio >= -90) levelEcio = 4;
921 else if (cdmaEcio >= -110) levelEcio = 3;
922 else if (cdmaEcio >= -130) levelEcio = 2;
923 else if (cdmaEcio >= -150) levelEcio = 1;
924 else levelEcio = 0;
925
926 return (levelDbm < levelEcio) ? levelDbm : levelEcio;
927 }
928
929 private int getEvdoLevel() {
930 int evdoDbm = mSignalStrength.getEvdoDbm();
931 int evdoSnr = mSignalStrength.getEvdoSnr();
932 int levelEvdoDbm = 0;
933 int levelEvdoSnr = 0;
934
935 if (evdoDbm >= -65) levelEvdoDbm = 4;
936 else if (evdoDbm >= -75) levelEvdoDbm = 3;
937 else if (evdoDbm >= -90) levelEvdoDbm = 2;
938 else if (evdoDbm >= -105) levelEvdoDbm = 1;
939 else levelEvdoDbm = 0;
940
941 if (evdoSnr > 7) levelEvdoSnr = 4;
942 else if (evdoSnr > 5) levelEvdoSnr = 3;
943 else if (evdoSnr > 3) levelEvdoSnr = 2;
944 else if (evdoSnr > 1) levelEvdoSnr = 1;
945 else levelEvdoSnr = 0;
946
947 return (levelEvdoDbm < levelEvdoSnr) ? levelEvdoDbm : levelEvdoSnr;
948 }
949
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800950 private final void updateDataNetType() {
Wink Saville04e71b32009-04-02 11:00:54 -0700951 int net = mPhone.getNetworkType();
Wink Saville04e71b32009-04-02 11:00:54 -0700952
953 switch (net) {
Wink Saville04e71b32009-04-02 11:00:54 -0700954 case TelephonyManager.NETWORK_TYPE_EDGE:
955 mDataIconList = sDataNetType_e;
956 break;
957 case TelephonyManager.NETWORK_TYPE_UMTS:
958 mDataIconList = sDataNetType_3g;
959 break;
Li Zheebe66342009-08-14 19:22:16 +0800960 case TelephonyManager.NETWORK_TYPE_HSDPA:
961 case TelephonyManager.NETWORK_TYPE_HSUPA:
962 case TelephonyManager.NETWORK_TYPE_HSPA:
963 mDataIconList = sDataNetType_h;
964 break;
Wink Saville04e71b32009-04-02 11:00:54 -0700965 case TelephonyManager.NETWORK_TYPE_CDMA:
966 // display 1xRTT for IS95A/B
johnwang9f87cb22009-08-25 15:25:37 -0700967 mDataIconList = this.sDataNetType_1x;
Wink Saville04e71b32009-04-02 11:00:54 -0700968 break;
969 case TelephonyManager.NETWORK_TYPE_1xRTT:
johnwang9f87cb22009-08-25 15:25:37 -0700970 mDataIconList = this.sDataNetType_1x;
Wink Saville04e71b32009-04-02 11:00:54 -0700971 break;
972 case TelephonyManager.NETWORK_TYPE_EVDO_0: //fall through
973 case TelephonyManager.NETWORK_TYPE_EVDO_A:
johnwang9f87cb22009-08-25 15:25:37 -0700974 mDataIconList = sDataNetType_3g;
Wink Saville04e71b32009-04-02 11:00:54 -0700975 break;
976 default:
977 mDataIconList = sDataNetType_g;
978 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800979 }
980 }
981
982 private final void updateDataIcon() {
983 int iconId;
984 boolean visible = true;
985
Wink Savillee9b06d72009-05-18 21:47:50 -0700986 if (!isCdma()) {
987 // GSM case, we have to check also the sim state
988 if (mSimState == IccCard.State.READY || mSimState == IccCard.State.UNKNOWN) {
989 if (hasService() && mDataState == TelephonyManager.DATA_CONNECTED) {
990 switch (mDataActivity) {
991 case TelephonyManager.DATA_ACTIVITY_IN:
992 iconId = mDataIconList[1];
993 break;
994 case TelephonyManager.DATA_ACTIVITY_OUT:
995 iconId = mDataIconList[2];
996 break;
997 case TelephonyManager.DATA_ACTIVITY_INOUT:
998 iconId = mDataIconList[3];
999 break;
1000 default:
1001 iconId = mDataIconList[0];
1002 break;
1003 }
1004 mDataData.iconId = iconId;
1005 mService.updateIcon(mDataIcon, mDataData, null);
1006 } else {
1007 visible = false;
1008 }
1009 } else {
1010 mDataData.iconId = com.android.internal.R.drawable.stat_sys_no_sim;
1011 mService.updateIcon(mDataIcon, mDataData, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001012 }
Wink Savillee9b06d72009-05-18 21:47:50 -07001013 } else {
1014 // CDMA case, mDataActivity can be also DATA_ACTIVITY_DORMANT
1015 if (hasService() && mDataState == TelephonyManager.DATA_CONNECTED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001016 switch (mDataActivity) {
1017 case TelephonyManager.DATA_ACTIVITY_IN:
Wink Savillee9b06d72009-05-18 21:47:50 -07001018 iconId = mDataIconList[1];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001019 break;
1020 case TelephonyManager.DATA_ACTIVITY_OUT:
Wink Savillee9b06d72009-05-18 21:47:50 -07001021 iconId = mDataIconList[2];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001022 break;
1023 case TelephonyManager.DATA_ACTIVITY_INOUT:
Wink Savillee9b06d72009-05-18 21:47:50 -07001024 iconId = mDataIconList[3];
1025 break;
1026 case TelephonyManager.DATA_ACTIVITY_DORMANT:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001027 default:
Wink Savillee9b06d72009-05-18 21:47:50 -07001028 iconId = mDataIconList[0];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001029 break;
1030 }
1031 mDataData.iconId = iconId;
1032 mService.updateIcon(mDataIcon, mDataData, null);
1033 } else {
1034 visible = false;
1035 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001036 }
Wink Savillee9b06d72009-05-18 21:47:50 -07001037
Dianne Hackborn4840e142009-03-24 22:40:29 -07001038 long ident = Binder.clearCallingIdentity();
1039 try {
Wink Saville04e71b32009-04-02 11:00:54 -07001040 mBatteryStats.notePhoneDataConnectionState(mPhone.getNetworkType(), visible);
Dianne Hackborn4840e142009-03-24 22:40:29 -07001041 } catch (RemoteException e) {
1042 } finally {
1043 Binder.restoreCallingIdentity(ident);
1044 }
Wink Savillee9b06d72009-05-18 21:47:50 -07001045
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001046 if (mDataIconVisible != visible) {
1047 mService.setIconVisibility(mDataIcon, visible);
1048 mDataIconVisible = visible;
1049 }
1050 }
1051
1052 private final void updateVolume() {
1053 AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
1054 final int ringerMode = audioManager.getRingerMode();
1055 final boolean visible = ringerMode == AudioManager.RINGER_MODE_SILENT ||
Wink Savillee9b06d72009-05-18 21:47:50 -07001056 ringerMode == AudioManager.RINGER_MODE_VIBRATE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001057 final int iconId = audioManager.shouldVibrate(AudioManager.VIBRATE_TYPE_RINGER)
1058 ? com.android.internal.R.drawable.stat_sys_ringer_vibrate
1059 : com.android.internal.R.drawable.stat_sys_ringer_silent;
1060
1061 if (visible) {
1062 mVolumeData.iconId = iconId;
1063 mService.updateIcon(mVolumeIcon, mVolumeData, null);
1064 }
1065 if (visible != mVolumeVisible) {
1066 mService.setIconVisibility(mVolumeIcon, visible);
1067 mVolumeVisible = visible;
1068 }
1069 }
1070
1071 private final void updateBluetooth(Intent intent) {
1072 int iconId = com.android.internal.R.drawable.stat_sys_data_bluetooth;
1073
1074 String action = intent.getAction();
Nick Pellyde893f52009-09-08 13:15:33 -07001075 if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
1076 int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
The Android Open Source Project10592532009-03-18 17:39:46 -07001077 BluetoothError.ERROR);
Nick Pellyde893f52009-09-08 13:15:33 -07001078 mBluetoothEnabled = state == BluetoothAdapter.STATE_ON;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001079 } else if (action.equals(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION)) {
1080 mBluetoothHeadsetState = intent.getIntExtra(BluetoothIntent.HEADSET_STATE,
1081 BluetoothHeadset.STATE_ERROR);
1082 } else if (action.equals(BluetoothA2dp.SINK_STATE_CHANGED_ACTION)) {
1083 mBluetoothA2dpState = intent.getIntExtra(BluetoothA2dp.SINK_STATE,
1084 BluetoothA2dp.STATE_DISCONNECTED);
Jiafa Liu3f416732009-07-02 16:36:02 +08001085 } else if (action.equals(BluetoothPbap.PBAP_STATE_CHANGED_ACTION)) {
1086 mBluetoothPbapState = intent.getIntExtra(BluetoothPbap.PBAP_STATE,
1087 BluetoothPbap.STATE_DISCONNECTED);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001088 } else {
1089 return;
1090 }
Wink Savillee9b06d72009-05-18 21:47:50 -07001091
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001092 if (mBluetoothHeadsetState == BluetoothHeadset.STATE_CONNECTED ||
1093 mBluetoothA2dpState == BluetoothA2dp.STATE_CONNECTED ||
Jiafa Liu3f416732009-07-02 16:36:02 +08001094 mBluetoothA2dpState == BluetoothA2dp.STATE_PLAYING ||
1095 mBluetoothPbapState == BluetoothPbap.STATE_CONNECTED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001096 iconId = com.android.internal.R.drawable.stat_sys_data_bluetooth_connected;
1097 }
1098
1099 mBluetoothData.iconId = iconId;
1100 mService.updateIcon(mBluetoothIcon, mBluetoothData, null);
1101 mService.setIconVisibility(mBluetoothIcon, mBluetoothEnabled);
1102 }
1103
1104 private final void updateWifi(Intent intent) {
1105 final String action = intent.getAction();
1106 if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
Wink Savillee9b06d72009-05-18 21:47:50 -07001107
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001108 final boolean enabled = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
1109 WifiManager.WIFI_STATE_UNKNOWN) == WifiManager.WIFI_STATE_ENABLED;
Wink Savillee9b06d72009-05-18 21:47:50 -07001110
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001111 if (!enabled) {
1112 // If disabled, hide the icon. (We show icon when connected.)
1113 mService.setIconVisibility(mWifiIcon, false);
1114 }
Wink Savillee9b06d72009-05-18 21:47:50 -07001115
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001116 } else if (action.equals(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION)) {
1117 final boolean enabled = intent.getBooleanExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED,
1118 false);
1119 if (!enabled) {
1120 mService.setIconVisibility(mWifiIcon, false);
1121 }
1122 } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
1123
Wink Savillee9b06d72009-05-18 21:47:50 -07001124 final NetworkInfo networkInfo = (NetworkInfo)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001125 intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
Wink Savillee9b06d72009-05-18 21:47:50 -07001126
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001127 int iconId;
1128 if (networkInfo != null && networkInfo.isConnected()) {
1129 mIsWifiConnected = true;
1130 if (mLastWifiSignalLevel == -1) {
1131 iconId = sWifiSignalImages[0];
1132 } else {
1133 iconId = sWifiSignalImages[mLastWifiSignalLevel];
1134 }
Wink Saville04e71b32009-04-02 11:00:54 -07001135
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001136 // Show the icon since wi-fi is connected
1137 mService.setIconVisibility(mWifiIcon, true);
Wink Saville04e71b32009-04-02 11:00:54 -07001138
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001139 } else {
1140 mLastWifiSignalLevel = -1;
1141 mIsWifiConnected = false;
1142 iconId = sWifiSignalImages[0];
1143
1144 // Hide the icon since we're not connected
1145 mService.setIconVisibility(mWifiIcon, false);
1146 }
1147
1148 mWifiData.iconId = iconId;
1149 mService.updateIcon(mWifiIcon, mWifiData, null);
1150 } else if (action.equals(WifiManager.RSSI_CHANGED_ACTION)) {
1151 final int newRssi = intent.getIntExtra(WifiManager.EXTRA_NEW_RSSI, -200);
1152 int newSignalLevel = WifiManager.calculateSignalLevel(newRssi,
1153 sWifiSignalImages.length);
1154 if (newSignalLevel != mLastWifiSignalLevel) {
1155 mLastWifiSignalLevel = newSignalLevel;
1156 if (mIsWifiConnected) {
1157 mWifiData.iconId = sWifiSignalImages[newSignalLevel];
1158 } else {
1159 mWifiData.iconId = sWifiTemporarilyNotConnectedImage;
1160 }
1161 mService.updateIcon(mWifiIcon, mWifiData, null);
1162 }
1163 }
1164 }
1165
1166 private final void updateGps(Intent intent) {
1167 final String action = intent.getAction();
1168 final boolean enabled = intent.getBooleanExtra(GpsLocationProvider.EXTRA_ENABLED, false);
1169
1170 if (action.equals(GpsLocationProvider.GPS_FIX_CHANGE_ACTION) && enabled) {
1171 // GPS is getting fixes
1172 mService.updateIcon(mGpsIcon, mGpsFixIconData, null);
Wink Savillee9b06d72009-05-18 21:47:50 -07001173 mService.setIconVisibility(mGpsIcon, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001174 } else if (action.equals(GpsLocationProvider.GPS_ENABLED_CHANGE_ACTION) && !enabled) {
1175 // GPS is off
Wink Savillee9b06d72009-05-18 21:47:50 -07001176 mService.setIconVisibility(mGpsIcon, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001177 } else {
1178 // GPS is on, but not receiving fixes
1179 mService.updateIcon(mGpsIcon, mGpsEnabledIconData, null);
Wink Savillee9b06d72009-05-18 21:47:50 -07001180 mService.setIconVisibility(mGpsIcon, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001181 }
1182 }
1183
Wink Savillee9b06d72009-05-18 21:47:50 -07001184 private final void updateTTY(Intent intent) {
Wink Saville04e71b32009-04-02 11:00:54 -07001185 final String action = intent.getAction();
1186 final boolean enabled = intent.getBooleanExtra(TtyIntent.TTY_ENABLED, false);
1187
1188 Log.i(TAG, "updateTTY: enabled: " + enabled);
1189
1190 if (enabled) {
1191 // TTY is on
1192 Log.i(TAG, "updateTTY: set TTY on");
1193 mService.updateIcon(mTTYModeIcon, mTTYModeEnableIconData, null);
Wink Savillee9b06d72009-05-18 21:47:50 -07001194 mService.setIconVisibility(mTTYModeIcon, true);
Wink Saville04e71b32009-04-02 11:00:54 -07001195 } else {
1196 // TTY is off
1197 Log.i(TAG, "updateTTY: set TTY off");
Wink Savillee9b06d72009-05-18 21:47:50 -07001198 mService.setIconVisibility(mTTYModeIcon, false);
Wink Saville04e71b32009-04-02 11:00:54 -07001199 }
1200 }
1201
Wink Savillee9b06d72009-05-18 21:47:50 -07001202 private final void updateCdmaRoamingIcon() {
1203 if (!hasService()) {
1204 mService.setIconVisibility(mCdmaRoamingIndicatorIcon, false);
Wink Savillef3152382009-06-01 14:39:20 -07001205 return;
Wink Savillee9b06d72009-05-18 21:47:50 -07001206 }
1207
1208 if (!isCdma()) {
1209 mService.setIconVisibility(mCdmaRoamingIndicatorIcon, false);
Wink Savillef3152382009-06-01 14:39:20 -07001210 return;
Wink Savillee9b06d72009-05-18 21:47:50 -07001211 }
1212
1213 int[] iconList = sRoamingIndicatorImages_cdma;
1214 int iconIndex = mPhone.getCdmaEriIconIndex();
1215 int iconMode = mPhone.getCdmaEriIconMode();
1216
1217 if (iconIndex == -1) {
1218 Log.e(TAG, "getCdmaEriIconIndex returned null, skipping ERI icon update");
1219 return;
1220 }
1221
1222 if (iconMode == -1) {
1223 Log.e(TAG, "getCdmeEriIconMode returned null, skipping ERI icon update");
1224 return;
1225 }
1226
1227 if (iconIndex == EriInfo.ROAMING_INDICATOR_OFF) {
1228 Log.d(TAG, "Cdma ROAMING_INDICATOR_OFF, removing ERI icon");
1229 mService.setIconVisibility(mCdmaRoamingIndicatorIcon, false);
1230 return;
1231 }
1232
1233 switch (iconMode) {
1234 case EriInfo.ROAMING_ICON_MODE_NORMAL:
1235 mCdmaRoamingIndicatorIconData.iconId = iconList[iconIndex];
1236 mService.updateIcon(mCdmaRoamingIndicatorIcon, mCdmaRoamingIndicatorIconData, null);
1237 mService.setIconVisibility(mCdmaRoamingIndicatorIcon, true);
1238 break;
1239 case EriInfo.ROAMING_ICON_MODE_FLASH:
Wink Savillef3152382009-06-01 14:39:20 -07001240 mCdmaRoamingIndicatorIconData.iconId =
1241 com.android.internal.R.drawable.stat_sys_roaming_cdma_flash;
Wink Savillee9b06d72009-05-18 21:47:50 -07001242 mService.updateIcon(mCdmaRoamingIndicatorIcon, mCdmaRoamingIndicatorIconData, null);
Wink Savillef3152382009-06-01 14:39:20 -07001243 mService.setIconVisibility(mCdmaRoamingIndicatorIcon, true);
Wink Savillee9b06d72009-05-18 21:47:50 -07001244 break;
1245
1246 }
1247 mService.updateIcon(mPhoneIcon, mPhoneData, null);
1248 }
1249
1250
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001251 private class StatusBarHandler extends Handler {
1252 @Override
1253 public void handleMessage(Message msg) {
1254 switch (msg.what) {
1255 case EVENT_BATTERY_CLOSE:
1256 if (msg.arg1 == mBatteryViewSequence) {
1257 closeLastBatteryView();
1258 }
1259 break;
1260 }
1261 }
1262 }
1263}