blob: f3127f3de028d0e1a6a592b20b161ff02f7ad418 [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 Project9066cfe2009-03-03 19:31:44 -080022import android.bluetooth.BluetoothHeadset;
23import android.bluetooth.BluetoothIntent;
Jiafa Liu3f416732009-07-02 16:36:02 +080024import android.bluetooth.BluetoothPbap;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080025import 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 Hackborn4840e142009-03-24 22:40:29 -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 Hackborn4840e142009-03-24 22:40:29 -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 Saville04e71b32009-04-02 11:00:54 -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 Saville04e71b32009-04-02 11:00:54 -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
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080079 private static final int EVENT_BATTERY_CLOSE = 4;
80
Dianne Hackborn4840e142009-03-24 22:40:29 -070081 private final Context mContext;
82 private final StatusBarService mService;
83 private final Handler mHandler = new StatusBarHandler();
84 private final IBatteryStats mBatteryStats;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080085
86 // clock
87 private Calendar mCalendar;
88 private IBinder mClockIcon;
89 private IconData mClockData;
90
91 // battery
92 private IBinder mBatteryIcon;
93 private IconData mBatteryData;
94 private boolean mBatteryFirst = true;
95 private boolean mBatteryPlugged;
96 private int mBatteryLevel;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080097 private AlertDialog mLowBatteryDialog;
98 private TextView mBatteryLevelTextView;
99 private View mBatteryView;
100 private int mBatteryViewSequence;
101 private boolean mBatteryShowLowOnEndCall = false;
102 private static final boolean SHOW_LOW_BATTERY_WARNING = true;
103
104 // phone
105 private TelephonyManager mPhone;
106 private IBinder mPhoneIcon;
Wink Saville04e71b32009-04-02 11:00:54 -0700107
108 //***** Signal strength icons
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800109 private IconData mPhoneData;
Wink Saville04e71b32009-04-02 11:00:54 -0700110 //GSM/UMTS
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800111 private static final int[] sSignalImages = new int[] {
Wink Savillee9b06d72009-05-18 21:47:50 -0700112 com.android.internal.R.drawable.stat_sys_signal_0,
113 com.android.internal.R.drawable.stat_sys_signal_1,
114 com.android.internal.R.drawable.stat_sys_signal_2,
115 com.android.internal.R.drawable.stat_sys_signal_3,
116 com.android.internal.R.drawable.stat_sys_signal_4
117 };
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800118 private static final int[] sSignalImages_r = new int[] {
Wink Savillee9b06d72009-05-18 21:47:50 -0700119 com.android.internal.R.drawable.stat_sys_r_signal_0,
120 com.android.internal.R.drawable.stat_sys_r_signal_1,
121 com.android.internal.R.drawable.stat_sys_r_signal_2,
122 com.android.internal.R.drawable.stat_sys_r_signal_3,
123 com.android.internal.R.drawable.stat_sys_r_signal_4
124 };
Wink Savillee9b06d72009-05-18 21:47:50 -0700125 private static final int[] sRoamingIndicatorImages_cdma = new int[] {
126 com.android.internal.R.drawable.stat_sys_roaming_cdma_0, //Standard Roaming Indicator
127 // 1 is Standard Roaming Indicator OFF
128 // TODO T: image never used, remove and put 0 instead?
129 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
130
131 // 2 is Standard Roaming Indicator FLASHING
132 // TODO T: image never used, remove and put 0 instead?
133 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
134
135 // 3-12 Standard ERI
136 com.android.internal.R.drawable.stat_sys_roaming_cdma_0, //3
137 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
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
147 // 13-63 Reserved for Standard ERI
148 com.android.internal.R.drawable.stat_sys_roaming_cdma_0, //13
149 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
150 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
151 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
152 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
153 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
154 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
155 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
156 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
157 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
200 // 64-127 Reserved for Non Standard (Operator Specific) ERI
201 com.android.internal.R.drawable.stat_sys_roaming_cdma_0, //64
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 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 //83
221
222 // 128-255 Reserved
Wink Saville04e71b32009-04-02 11:00:54 -0700223 };
Wink Saville04e71b32009-04-02 11:00:54 -0700224
225 //***** Data connection icons
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800226 private int[] mDataIconList = sDataNetType_g;
Wink Saville04e71b32009-04-02 11:00:54 -0700227 //GSM/UMTS
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800228 private static final int[] sDataNetType_g = new int[] {
229 com.android.internal.R.drawable.stat_sys_data_connected_g,
230 com.android.internal.R.drawable.stat_sys_data_in_g,
231 com.android.internal.R.drawable.stat_sys_data_out_g,
232 com.android.internal.R.drawable.stat_sys_data_inandout_g,
233 };
234 private static final int[] sDataNetType_3g = new int[] {
235 com.android.internal.R.drawable.stat_sys_data_connected_3g,
236 com.android.internal.R.drawable.stat_sys_data_in_3g,
237 com.android.internal.R.drawable.stat_sys_data_out_3g,
238 com.android.internal.R.drawable.stat_sys_data_inandout_3g,
239 };
240 private static final int[] sDataNetType_e = new int[] {
241 com.android.internal.R.drawable.stat_sys_data_connected_e,
242 com.android.internal.R.drawable.stat_sys_data_in_e,
243 com.android.internal.R.drawable.stat_sys_data_out_e,
244 com.android.internal.R.drawable.stat_sys_data_inandout_e,
245 };
Li Zheebe66342009-08-14 19:22:16 +0800246 //3.5G
247 private static final int[] sDataNetType_h = new int[] {
248 com.android.internal.R.drawable.stat_sys_data_connected_h,
249 com.android.internal.R.drawable.stat_sys_data_in_h,
250 com.android.internal.R.drawable.stat_sys_data_out_h,
251 com.android.internal.R.drawable.stat_sys_data_inandout_h,
252 };
253
Wink Saville04e71b32009-04-02 11:00:54 -0700254 //CDMA
johnwang9f87cb22009-08-25 15:25:37 -0700255 // Use 3G icons for EVDO data and 1x icons for 1XRTT data
256 private static final int[] sDataNetType_1x = new int[] {
257 com.android.internal.R.drawable.stat_sys_data_connected_1x,
258 com.android.internal.R.drawable.stat_sys_data_in_1x,
259 com.android.internal.R.drawable.stat_sys_data_out_1x,
260 com.android.internal.R.drawable.stat_sys_data_inandout_1x,
Wink Saville04e71b32009-04-02 11:00:54 -0700261 };
262
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800263 // Assume it's all good unless we hear otherwise. We don't always seem
264 // to get broadcasts that it *is* there.
Wink Saville04e71b32009-04-02 11:00:54 -0700265 IccCard.State mSimState = IccCard.State.READY;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800266 int mPhoneState = TelephonyManager.CALL_STATE_IDLE;
267 int mDataState = TelephonyManager.DATA_DISCONNECTED;
268 int mDataActivity = TelephonyManager.DATA_ACTIVITY_NONE;
269 ServiceState mServiceState;
Wink Savillee9b06d72009-05-18 21:47:50 -0700270 SignalStrength mSignalStrength;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800271
272 // data connection
273 private IBinder mDataIcon;
274 private IconData mDataData;
275 private boolean mDataIconVisible;
276
277 // ringer volume
278 private IBinder mVolumeIcon;
279 private IconData mVolumeData;
280 private boolean mVolumeVisible;
Wink Saville04e71b32009-04-02 11:00:54 -0700281
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800282 // bluetooth device status
283 private IBinder mBluetoothIcon;
284 private IconData mBluetoothData;
285 private int mBluetoothHeadsetState;
286 private int mBluetoothA2dpState;
Jiafa Liu3f416732009-07-02 16:36:02 +0800287 private int mBluetoothPbapState;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800288 private boolean mBluetoothEnabled;
289
290 // wifi
291 private static final int[] sWifiSignalImages = new int[] {
292 com.android.internal.R.drawable.stat_sys_wifi_signal_1,
293 com.android.internal.R.drawable.stat_sys_wifi_signal_2,
294 com.android.internal.R.drawable.stat_sys_wifi_signal_3,
295 com.android.internal.R.drawable.stat_sys_wifi_signal_4,
296 };
297 private static final int sWifiTemporarilyNotConnectedImage =
298 com.android.internal.R.drawable.stat_sys_wifi_signal_0;
299
300 private int mLastWifiSignalLevel = -1;
301 private boolean mIsWifiConnected = false;
302 private IBinder mWifiIcon;
303 private IconData mWifiData;
304
305 // gps
306 private IBinder mGpsIcon;
307 private IconData mGpsEnabledIconData;
308 private IconData mGpsFixIconData;
309
310 // alarm clock
311 // Icon lit when clock is set
312 private IBinder mAlarmClockIcon;
313 private IconData mAlarmClockIconData;
314
315 // sync state
316 // If sync is active the SyncActive icon is displayed. If sync is not active but
317 // sync is failing the SyncFailing icon is displayed. Otherwise neither are displayed.
318 private IBinder mSyncActiveIcon;
319 private IBinder mSyncFailingIcon;
320
Wink Saville04e71b32009-04-02 11:00:54 -0700321 // TTY mode
322 // Icon lit when TTY mode is enabled
323 private IBinder mTTYModeIcon;
324 private IconData mTTYModeEnableIconData;
325
Wink Savillee9b06d72009-05-18 21:47:50 -0700326 // Cdma Roaming Indicator, ERI
327 private IBinder mCdmaRoamingIndicatorIcon;
328 private IconData mCdmaRoamingIndicatorIconData;
329
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800330 private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
331 @Override
332 public void onReceive(Context context, Intent intent) {
333 String action = intent.getAction();
334 if (action.equals(Intent.ACTION_TIME_TICK)) {
335 updateClock();
336 }
337 else if (action.equals(Intent.ACTION_TIME_CHANGED)) {
338 updateClock();
339 }
Dianne Hackborn8ec5b832009-07-01 21:19:35 -0700340 else if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
341 updateBattery(intent);
342 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800343 else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
344 updateClock();
345 }
346 else if (action.equals(Intent.ACTION_TIMEZONE_CHANGED)) {
347 String tz = intent.getStringExtra("time-zone");
348 mCalendar = Calendar.getInstance(TimeZone.getTimeZone(tz));
349 updateClock();
350 }
351 else if (action.equals(Intent.ACTION_ALARM_CHANGED)) {
352 updateAlarm(intent);
353 }
354 else if (action.equals(Intent.ACTION_SYNC_STATE_CHANGED)) {
355 updateSyncState(intent);
356 }
Mihai Predaa82842f2009-04-29 15:05:56 +0200357 else if (action.equals(Intent.ACTION_BATTERY_LOW)) {
358 onBatteryLow(intent);
359 }
Mike Lockwood69eb0bf2009-08-01 23:02:28 -0400360 else if (action.equals(Intent.ACTION_BATTERY_OKAY)
361 || action.equals(Intent.ACTION_POWER_CONNECTED)) {
Dianne Hackborn8ec5b832009-07-01 21:19:35 -0700362 onBatteryOkay(intent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800363 }
Nick Pellyde893f52009-09-08 13:15:33 -0700364 else if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED) ||
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800365 action.equals(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION) ||
Jiafa Liu3f416732009-07-02 16:36:02 +0800366 action.equals(BluetoothA2dp.SINK_STATE_CHANGED_ACTION) ||
367 action.equals(BluetoothPbap.PBAP_STATE_CHANGED_ACTION)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800368 updateBluetooth(intent);
369 }
370 else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION) ||
371 action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION) ||
372 action.equals(WifiManager.RSSI_CHANGED_ACTION)) {
373 updateWifi(intent);
374 }
375 else if (action.equals(GpsLocationProvider.GPS_ENABLED_CHANGE_ACTION) ||
376 action.equals(GpsLocationProvider.GPS_FIX_CHANGE_ACTION)) {
377 updateGps(intent);
378 }
379 else if (action.equals(AudioManager.RINGER_MODE_CHANGED_ACTION) ||
380 action.equals(AudioManager.VIBRATE_SETTING_CHANGED_ACTION)) {
381 updateVolume();
382 }
383 else if (action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) {
384 updateSimState(intent);
385 }
Wink Saville04e71b32009-04-02 11:00:54 -0700386 else if (action.equals(TtyIntent.TTY_ENABLED_CHANGE_ACTION)) {
387 updateTTY(intent);
388 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800389 }
390 };
391
392 private StatusBarPolicy(Context context, StatusBarService service) {
393 mContext = context;
394 mService = service;
Wink Savillee9b06d72009-05-18 21:47:50 -0700395 mSignalStrength = new SignalStrength();
Dianne Hackborn4840e142009-03-24 22:40:29 -0700396 mBatteryStats = BatteryStatsService.getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800397
398 // clock
399 mCalendar = Calendar.getInstance(TimeZone.getDefault());
400 mClockData = IconData.makeText("clock", "");
401 mClockIcon = service.addIcon(mClockData, null);
402 updateClock();
403
404 // battery
405 mBatteryData = IconData.makeIcon("battery",
406 null, com.android.internal.R.drawable.stat_sys_battery_unknown, 0, 0);
407 mBatteryIcon = service.addIcon(mBatteryData, null);
408
409 // phone_signal
410 mPhone = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
Wink Savillee9b06d72009-05-18 21:47:50 -0700411 mPhoneData = IconData.makeIcon("phone_signal",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800412 null, com.android.internal.R.drawable.stat_sys_signal_null, 0, 0);
413 mPhoneIcon = service.addIcon(mPhoneData, null);
Wink Savillee9b06d72009-05-18 21:47:50 -0700414
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800415 // register for phone state notifications.
416 ((TelephonyManager)mContext.getSystemService(Context.TELEPHONY_SERVICE))
417 .listen(mPhoneStateListener,
418 PhoneStateListener.LISTEN_SERVICE_STATE
Wink Savillee9b06d72009-05-18 21:47:50 -0700419 | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800420 | PhoneStateListener.LISTEN_CALL_STATE
421 | PhoneStateListener.LISTEN_DATA_CONNECTION_STATE
422 | PhoneStateListener.LISTEN_DATA_ACTIVITY);
423
424 // data_connection
425 mDataData = IconData.makeIcon("data_connection",
426 null, com.android.internal.R.drawable.stat_sys_data_connected_g, 0, 0);
427 mDataIcon = service.addIcon(mDataData, null);
428 service.setIconVisibility(mDataIcon, false);
429
430 // wifi
431 mWifiData = IconData.makeIcon("wifi", null, sWifiSignalImages[0], 0, 0);
432 mWifiIcon = service.addIcon(mWifiData, null);
433 service.setIconVisibility(mWifiIcon, false);
434 // wifi will get updated by the sticky intents
Wink Saville04e71b32009-04-02 11:00:54 -0700435
436 // TTY status
437 mTTYModeEnableIconData = IconData.makeIcon("tty",
438 null, com.android.internal.R.drawable.stat_sys_tty_mode, 0, 0);
439 mTTYModeIcon = service.addIcon(mTTYModeEnableIconData, null);
440 service.setIconVisibility(mTTYModeIcon, false);
441
Wink Savillee9b06d72009-05-18 21:47:50 -0700442 // Cdma Roaming Indicator, ERI
443 mCdmaRoamingIndicatorIconData = IconData.makeIcon("cdma_eri",
444 null, com.android.internal.R.drawable.stat_sys_roaming_cdma_0, 0, 0);
445 mCdmaRoamingIndicatorIcon = service.addIcon(mCdmaRoamingIndicatorIconData, null);
446 service.setIconVisibility(mCdmaRoamingIndicatorIcon, false);
447
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800448 // bluetooth status
449 mBluetoothData = IconData.makeIcon("bluetooth",
450 null, com.android.internal.R.drawable.stat_sys_data_bluetooth, 0, 0);
451 mBluetoothIcon = service.addIcon(mBluetoothData, null);
Nick Pellybd022f42009-08-14 18:33:38 -0700452 BluetoothAdapter adapter =
453 (BluetoothAdapter) mContext.getSystemService(Context.BLUETOOTH_SERVICE);
454 if (adapter != null) {
455 mBluetoothEnabled = adapter.isEnabled();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800456 } else {
457 mBluetoothEnabled = false;
458 }
459 mBluetoothA2dpState = BluetoothA2dp.STATE_DISCONNECTED;
460 mBluetoothHeadsetState = BluetoothHeadset.STATE_DISCONNECTED;
Jiafa Liu3f416732009-07-02 16:36:02 +0800461 mBluetoothPbapState = BluetoothPbap.STATE_DISCONNECTED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800462 mService.setIconVisibility(mBluetoothIcon, mBluetoothEnabled);
463
464 // Gps status
465 mGpsEnabledIconData = IconData.makeIcon("gps",
466 null, com.android.internal.R.drawable.stat_sys_gps_acquiring_anim, 0, 0);
467 mGpsFixIconData = IconData.makeIcon("gps",
468 null, com.android.internal.R.drawable.stat_sys_gps_on, 0, 0);
469 mGpsIcon = service.addIcon(mGpsEnabledIconData, null);
johnwang347c5a22009-08-24 22:11:11 -0700470 service.setIconVisibility(mGpsIcon, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800471
472 // Alarm clock
473 mAlarmClockIconData = IconData.makeIcon(
474 "alarm_clock",
475 null, com.android.internal.R.drawable.stat_notify_alarm, 0, 0);
476 mAlarmClockIcon = service.addIcon(mAlarmClockIconData, null);
477 service.setIconVisibility(mAlarmClockIcon, false);
478
479 // Sync state
480 mSyncActiveIcon = service.addIcon(IconData.makeIcon("sync_active",
481 null, R.drawable.stat_notify_sync_anim0, 0, 0), null);
482 mSyncFailingIcon = service.addIcon(IconData.makeIcon("sync_failing",
483 null, R.drawable.stat_notify_sync_error, 0, 0), null);
484 service.setIconVisibility(mSyncActiveIcon, false);
485 service.setIconVisibility(mSyncFailingIcon, false);
486
487 // volume
488 mVolumeData = IconData.makeIcon("volume",
489 null, com.android.internal.R.drawable.stat_sys_ringer_silent, 0, 0);
490 mVolumeIcon = service.addIcon(mVolumeData, null);
491 service.setIconVisibility(mVolumeIcon, false);
492 updateVolume();
johnwang347c5a22009-08-24 22:11:11 -0700493
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800494 IntentFilter filter = new IntentFilter();
495
496 // Register for Intent broadcasts for...
497 filter.addAction(Intent.ACTION_TIME_TICK);
498 filter.addAction(Intent.ACTION_TIME_CHANGED);
499 filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
500 filter.addAction(Intent.ACTION_BATTERY_CHANGED);
Mihai Predaa82842f2009-04-29 15:05:56 +0200501 filter.addAction(Intent.ACTION_BATTERY_LOW);
Dianne Hackborn8ec5b832009-07-01 21:19:35 -0700502 filter.addAction(Intent.ACTION_BATTERY_OKAY);
Mike Lockwood69eb0bf2009-08-01 23:02:28 -0400503 filter.addAction(Intent.ACTION_POWER_CONNECTED);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800504 filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
505 filter.addAction(Intent.ACTION_ALARM_CHANGED);
506 filter.addAction(Intent.ACTION_SYNC_STATE_CHANGED);
507 filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
508 filter.addAction(AudioManager.VIBRATE_SETTING_CHANGED_ACTION);
Nick Pellyde893f52009-09-08 13:15:33 -0700509 filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800510 filter.addAction(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION);
511 filter.addAction(BluetoothA2dp.SINK_STATE_CHANGED_ACTION);
Jiafa Liu3f416732009-07-02 16:36:02 +0800512 filter.addAction(BluetoothPbap.PBAP_STATE_CHANGED_ACTION);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800513 filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
514 filter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
515 filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
516 filter.addAction(WifiManager.RSSI_CHANGED_ACTION);
517 filter.addAction(GpsLocationProvider.GPS_ENABLED_CHANGE_ACTION);
518 filter.addAction(GpsLocationProvider.GPS_FIX_CHANGE_ACTION);
519 filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
Wink Saville04e71b32009-04-02 11:00:54 -0700520 filter.addAction(TtyIntent.TTY_ENABLED_CHANGE_ACTION);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800521 mContext.registerReceiver(mIntentReceiver, filter, null, mHandler);
522 }
523
524 public static void installIcons(Context context, StatusBarService service) {
525 sInstance = new StatusBarPolicy(context, service);
526 }
527
528 private final void updateClock() {
529 mCalendar.setTimeInMillis(System.currentTimeMillis());
530 mClockData.text = DateFormat.getTimeFormat(mContext)
531 .format(mCalendar.getTime());
532 mService.updateIcon(mClockIcon, mClockData, null);
533 }
534
535 private final void updateAlarm(Intent intent) {
536 boolean alarmSet = intent.getBooleanExtra("alarmSet", false);
537 mService.setIconVisibility(mAlarmClockIcon, alarmSet);
538 }
539
540 private final void updateSyncState(Intent intent) {
541 boolean isActive = intent.getBooleanExtra("active", false);
542 boolean isFailing = intent.getBooleanExtra("failing", false);
543 mService.setIconVisibility(mSyncActiveIcon, isActive);
544 // Don't display sync failing icon: BUG 1297963 Set sync error timeout to "never"
545 //mService.setIconVisibility(mSyncFailingIcon, isFailing && !isActive);
546 }
547
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800548 private final void updateBattery(Intent intent) {
549 mBatteryData.iconId = intent.getIntExtra("icon-small", 0);
550 mBatteryData.iconLevel = intent.getIntExtra("level", 0);
551 mService.updateIcon(mBatteryIcon, mBatteryData, null);
552
553 boolean plugged = intent.getIntExtra("plugged", 0) != 0;
554 int level = intent.getIntExtra("level", -1);
555 if (false) {
556 Log.d(TAG, "updateBattery level=" + level
557 + " plugged=" + plugged
558 + " mBatteryPlugged=" + mBatteryPlugged
559 + " mBatteryLevel=" + mBatteryLevel
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800560 + " mBatteryFirst=" + mBatteryFirst);
561 }
562
563 boolean oldPlugged = mBatteryPlugged;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800564
565 mBatteryPlugged = plugged;
566 mBatteryLevel = level;
567
568 if (mBatteryFirst) {
569 mBatteryFirst = false;
570 }
571 /*
572 * No longer showing the battery view because it draws attention away
573 * from the USB storage notification. We could still show it when
574 * connected to a brick, but that could lead to the user into thinking
575 * the device does not charge when plugged into USB (since he/she would
576 * not see the same battery screen on USB as he sees on brick).
577 */
578 /* else {
579 if (plugged && !oldPlugged) {
580 showBatteryView();
581 }
582 }
583 */
584 if (false) {
Mihai Predaa82842f2009-04-29 15:05:56 +0200585 Log.d(TAG, "plugged=" + plugged + " oldPlugged=" + oldPlugged + " level=" + level);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800586 }
Mihai Predaa82842f2009-04-29 15:05:56 +0200587 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800588
Mihai Predaa82842f2009-04-29 15:05:56 +0200589 private void onBatteryLow(Intent intent) {
590 if (SHOW_LOW_BATTERY_WARNING) {
591 if (false) {
592 Log.d(TAG, "mPhoneState=" + mPhoneState
593 + " mLowBatteryDialog=" + mLowBatteryDialog
594 + " mBatteryShowLowOnEndCall=" + mBatteryShowLowOnEndCall);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800595 }
Mihai Predaa82842f2009-04-29 15:05:56 +0200596
597 if (mPhoneState == TelephonyManager.CALL_STATE_IDLE) {
598 showLowBatteryWarning();
599 } else {
600 mBatteryShowLowOnEndCall = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800601 }
602 }
603 }
604
Dianne Hackborn8ec5b832009-07-01 21:19:35 -0700605 private void onBatteryOkay(Intent intent) {
606 if (mLowBatteryDialog != null
607 && SHOW_LOW_BATTERY_WARNING) {
608 mLowBatteryDialog.dismiss();
609 mBatteryShowLowOnEndCall = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800610 }
611 }
612
johnwang347c5a22009-08-24 22:11:11 -0700613 private void showBatteryView() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800614 closeLastBatteryView();
615 if (mLowBatteryDialog != null) {
616 mLowBatteryDialog.dismiss();
617 }
618
619 int level = mBatteryLevel;
620
621 View v = View.inflate(mContext, com.android.internal.R.layout.battery_status, null);
622 mBatteryView = v;
623 int pixelFormat = PixelFormat.TRANSLUCENT;
624 Drawable bg = v.getBackground();
625 if (bg != null) {
626 pixelFormat = bg.getOpacity();
627 }
628
629 WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
630 ViewGroup.LayoutParams.WRAP_CONTENT,
631 ViewGroup.LayoutParams.WRAP_CONTENT,
632 WindowManager.LayoutParams.TYPE_TOAST,
633 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
634 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
635 | WindowManager.LayoutParams.FLAG_BLUR_BEHIND
636 | WindowManager.LayoutParams.FLAG_DIM_BEHIND,
637 pixelFormat);
638
639 // Get the dim amount from the theme
640 TypedArray a = mContext.obtainStyledAttributes(
641 com.android.internal.R.styleable.Theme);
642 lp.dimAmount = a.getFloat(android.R.styleable.Theme_backgroundDimAmount, 0.5f);
643 a.recycle();
Wink Saville04e71b32009-04-02 11:00:54 -0700644
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800645 lp.setTitle("Battery");
646
647 TextView levelTextView = (TextView)v.findViewById(com.android.internal.R.id.level_percent);
648 levelTextView.setText(mContext.getString(
649 com.android.internal.R.string.battery_status_text_percent_format, level));
650
651 setBatteryLevel(v, com.android.internal.R.id.spacer, 100-level, 0, 0);
652 setBatteryLevel(v, com.android.internal.R.id.level, level,
653 com.android.internal.R.drawable.battery_charge_fill, level);
654
655 WindowManagerImpl.getDefault().addView(v, lp);
656
657 scheduleCloseBatteryView();
658 }
659
660 private void setBatteryLevel(View parent, int id, int height, int background, int level) {
661 ImageView v = (ImageView)parent.findViewById(id);
662 LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)v.getLayoutParams();
663 lp.weight = height;
664 if (background != 0) {
665 v.setBackgroundResource(background);
666 Drawable bkg = v.getBackground();
667 bkg.setLevel(level);
668 }
669 }
670
671 private void showLowBatteryWarning() {
672 closeLastBatteryView();
673
Mihai Predaa82842f2009-04-29 15:05:56 +0200674 /* Show exact battery level.
675 * Add 1 because the text says "less than X%".
676 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800677 CharSequence levelText = mContext.getString(
Mihai Predaa82842f2009-04-29 15:05:56 +0200678 com.android.internal.R.string.battery_low_percent_format, mBatteryLevel + 1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800679
680 if (mBatteryLevelTextView != null) {
681 mBatteryLevelTextView.setText(levelText);
682 } else {
683 View v = View.inflate(mContext, com.android.internal.R.layout.battery_low, null);
684 mBatteryLevelTextView=(TextView)v.findViewById(com.android.internal.R.id.level_percent);
685
686 mBatteryLevelTextView.setText(levelText);
687
688 AlertDialog.Builder b = new AlertDialog.Builder(mContext);
689 b.setCancelable(true);
690 b.setTitle(com.android.internal.R.string.battery_low_title);
691 b.setView(v);
692 b.setIcon(android.R.drawable.ic_dialog_alert);
693 b.setPositiveButton(android.R.string.ok, null);
johnwang347c5a22009-08-24 22:11:11 -0700694
Dianne Hackborn3d74bb42009-06-19 10:35:21 -0700695 final Intent intent = new Intent(Intent.ACTION_POWER_USAGE_SUMMARY);
696 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
697 | Intent.FLAG_ACTIVITY_MULTIPLE_TASK
698 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
699 | Intent.FLAG_ACTIVITY_NO_HISTORY);
700 if (intent.resolveActivity(mContext.getPackageManager()) != null) {
701 b.setNegativeButton(com.android.internal.R.string.battery_low_why,
702 new DialogInterface.OnClickListener() {
703 public void onClick(DialogInterface dialog, int which) {
704 mContext.startActivity(intent);
705 if (mLowBatteryDialog != null) {
706 mLowBatteryDialog.dismiss();
707 }
708 }
709 });
710 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800711
712 AlertDialog d = b.create();
713 d.setOnDismissListener(mLowBatteryListener);
714 d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
715 d.show();
716 mLowBatteryDialog = d;
717 }
718 }
719
720 private final void updateCallState(int state) {
721 mPhoneState = state;
722 if (false) {
723 Log.d(TAG, "mPhoneState=" + mPhoneState
724 + " mLowBatteryDialog=" + mLowBatteryDialog
725 + " mBatteryShowLowOnEndCall=" + mBatteryShowLowOnEndCall);
726 }
727 if (mPhoneState == TelephonyManager.CALL_STATE_IDLE) {
728 if (mBatteryShowLowOnEndCall) {
729 if (!mBatteryPlugged) {
730 showLowBatteryWarning();
731 }
732 mBatteryShowLowOnEndCall = false;
733 }
734 } else {
735 if (mLowBatteryDialog != null) {
736 mLowBatteryDialog.dismiss();
737 mBatteryShowLowOnEndCall = true;
738 }
739 }
740 }
741
742 private DialogInterface.OnDismissListener mLowBatteryListener
743 = new DialogInterface.OnDismissListener() {
744 public void onDismiss(DialogInterface dialog) {
745 mLowBatteryDialog = null;
746 mBatteryLevelTextView = null;
747 }
748 };
749
750 private void scheduleCloseBatteryView() {
751 Message m = mHandler.obtainMessage(EVENT_BATTERY_CLOSE);
752 m.arg1 = (++mBatteryViewSequence);
753 mHandler.sendMessageDelayed(m, 3000);
754 }
755
756 private void closeLastBatteryView() {
757 if (mBatteryView != null) {
758 //mBatteryView.debug();
759 WindowManagerImpl.getDefault().removeView(mBatteryView);
760 mBatteryView = null;
761 }
762 }
763
764 private PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
765 @Override
Wink Savillee9b06d72009-05-18 21:47:50 -0700766 public void onSignalStrengthsChanged(SignalStrength signalStrength) {
767 mSignalStrength = signalStrength;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800768 updateSignalStrength();
769 }
770
771 @Override
772 public void onServiceStateChanged(ServiceState state) {
773 mServiceState = state;
774 updateSignalStrength();
Wink Savillee9b06d72009-05-18 21:47:50 -0700775 updateCdmaRoamingIcon();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800776 updateDataIcon();
777 }
778
779 @Override
780 public void onCallStateChanged(int state, String incomingNumber) {
781 updateCallState(state);
johnwang347c5a22009-08-24 22:11:11 -0700782 // In cdma, if a voice call is made, RSSI should switch to 1x.
783 if (isCdma()) {
784 updateSignalStrength();
785 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800786 }
787
788 @Override
789 public void onDataConnectionStateChanged(int state) {
790 mDataState = state;
791 updateDataNetType();
792 updateDataIcon();
793 }
794
795 @Override
796 public void onDataActivity(int direction) {
797 mDataActivity = direction;
798 updateDataIcon();
799 }
800 };
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800801
802 private final void updateSimState(Intent intent) {
Wink Saville04e71b32009-04-02 11:00:54 -0700803 String stateExtra = intent.getStringExtra(IccCard.INTENT_KEY_ICC_STATE);
804 if (IccCard.INTENT_VALUE_ICC_ABSENT.equals(stateExtra)) {
805 mSimState = IccCard.State.ABSENT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800806 }
Wink Saville04e71b32009-04-02 11:00:54 -0700807 else if (IccCard.INTENT_VALUE_ICC_READY.equals(stateExtra)) {
808 mSimState = IccCard.State.READY;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800809 }
Wink Saville04e71b32009-04-02 11:00:54 -0700810 else if (IccCard.INTENT_VALUE_ICC_LOCKED.equals(stateExtra)) {
811 final String lockedReason = intent.getStringExtra(IccCard.INTENT_KEY_LOCKED_REASON);
812 if (IccCard.INTENT_VALUE_LOCKED_ON_PIN.equals(lockedReason)) {
813 mSimState = IccCard.State.PIN_REQUIRED;
johnwang347c5a22009-08-24 22:11:11 -0700814 }
Wink Saville04e71b32009-04-02 11:00:54 -0700815 else if (IccCard.INTENT_VALUE_LOCKED_ON_PUK.equals(lockedReason)) {
816 mSimState = IccCard.State.PUK_REQUIRED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800817 }
818 else {
Wink Saville04e71b32009-04-02 11:00:54 -0700819 mSimState = IccCard.State.NETWORK_LOCKED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800820 }
821 } else {
Wink Saville04e71b32009-04-02 11:00:54 -0700822 mSimState = IccCard.State.UNKNOWN;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800823 }
824 updateDataIcon();
825 }
826
Wink Savillee9b06d72009-05-18 21:47:50 -0700827 private boolean isCdma() {
Wink Savillef3152382009-06-01 14:39:20 -0700828 return ((mPhone != null) && (mPhone.getPhoneType() == TelephonyManager.PHONE_TYPE_CDMA));
Wink Savillee9b06d72009-05-18 21:47:50 -0700829 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800830
johnwang347c5a22009-08-24 22:11:11 -0700831 private boolean isEvdo() {
832 return ( (mServiceState != null)
833 && ((mServiceState.getRadioTechnology()
834 == ServiceState.RADIO_TECHNOLOGY_EVDO_0)
835 || (mServiceState.getRadioTechnology()
836 == ServiceState.RADIO_TECHNOLOGY_EVDO_A)));
837 }
838
Wink Savillee9b06d72009-05-18 21:47:50 -0700839 private boolean hasService() {
840 if (mServiceState != null) {
841 switch (mServiceState.getState()) {
842 case ServiceState.STATE_OUT_OF_SERVICE:
843 case ServiceState.STATE_POWER_OFF:
844 return false;
845 default:
846 return true;
847 }
848 } else {
849 return false;
850 }
851 }
852
853 private final void updateSignalStrength() {
854 int iconLevel = -1;
Wink Savillee9b06d72009-05-18 21:47:50 -0700855 int[] iconList;
Wink Savillee9b06d72009-05-18 21:47:50 -0700856
857 if (!hasService()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800858 //Log.d(TAG, "updateSignalStrength: no service");
859 if (Settings.System.getInt(mContext.getContentResolver(),
860 Settings.System.AIRPLANE_MODE_ON, 0) == 1) {
861 mPhoneData.iconId = com.android.internal.R.drawable.stat_sys_signal_flightmode;
862 } else {
863 mPhoneData.iconId = com.android.internal.R.drawable.stat_sys_signal_null;
864 }
865 mService.updateIcon(mPhoneIcon, mPhoneData, null);
866 return;
867 }
868
Wink Savillee9b06d72009-05-18 21:47:50 -0700869 if (!isCdma()) {
870 int asu = mSignalStrength.getGsmSignalStrength();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800871
Wink Savillee9b06d72009-05-18 21:47:50 -0700872 // ASU ranges from 0 to 31 - TS 27.007 Sec 8.5
873 // asu = 0 (-113dB or less) is very weak
874 // signal, its better to show 0 bars to the user in such cases.
875 // asu = 99 is a special case, where the signal strength is unknown.
876 if (asu <= 0 || asu == 99) iconLevel = 0;
877 else if (asu >= 16) iconLevel = 4;
878 else if (asu >= 8) iconLevel = 3;
879 else if (asu >= 4) iconLevel = 2;
880 else iconLevel = 1;
881
882 if (mPhone.isNetworkRoaming()) {
883 iconList = sSignalImages_r;
884 } else {
885 iconList = sSignalImages;
Wink Saville04e71b32009-04-02 11:00:54 -0700886 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800887 } else {
johnwang347c5a22009-08-24 22:11:11 -0700888 iconList = this.sSignalImages;
Wink Savillee9b06d72009-05-18 21:47:50 -0700889
johnwang347c5a22009-08-24 22:11:11 -0700890 // If 3G(EV) and 1x network are available than 3G should be
891 // displayed, displayed RSSI should be from the EV side.
892 // If a voice call is made then RSSI should switch to 1x.
893 if ((mPhoneState == TelephonyManager.CALL_STATE_IDLE) && isEvdo()){
894 iconLevel = getEvdoLevel();
895 if (false) {
896 Log.d(TAG, "use Evdo level=" + iconLevel + " to replace Cdma Level=" + getCdmaLevel());
897 }
898 } else {
899 iconLevel = getCdmaLevel();
900 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800901 }
Wink Savillee9b06d72009-05-18 21:47:50 -0700902 mPhoneData.iconId = iconList[iconLevel];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800903 mService.updateIcon(mPhoneIcon, mPhoneData, null);
904 }
905
johnwang347c5a22009-08-24 22:11:11 -0700906 private int getCdmaLevel() {
907 final int cdmaDbm = mSignalStrength.getCdmaDbm();
908 final int cdmaEcio = mSignalStrength.getCdmaEcio();
909 int levelDbm = 0;
910 int levelEcio = 0;
911
912 if (cdmaDbm >= -75) levelDbm = 4;
913 else if (cdmaDbm >= -85) levelDbm = 3;
914 else if (cdmaDbm >= -95) levelDbm = 2;
915 else if (cdmaDbm >= -100) levelDbm = 1;
916 else levelDbm = 0;
917
918 // Ec/Io are in dB*10
919 if (cdmaEcio >= -90) levelEcio = 4;
920 else if (cdmaEcio >= -110) levelEcio = 3;
921 else if (cdmaEcio >= -130) levelEcio = 2;
922 else if (cdmaEcio >= -150) levelEcio = 1;
923 else levelEcio = 0;
924
925 return (levelDbm < levelEcio) ? levelDbm : levelEcio;
926 }
927
928 private int getEvdoLevel() {
929 int evdoDbm = mSignalStrength.getEvdoDbm();
930 int evdoSnr = mSignalStrength.getEvdoSnr();
931 int levelEvdoDbm = 0;
932 int levelEvdoSnr = 0;
933
934 if (evdoDbm >= -65) levelEvdoDbm = 4;
935 else if (evdoDbm >= -75) levelEvdoDbm = 3;
936 else if (evdoDbm >= -90) levelEvdoDbm = 2;
937 else if (evdoDbm >= -105) levelEvdoDbm = 1;
938 else levelEvdoDbm = 0;
939
940 if (evdoSnr > 7) levelEvdoSnr = 4;
941 else if (evdoSnr > 5) levelEvdoSnr = 3;
942 else if (evdoSnr > 3) levelEvdoSnr = 2;
943 else if (evdoSnr > 1) levelEvdoSnr = 1;
944 else levelEvdoSnr = 0;
945
946 return (levelEvdoDbm < levelEvdoSnr) ? levelEvdoDbm : levelEvdoSnr;
947 }
948
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800949 private final void updateDataNetType() {
Wink Saville04e71b32009-04-02 11:00:54 -0700950 int net = mPhone.getNetworkType();
Wink Saville04e71b32009-04-02 11:00:54 -0700951
952 switch (net) {
Wink Saville04e71b32009-04-02 11:00:54 -0700953 case TelephonyManager.NETWORK_TYPE_EDGE:
954 mDataIconList = sDataNetType_e;
955 break;
956 case TelephonyManager.NETWORK_TYPE_UMTS:
957 mDataIconList = sDataNetType_3g;
958 break;
Li Zheebe66342009-08-14 19:22:16 +0800959 case TelephonyManager.NETWORK_TYPE_HSDPA:
960 case TelephonyManager.NETWORK_TYPE_HSUPA:
961 case TelephonyManager.NETWORK_TYPE_HSPA:
962 mDataIconList = sDataNetType_h;
963 break;
Wink Saville04e71b32009-04-02 11:00:54 -0700964 case TelephonyManager.NETWORK_TYPE_CDMA:
965 // display 1xRTT for IS95A/B
johnwang9f87cb22009-08-25 15:25:37 -0700966 mDataIconList = this.sDataNetType_1x;
Wink Saville04e71b32009-04-02 11:00:54 -0700967 break;
968 case TelephonyManager.NETWORK_TYPE_1xRTT:
johnwang9f87cb22009-08-25 15:25:37 -0700969 mDataIconList = this.sDataNetType_1x;
Wink Saville04e71b32009-04-02 11:00:54 -0700970 break;
971 case TelephonyManager.NETWORK_TYPE_EVDO_0: //fall through
972 case TelephonyManager.NETWORK_TYPE_EVDO_A:
johnwang9f87cb22009-08-25 15:25:37 -0700973 mDataIconList = sDataNetType_3g;
Wink Saville04e71b32009-04-02 11:00:54 -0700974 break;
975 default:
976 mDataIconList = sDataNetType_g;
977 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800978 }
979 }
980
981 private final void updateDataIcon() {
982 int iconId;
983 boolean visible = true;
984
Wink Savillee9b06d72009-05-18 21:47:50 -0700985 if (!isCdma()) {
986 // GSM case, we have to check also the sim state
987 if (mSimState == IccCard.State.READY || mSimState == IccCard.State.UNKNOWN) {
988 if (hasService() && mDataState == TelephonyManager.DATA_CONNECTED) {
989 switch (mDataActivity) {
990 case TelephonyManager.DATA_ACTIVITY_IN:
991 iconId = mDataIconList[1];
992 break;
993 case TelephonyManager.DATA_ACTIVITY_OUT:
994 iconId = mDataIconList[2];
995 break;
996 case TelephonyManager.DATA_ACTIVITY_INOUT:
997 iconId = mDataIconList[3];
998 break;
999 default:
1000 iconId = mDataIconList[0];
1001 break;
1002 }
1003 mDataData.iconId = iconId;
1004 mService.updateIcon(mDataIcon, mDataData, null);
1005 } else {
1006 visible = false;
1007 }
1008 } else {
1009 mDataData.iconId = com.android.internal.R.drawable.stat_sys_no_sim;
1010 mService.updateIcon(mDataIcon, mDataData, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001011 }
Wink Savillee9b06d72009-05-18 21:47:50 -07001012 } else {
1013 // CDMA case, mDataActivity can be also DATA_ACTIVITY_DORMANT
1014 if (hasService() && mDataState == TelephonyManager.DATA_CONNECTED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001015 switch (mDataActivity) {
1016 case TelephonyManager.DATA_ACTIVITY_IN:
Wink Savillee9b06d72009-05-18 21:47:50 -07001017 iconId = mDataIconList[1];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001018 break;
1019 case TelephonyManager.DATA_ACTIVITY_OUT:
Wink Savillee9b06d72009-05-18 21:47:50 -07001020 iconId = mDataIconList[2];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001021 break;
1022 case TelephonyManager.DATA_ACTIVITY_INOUT:
Wink Savillee9b06d72009-05-18 21:47:50 -07001023 iconId = mDataIconList[3];
1024 break;
1025 case TelephonyManager.DATA_ACTIVITY_DORMANT:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001026 default:
Wink Savillee9b06d72009-05-18 21:47:50 -07001027 iconId = mDataIconList[0];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001028 break;
1029 }
1030 mDataData.iconId = iconId;
1031 mService.updateIcon(mDataIcon, mDataData, null);
1032 } else {
1033 visible = false;
1034 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001035 }
Wink Savillee9b06d72009-05-18 21:47:50 -07001036
Dianne Hackborn4840e142009-03-24 22:40:29 -07001037 long ident = Binder.clearCallingIdentity();
1038 try {
Wink Saville04e71b32009-04-02 11:00:54 -07001039 mBatteryStats.notePhoneDataConnectionState(mPhone.getNetworkType(), visible);
Dianne Hackborn4840e142009-03-24 22:40:29 -07001040 } catch (RemoteException e) {
1041 } finally {
1042 Binder.restoreCallingIdentity(ident);
1043 }
Wink Savillee9b06d72009-05-18 21:47:50 -07001044
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001045 if (mDataIconVisible != visible) {
1046 mService.setIconVisibility(mDataIcon, visible);
1047 mDataIconVisible = visible;
1048 }
1049 }
1050
1051 private final void updateVolume() {
1052 AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
1053 final int ringerMode = audioManager.getRingerMode();
1054 final boolean visible = ringerMode == AudioManager.RINGER_MODE_SILENT ||
Wink Savillee9b06d72009-05-18 21:47:50 -07001055 ringerMode == AudioManager.RINGER_MODE_VIBRATE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001056 final int iconId = audioManager.shouldVibrate(AudioManager.VIBRATE_TYPE_RINGER)
1057 ? com.android.internal.R.drawable.stat_sys_ringer_vibrate
1058 : com.android.internal.R.drawable.stat_sys_ringer_silent;
1059
1060 if (visible) {
1061 mVolumeData.iconId = iconId;
1062 mService.updateIcon(mVolumeIcon, mVolumeData, null);
1063 }
1064 if (visible != mVolumeVisible) {
1065 mService.setIconVisibility(mVolumeIcon, visible);
1066 mVolumeVisible = visible;
1067 }
1068 }
1069
1070 private final void updateBluetooth(Intent intent) {
1071 int iconId = com.android.internal.R.drawable.stat_sys_data_bluetooth;
1072
1073 String action = intent.getAction();
Nick Pellyde893f52009-09-08 13:15:33 -07001074 if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
Nick Pellyb24e11b2009-09-08 17:40:43 -07001075 int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
Nick Pellyde893f52009-09-08 13:15:33 -07001076 mBluetoothEnabled = state == BluetoothAdapter.STATE_ON;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001077 } else if (action.equals(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION)) {
1078 mBluetoothHeadsetState = intent.getIntExtra(BluetoothIntent.HEADSET_STATE,
1079 BluetoothHeadset.STATE_ERROR);
1080 } else if (action.equals(BluetoothA2dp.SINK_STATE_CHANGED_ACTION)) {
1081 mBluetoothA2dpState = intent.getIntExtra(BluetoothA2dp.SINK_STATE,
1082 BluetoothA2dp.STATE_DISCONNECTED);
Jiafa Liu3f416732009-07-02 16:36:02 +08001083 } else if (action.equals(BluetoothPbap.PBAP_STATE_CHANGED_ACTION)) {
1084 mBluetoothPbapState = intent.getIntExtra(BluetoothPbap.PBAP_STATE,
1085 BluetoothPbap.STATE_DISCONNECTED);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001086 } else {
1087 return;
1088 }
Wink Savillee9b06d72009-05-18 21:47:50 -07001089
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001090 if (mBluetoothHeadsetState == BluetoothHeadset.STATE_CONNECTED ||
1091 mBluetoothA2dpState == BluetoothA2dp.STATE_CONNECTED ||
Jiafa Liu3f416732009-07-02 16:36:02 +08001092 mBluetoothA2dpState == BluetoothA2dp.STATE_PLAYING ||
1093 mBluetoothPbapState == BluetoothPbap.STATE_CONNECTED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001094 iconId = com.android.internal.R.drawable.stat_sys_data_bluetooth_connected;
1095 }
1096
1097 mBluetoothData.iconId = iconId;
1098 mService.updateIcon(mBluetoothIcon, mBluetoothData, null);
1099 mService.setIconVisibility(mBluetoothIcon, mBluetoothEnabled);
1100 }
1101
1102 private final void updateWifi(Intent intent) {
1103 final String action = intent.getAction();
1104 if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
Wink Savillee9b06d72009-05-18 21:47:50 -07001105
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001106 final boolean enabled = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
1107 WifiManager.WIFI_STATE_UNKNOWN) == WifiManager.WIFI_STATE_ENABLED;
Wink Savillee9b06d72009-05-18 21:47:50 -07001108
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001109 if (!enabled) {
1110 // If disabled, hide the icon. (We show icon when connected.)
1111 mService.setIconVisibility(mWifiIcon, false);
1112 }
Wink Savillee9b06d72009-05-18 21:47:50 -07001113
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001114 } else if (action.equals(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION)) {
1115 final boolean enabled = intent.getBooleanExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED,
1116 false);
1117 if (!enabled) {
1118 mService.setIconVisibility(mWifiIcon, false);
1119 }
1120 } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
1121
Wink Savillee9b06d72009-05-18 21:47:50 -07001122 final NetworkInfo networkInfo = (NetworkInfo)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001123 intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
Wink Savillee9b06d72009-05-18 21:47:50 -07001124
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001125 int iconId;
1126 if (networkInfo != null && networkInfo.isConnected()) {
1127 mIsWifiConnected = true;
1128 if (mLastWifiSignalLevel == -1) {
1129 iconId = sWifiSignalImages[0];
1130 } else {
1131 iconId = sWifiSignalImages[mLastWifiSignalLevel];
1132 }
Wink Saville04e71b32009-04-02 11:00:54 -07001133
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001134 // Show the icon since wi-fi is connected
1135 mService.setIconVisibility(mWifiIcon, true);
Wink Saville04e71b32009-04-02 11:00:54 -07001136
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001137 } else {
1138 mLastWifiSignalLevel = -1;
1139 mIsWifiConnected = false;
1140 iconId = sWifiSignalImages[0];
1141
1142 // Hide the icon since we're not connected
1143 mService.setIconVisibility(mWifiIcon, false);
1144 }
1145
1146 mWifiData.iconId = iconId;
1147 mService.updateIcon(mWifiIcon, mWifiData, null);
1148 } else if (action.equals(WifiManager.RSSI_CHANGED_ACTION)) {
1149 final int newRssi = intent.getIntExtra(WifiManager.EXTRA_NEW_RSSI, -200);
1150 int newSignalLevel = WifiManager.calculateSignalLevel(newRssi,
1151 sWifiSignalImages.length);
1152 if (newSignalLevel != mLastWifiSignalLevel) {
1153 mLastWifiSignalLevel = newSignalLevel;
1154 if (mIsWifiConnected) {
1155 mWifiData.iconId = sWifiSignalImages[newSignalLevel];
1156 } else {
1157 mWifiData.iconId = sWifiTemporarilyNotConnectedImage;
1158 }
1159 mService.updateIcon(mWifiIcon, mWifiData, null);
1160 }
1161 }
1162 }
1163
1164 private final void updateGps(Intent intent) {
1165 final String action = intent.getAction();
1166 final boolean enabled = intent.getBooleanExtra(GpsLocationProvider.EXTRA_ENABLED, false);
1167
1168 if (action.equals(GpsLocationProvider.GPS_FIX_CHANGE_ACTION) && enabled) {
1169 // GPS is getting fixes
1170 mService.updateIcon(mGpsIcon, mGpsFixIconData, null);
Wink Savillee9b06d72009-05-18 21:47:50 -07001171 mService.setIconVisibility(mGpsIcon, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001172 } else if (action.equals(GpsLocationProvider.GPS_ENABLED_CHANGE_ACTION) && !enabled) {
1173 // GPS is off
Wink Savillee9b06d72009-05-18 21:47:50 -07001174 mService.setIconVisibility(mGpsIcon, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001175 } else {
1176 // GPS is on, but not receiving fixes
1177 mService.updateIcon(mGpsIcon, mGpsEnabledIconData, null);
Wink Savillee9b06d72009-05-18 21:47:50 -07001178 mService.setIconVisibility(mGpsIcon, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001179 }
1180 }
1181
Wink Savillee9b06d72009-05-18 21:47:50 -07001182 private final void updateTTY(Intent intent) {
Wink Saville04e71b32009-04-02 11:00:54 -07001183 final String action = intent.getAction();
1184 final boolean enabled = intent.getBooleanExtra(TtyIntent.TTY_ENABLED, false);
1185
1186 Log.i(TAG, "updateTTY: enabled: " + enabled);
1187
1188 if (enabled) {
1189 // TTY is on
1190 Log.i(TAG, "updateTTY: set TTY on");
1191 mService.updateIcon(mTTYModeIcon, mTTYModeEnableIconData, null);
Wink Savillee9b06d72009-05-18 21:47:50 -07001192 mService.setIconVisibility(mTTYModeIcon, true);
Wink Saville04e71b32009-04-02 11:00:54 -07001193 } else {
1194 // TTY is off
1195 Log.i(TAG, "updateTTY: set TTY off");
Wink Savillee9b06d72009-05-18 21:47:50 -07001196 mService.setIconVisibility(mTTYModeIcon, false);
Wink Saville04e71b32009-04-02 11:00:54 -07001197 }
1198 }
1199
Wink Savillee9b06d72009-05-18 21:47:50 -07001200 private final void updateCdmaRoamingIcon() {
1201 if (!hasService()) {
1202 mService.setIconVisibility(mCdmaRoamingIndicatorIcon, false);
Wink Savillef3152382009-06-01 14:39:20 -07001203 return;
Wink Savillee9b06d72009-05-18 21:47:50 -07001204 }
1205
1206 if (!isCdma()) {
1207 mService.setIconVisibility(mCdmaRoamingIndicatorIcon, false);
Wink Savillef3152382009-06-01 14:39:20 -07001208 return;
Wink Savillee9b06d72009-05-18 21:47:50 -07001209 }
1210
1211 int[] iconList = sRoamingIndicatorImages_cdma;
1212 int iconIndex = mPhone.getCdmaEriIconIndex();
1213 int iconMode = mPhone.getCdmaEriIconMode();
1214
1215 if (iconIndex == -1) {
1216 Log.e(TAG, "getCdmaEriIconIndex returned null, skipping ERI icon update");
1217 return;
1218 }
1219
1220 if (iconMode == -1) {
1221 Log.e(TAG, "getCdmeEriIconMode returned null, skipping ERI icon update");
1222 return;
1223 }
1224
1225 if (iconIndex == EriInfo.ROAMING_INDICATOR_OFF) {
1226 Log.d(TAG, "Cdma ROAMING_INDICATOR_OFF, removing ERI icon");
1227 mService.setIconVisibility(mCdmaRoamingIndicatorIcon, false);
1228 return;
1229 }
1230
1231 switch (iconMode) {
1232 case EriInfo.ROAMING_ICON_MODE_NORMAL:
1233 mCdmaRoamingIndicatorIconData.iconId = iconList[iconIndex];
1234 mService.updateIcon(mCdmaRoamingIndicatorIcon, mCdmaRoamingIndicatorIconData, null);
1235 mService.setIconVisibility(mCdmaRoamingIndicatorIcon, true);
1236 break;
1237 case EriInfo.ROAMING_ICON_MODE_FLASH:
Wink Savillef3152382009-06-01 14:39:20 -07001238 mCdmaRoamingIndicatorIconData.iconId =
1239 com.android.internal.R.drawable.stat_sys_roaming_cdma_flash;
Wink Savillee9b06d72009-05-18 21:47:50 -07001240 mService.updateIcon(mCdmaRoamingIndicatorIcon, mCdmaRoamingIndicatorIconData, null);
Wink Savillef3152382009-06-01 14:39:20 -07001241 mService.setIconVisibility(mCdmaRoamingIndicatorIcon, true);
Wink Savillee9b06d72009-05-18 21:47:50 -07001242 break;
1243
1244 }
1245 mService.updateIcon(mPhoneIcon, mPhoneData, null);
1246 }
1247
1248
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001249 private class StatusBarHandler extends Handler {
1250 @Override
1251 public void handleMessage(Message msg) {
1252 switch (msg.what) {
1253 case EVENT_BATTERY_CLOSE:
1254 if (msg.arg1 == mBatteryViewSequence) {
1255 closeLastBatteryView();
1256 }
1257 break;
1258 }
1259 }
1260 }
1261}