blob: 33d899accc2502b0153e8ebad9f6df691b14b49b [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 Savillee9b06d72009-05-18 21:47:50 -0700108 private IBinder mPhoneEvdoIcon;
Wink Saville04e71b32009-04-02 11:00:54 -0700109
110 //***** Signal strength icons
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800111 private IconData mPhoneData;
Wink Savillee9b06d72009-05-18 21:47:50 -0700112 private IconData mPhoneEvdoData;
Wink Saville04e71b32009-04-02 11:00:54 -0700113 //GSM/UMTS
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800114 private static final int[] sSignalImages = new int[] {
Wink Savillee9b06d72009-05-18 21:47:50 -0700115 com.android.internal.R.drawable.stat_sys_signal_0,
116 com.android.internal.R.drawable.stat_sys_signal_1,
117 com.android.internal.R.drawable.stat_sys_signal_2,
118 com.android.internal.R.drawable.stat_sys_signal_3,
119 com.android.internal.R.drawable.stat_sys_signal_4
120 };
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800121 private static final int[] sSignalImages_r = new int[] {
Wink Savillee9b06d72009-05-18 21:47:50 -0700122 com.android.internal.R.drawable.stat_sys_r_signal_0,
123 com.android.internal.R.drawable.stat_sys_r_signal_1,
124 com.android.internal.R.drawable.stat_sys_r_signal_2,
125 com.android.internal.R.drawable.stat_sys_r_signal_3,
126 com.android.internal.R.drawable.stat_sys_r_signal_4
127 };
Wink Saville04e71b32009-04-02 11:00:54 -0700128 //CDMA
129 private static final int[] sSignalImages_cdma = new int[] {
Wink Savillee9b06d72009-05-18 21:47:50 -0700130 com.android.internal.R.drawable.stat_sys_signal_cdma_0,
131 com.android.internal.R.drawable.stat_sys_signal_cdma_1,
132 com.android.internal.R.drawable.stat_sys_signal_cdma_2,
133 com.android.internal.R.drawable.stat_sys_signal_cdma_3,
134 com.android.internal.R.drawable.stat_sys_signal_cdma_4
Wink Saville04e71b32009-04-02 11:00:54 -0700135 };
Wink Savillee9b06d72009-05-18 21:47:50 -0700136 private static final int[] sRoamingIndicatorImages_cdma = new int[] {
137 com.android.internal.R.drawable.stat_sys_roaming_cdma_0, //Standard Roaming Indicator
138 // 1 is Standard Roaming Indicator OFF
139 // TODO T: image never used, remove and put 0 instead?
140 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
141
142 // 2 is Standard Roaming Indicator FLASHING
143 // TODO T: image never used, remove and put 0 instead?
144 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
145
146 // 3-12 Standard ERI
147 com.android.internal.R.drawable.stat_sys_roaming_cdma_0, //3
148 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
149 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
150 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
151 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
152 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
153 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
154 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
155 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
156 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
157
158 // 13-63 Reserved for Standard ERI
159 com.android.internal.R.drawable.stat_sys_roaming_cdma_0, //13
160 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
161 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
162 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
163 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
164 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
165 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
166 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
167 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
168 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
169 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
170 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
171 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
172 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
173 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
174 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
175 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
176 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
177 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
178 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
179 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
180 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
181 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
182 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
183 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
184 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
185 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
186 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
187 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
188 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
189 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
190 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
191 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
192 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
193 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
194 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
195 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
196 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
197 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
198 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
199 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
200 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
201 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
202 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
203 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
204 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
205 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
206 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
207 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
208 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
209 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
210
211 // 64-127 Reserved for Non Standard (Operator Specific) ERI
212 com.android.internal.R.drawable.stat_sys_roaming_cdma_0, //64
213 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
214 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
215 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
216 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
217 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
218 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
219 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
220 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
221 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
222 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
223 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
224 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
225 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
226 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
227 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
228 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
229 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
230 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
231 com.android.internal.R.drawable.stat_sys_roaming_cdma_0 //83
232
233 // 128-255 Reserved
Wink Saville04e71b32009-04-02 11:00:54 -0700234 };
Wink Savillee9b06d72009-05-18 21:47:50 -0700235 // EVDO
236 private static final int[] sSignalImages_evdo = new int[] {
237 com.android.internal.R.drawable.stat_sys_signal_evdo_0,
238 com.android.internal.R.drawable.stat_sys_signal_evdo_1,
239 com.android.internal.R.drawable.stat_sys_signal_evdo_2,
240 com.android.internal.R.drawable.stat_sys_signal_evdo_3,
241 com.android.internal.R.drawable.stat_sys_signal_evdo_4
Wink Saville04e71b32009-04-02 11:00:54 -0700242 };
243
244 //***** Data connection icons
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800245 private int[] mDataIconList = sDataNetType_g;
Wink Saville04e71b32009-04-02 11:00:54 -0700246 //GSM/UMTS
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800247 private static final int[] sDataNetType_g = new int[] {
248 com.android.internal.R.drawable.stat_sys_data_connected_g,
249 com.android.internal.R.drawable.stat_sys_data_in_g,
250 com.android.internal.R.drawable.stat_sys_data_out_g,
251 com.android.internal.R.drawable.stat_sys_data_inandout_g,
252 };
253 private static final int[] sDataNetType_3g = new int[] {
254 com.android.internal.R.drawable.stat_sys_data_connected_3g,
255 com.android.internal.R.drawable.stat_sys_data_in_3g,
256 com.android.internal.R.drawable.stat_sys_data_out_3g,
257 com.android.internal.R.drawable.stat_sys_data_inandout_3g,
258 };
259 private static final int[] sDataNetType_e = new int[] {
260 com.android.internal.R.drawable.stat_sys_data_connected_e,
261 com.android.internal.R.drawable.stat_sys_data_in_e,
262 com.android.internal.R.drawable.stat_sys_data_out_e,
263 com.android.internal.R.drawable.stat_sys_data_inandout_e,
264 };
Wink Saville04e71b32009-04-02 11:00:54 -0700265 //CDMA
266 private static final int[] sDataNetType_evdo = new int[] {
267 com.android.internal.R.drawable.stat_sys_data_connected_evdo,
268 com.android.internal.R.drawable.stat_sys_data_in_evdo,
269 com.android.internal.R.drawable.stat_sys_data_out_evdo,
270 com.android.internal.R.drawable.stat_sys_data_inandout_evdo,
Wink Savillee9b06d72009-05-18 21:47:50 -0700271 com.android.internal.R.drawable.stat_sys_data_dormant_evdo,
Wink Saville04e71b32009-04-02 11:00:54 -0700272 };
273 private static final int[] sDataNetType_1xrtt = new int[] {
274 com.android.internal.R.drawable.stat_sys_data_connected_1xrtt,
275 com.android.internal.R.drawable.stat_sys_data_in_1xrtt,
276 com.android.internal.R.drawable.stat_sys_data_out_1xrtt,
277 com.android.internal.R.drawable.stat_sys_data_inandout_1xrtt,
Wink Savillee9b06d72009-05-18 21:47:50 -0700278 com.android.internal.R.drawable.stat_sys_data_dormant_1xrtt,
Wink Saville04e71b32009-04-02 11:00:54 -0700279 };
280
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800281 // Assume it's all good unless we hear otherwise. We don't always seem
282 // to get broadcasts that it *is* there.
Wink Saville04e71b32009-04-02 11:00:54 -0700283 IccCard.State mSimState = IccCard.State.READY;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800284 int mPhoneState = TelephonyManager.CALL_STATE_IDLE;
285 int mDataState = TelephonyManager.DATA_DISCONNECTED;
286 int mDataActivity = TelephonyManager.DATA_ACTIVITY_NONE;
287 ServiceState mServiceState;
Wink Savillee9b06d72009-05-18 21:47:50 -0700288 SignalStrength mSignalStrength;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800289
290 // data connection
291 private IBinder mDataIcon;
292 private IconData mDataData;
293 private boolean mDataIconVisible;
294
295 // ringer volume
296 private IBinder mVolumeIcon;
297 private IconData mVolumeData;
298 private boolean mVolumeVisible;
Wink Saville04e71b32009-04-02 11:00:54 -0700299
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800300 // bluetooth device status
301 private IBinder mBluetoothIcon;
302 private IconData mBluetoothData;
303 private int mBluetoothHeadsetState;
304 private int mBluetoothA2dpState;
Jiafa Liu3f416732009-07-02 16:36:02 +0800305 private int mBluetoothPbapState;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800306 private boolean mBluetoothEnabled;
307
308 // wifi
309 private static final int[] sWifiSignalImages = new int[] {
310 com.android.internal.R.drawable.stat_sys_wifi_signal_1,
311 com.android.internal.R.drawable.stat_sys_wifi_signal_2,
312 com.android.internal.R.drawable.stat_sys_wifi_signal_3,
313 com.android.internal.R.drawable.stat_sys_wifi_signal_4,
314 };
315 private static final int sWifiTemporarilyNotConnectedImage =
316 com.android.internal.R.drawable.stat_sys_wifi_signal_0;
317
318 private int mLastWifiSignalLevel = -1;
319 private boolean mIsWifiConnected = false;
320 private IBinder mWifiIcon;
321 private IconData mWifiData;
322
323 // gps
324 private IBinder mGpsIcon;
325 private IconData mGpsEnabledIconData;
326 private IconData mGpsFixIconData;
327
328 // alarm clock
329 // Icon lit when clock is set
330 private IBinder mAlarmClockIcon;
331 private IconData mAlarmClockIconData;
332
333 // sync state
334 // If sync is active the SyncActive icon is displayed. If sync is not active but
335 // sync is failing the SyncFailing icon is displayed. Otherwise neither are displayed.
336 private IBinder mSyncActiveIcon;
337 private IBinder mSyncFailingIcon;
338
Wink Saville04e71b32009-04-02 11:00:54 -0700339 // TTY mode
340 // Icon lit when TTY mode is enabled
341 private IBinder mTTYModeIcon;
342 private IconData mTTYModeEnableIconData;
343
Wink Savillee9b06d72009-05-18 21:47:50 -0700344 // Cdma Roaming Indicator, ERI
345 private IBinder mCdmaRoamingIndicatorIcon;
346 private IconData mCdmaRoamingIndicatorIconData;
347
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800348 private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
349 @Override
350 public void onReceive(Context context, Intent intent) {
351 String action = intent.getAction();
352 if (action.equals(Intent.ACTION_TIME_TICK)) {
353 updateClock();
354 }
355 else if (action.equals(Intent.ACTION_TIME_CHANGED)) {
356 updateClock();
357 }
Dianne Hackborn8ec5b832009-07-01 21:19:35 -0700358 else if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
359 updateBattery(intent);
360 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800361 else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
362 updateClock();
363 }
364 else if (action.equals(Intent.ACTION_TIMEZONE_CHANGED)) {
365 String tz = intent.getStringExtra("time-zone");
366 mCalendar = Calendar.getInstance(TimeZone.getTimeZone(tz));
367 updateClock();
368 }
369 else if (action.equals(Intent.ACTION_ALARM_CHANGED)) {
370 updateAlarm(intent);
371 }
372 else if (action.equals(Intent.ACTION_SYNC_STATE_CHANGED)) {
373 updateSyncState(intent);
374 }
Mihai Predaa82842f2009-04-29 15:05:56 +0200375 else if (action.equals(Intent.ACTION_BATTERY_LOW)) {
376 onBatteryLow(intent);
377 }
Mike Lockwood69eb0bf2009-08-01 23:02:28 -0400378 else if (action.equals(Intent.ACTION_BATTERY_OKAY)
379 || action.equals(Intent.ACTION_POWER_CONNECTED)) {
Dianne Hackborn8ec5b832009-07-01 21:19:35 -0700380 onBatteryOkay(intent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800381 }
The Android Open Source Project10592532009-03-18 17:39:46 -0700382 else if (action.equals(BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION) ||
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800383 action.equals(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION) ||
Jiafa Liu3f416732009-07-02 16:36:02 +0800384 action.equals(BluetoothA2dp.SINK_STATE_CHANGED_ACTION) ||
385 action.equals(BluetoothPbap.PBAP_STATE_CHANGED_ACTION)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800386 updateBluetooth(intent);
387 }
388 else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION) ||
389 action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION) ||
390 action.equals(WifiManager.RSSI_CHANGED_ACTION)) {
391 updateWifi(intent);
392 }
393 else if (action.equals(GpsLocationProvider.GPS_ENABLED_CHANGE_ACTION) ||
394 action.equals(GpsLocationProvider.GPS_FIX_CHANGE_ACTION)) {
395 updateGps(intent);
396 }
397 else if (action.equals(AudioManager.RINGER_MODE_CHANGED_ACTION) ||
398 action.equals(AudioManager.VIBRATE_SETTING_CHANGED_ACTION)) {
399 updateVolume();
400 }
401 else if (action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) {
402 updateSimState(intent);
403 }
Wink Saville04e71b32009-04-02 11:00:54 -0700404 else if (action.equals(TtyIntent.TTY_ENABLED_CHANGE_ACTION)) {
405 updateTTY(intent);
406 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800407 }
408 };
409
410 private StatusBarPolicy(Context context, StatusBarService service) {
411 mContext = context;
412 mService = service;
Wink Savillee9b06d72009-05-18 21:47:50 -0700413 mSignalStrength = new SignalStrength();
Dianne Hackborn4840e142009-03-24 22:40:29 -0700414 mBatteryStats = BatteryStatsService.getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800415
416 // clock
417 mCalendar = Calendar.getInstance(TimeZone.getDefault());
418 mClockData = IconData.makeText("clock", "");
419 mClockIcon = service.addIcon(mClockData, null);
420 updateClock();
421
422 // battery
423 mBatteryData = IconData.makeIcon("battery",
424 null, com.android.internal.R.drawable.stat_sys_battery_unknown, 0, 0);
425 mBatteryIcon = service.addIcon(mBatteryData, null);
426
427 // phone_signal
428 mPhone = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
Wink Savillee9b06d72009-05-18 21:47:50 -0700429 mPhoneData = IconData.makeIcon("phone_signal",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800430 null, com.android.internal.R.drawable.stat_sys_signal_null, 0, 0);
431 mPhoneIcon = service.addIcon(mPhoneData, null);
Wink Savillee9b06d72009-05-18 21:47:50 -0700432
433 // phone_evdo_signal
434 mPhoneEvdoData = IconData.makeIcon("phone_evdo_signal",
435 null, com.android.internal.R.drawable.stat_sys_signal_evdo_0, 0, 0);
436 mPhoneEvdoIcon = service.addIcon(mPhoneEvdoData, null);
437 service.setIconVisibility(mPhoneEvdoIcon, false);
438
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800439 // register for phone state notifications.
440 ((TelephonyManager)mContext.getSystemService(Context.TELEPHONY_SERVICE))
441 .listen(mPhoneStateListener,
442 PhoneStateListener.LISTEN_SERVICE_STATE
Wink Savillee9b06d72009-05-18 21:47:50 -0700443 | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800444 | PhoneStateListener.LISTEN_CALL_STATE
445 | PhoneStateListener.LISTEN_DATA_CONNECTION_STATE
446 | PhoneStateListener.LISTEN_DATA_ACTIVITY);
447
448 // data_connection
449 mDataData = IconData.makeIcon("data_connection",
450 null, com.android.internal.R.drawable.stat_sys_data_connected_g, 0, 0);
451 mDataIcon = service.addIcon(mDataData, null);
452 service.setIconVisibility(mDataIcon, false);
453
454 // wifi
455 mWifiData = IconData.makeIcon("wifi", null, sWifiSignalImages[0], 0, 0);
456 mWifiIcon = service.addIcon(mWifiData, null);
457 service.setIconVisibility(mWifiIcon, false);
458 // wifi will get updated by the sticky intents
Wink Saville04e71b32009-04-02 11:00:54 -0700459
460 // TTY status
461 mTTYModeEnableIconData = IconData.makeIcon("tty",
462 null, com.android.internal.R.drawable.stat_sys_tty_mode, 0, 0);
463 mTTYModeIcon = service.addIcon(mTTYModeEnableIconData, null);
464 service.setIconVisibility(mTTYModeIcon, false);
465
Wink Savillee9b06d72009-05-18 21:47:50 -0700466 // Cdma Roaming Indicator, ERI
467 mCdmaRoamingIndicatorIconData = IconData.makeIcon("cdma_eri",
468 null, com.android.internal.R.drawable.stat_sys_roaming_cdma_0, 0, 0);
469 mCdmaRoamingIndicatorIcon = service.addIcon(mCdmaRoamingIndicatorIconData, null);
470 service.setIconVisibility(mCdmaRoamingIndicatorIcon, false);
471
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800472 // bluetooth status
473 mBluetoothData = IconData.makeIcon("bluetooth",
474 null, com.android.internal.R.drawable.stat_sys_data_bluetooth, 0, 0);
475 mBluetoothIcon = service.addIcon(mBluetoothData, null);
Nick Pellybd022f42009-08-14 18:33:38 -0700476 BluetoothAdapter adapter =
477 (BluetoothAdapter) mContext.getSystemService(Context.BLUETOOTH_SERVICE);
478 if (adapter != null) {
479 mBluetoothEnabled = adapter.isEnabled();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800480 } else {
481 mBluetoothEnabled = false;
482 }
483 mBluetoothA2dpState = BluetoothA2dp.STATE_DISCONNECTED;
484 mBluetoothHeadsetState = BluetoothHeadset.STATE_DISCONNECTED;
Jiafa Liu3f416732009-07-02 16:36:02 +0800485 mBluetoothPbapState = BluetoothPbap.STATE_DISCONNECTED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800486 mService.setIconVisibility(mBluetoothIcon, mBluetoothEnabled);
487
488 // Gps status
489 mGpsEnabledIconData = IconData.makeIcon("gps",
490 null, com.android.internal.R.drawable.stat_sys_gps_acquiring_anim, 0, 0);
491 mGpsFixIconData = IconData.makeIcon("gps",
492 null, com.android.internal.R.drawable.stat_sys_gps_on, 0, 0);
493 mGpsIcon = service.addIcon(mGpsEnabledIconData, null);
494 service.setIconVisibility(mGpsIcon, false);
495
496 // Alarm clock
497 mAlarmClockIconData = IconData.makeIcon(
498 "alarm_clock",
499 null, com.android.internal.R.drawable.stat_notify_alarm, 0, 0);
500 mAlarmClockIcon = service.addIcon(mAlarmClockIconData, null);
501 service.setIconVisibility(mAlarmClockIcon, false);
502
503 // Sync state
504 mSyncActiveIcon = service.addIcon(IconData.makeIcon("sync_active",
505 null, R.drawable.stat_notify_sync_anim0, 0, 0), null);
506 mSyncFailingIcon = service.addIcon(IconData.makeIcon("sync_failing",
507 null, R.drawable.stat_notify_sync_error, 0, 0), null);
508 service.setIconVisibility(mSyncActiveIcon, false);
509 service.setIconVisibility(mSyncFailingIcon, false);
510
511 // volume
512 mVolumeData = IconData.makeIcon("volume",
513 null, com.android.internal.R.drawable.stat_sys_ringer_silent, 0, 0);
514 mVolumeIcon = service.addIcon(mVolumeData, null);
515 service.setIconVisibility(mVolumeIcon, false);
516 updateVolume();
517
518 IntentFilter filter = new IntentFilter();
519
520 // Register for Intent broadcasts for...
521 filter.addAction(Intent.ACTION_TIME_TICK);
522 filter.addAction(Intent.ACTION_TIME_CHANGED);
523 filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
524 filter.addAction(Intent.ACTION_BATTERY_CHANGED);
Mihai Predaa82842f2009-04-29 15:05:56 +0200525 filter.addAction(Intent.ACTION_BATTERY_LOW);
Dianne Hackborn8ec5b832009-07-01 21:19:35 -0700526 filter.addAction(Intent.ACTION_BATTERY_OKAY);
Mike Lockwood69eb0bf2009-08-01 23:02:28 -0400527 filter.addAction(Intent.ACTION_POWER_CONNECTED);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800528 filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
529 filter.addAction(Intent.ACTION_ALARM_CHANGED);
530 filter.addAction(Intent.ACTION_SYNC_STATE_CHANGED);
531 filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
532 filter.addAction(AudioManager.VIBRATE_SETTING_CHANGED_ACTION);
The Android Open Source Project10592532009-03-18 17:39:46 -0700533 filter.addAction(BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800534 filter.addAction(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION);
535 filter.addAction(BluetoothA2dp.SINK_STATE_CHANGED_ACTION);
Jiafa Liu3f416732009-07-02 16:36:02 +0800536 filter.addAction(BluetoothPbap.PBAP_STATE_CHANGED_ACTION);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800537 filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
538 filter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
539 filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
540 filter.addAction(WifiManager.RSSI_CHANGED_ACTION);
541 filter.addAction(GpsLocationProvider.GPS_ENABLED_CHANGE_ACTION);
542 filter.addAction(GpsLocationProvider.GPS_FIX_CHANGE_ACTION);
543 filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
Wink Saville04e71b32009-04-02 11:00:54 -0700544 filter.addAction(TtyIntent.TTY_ENABLED_CHANGE_ACTION);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800545 mContext.registerReceiver(mIntentReceiver, filter, null, mHandler);
546 }
547
548 public static void installIcons(Context context, StatusBarService service) {
549 sInstance = new StatusBarPolicy(context, service);
550 }
551
552 private final void updateClock() {
553 mCalendar.setTimeInMillis(System.currentTimeMillis());
554 mClockData.text = DateFormat.getTimeFormat(mContext)
555 .format(mCalendar.getTime());
556 mService.updateIcon(mClockIcon, mClockData, null);
557 }
558
559 private final void updateAlarm(Intent intent) {
560 boolean alarmSet = intent.getBooleanExtra("alarmSet", false);
561 mService.setIconVisibility(mAlarmClockIcon, alarmSet);
562 }
563
564 private final void updateSyncState(Intent intent) {
565 boolean isActive = intent.getBooleanExtra("active", false);
566 boolean isFailing = intent.getBooleanExtra("failing", false);
567 mService.setIconVisibility(mSyncActiveIcon, isActive);
568 // Don't display sync failing icon: BUG 1297963 Set sync error timeout to "never"
569 //mService.setIconVisibility(mSyncFailingIcon, isFailing && !isActive);
570 }
571
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800572 private final void updateBattery(Intent intent) {
573 mBatteryData.iconId = intent.getIntExtra("icon-small", 0);
574 mBatteryData.iconLevel = intent.getIntExtra("level", 0);
575 mService.updateIcon(mBatteryIcon, mBatteryData, null);
576
577 boolean plugged = intent.getIntExtra("plugged", 0) != 0;
578 int level = intent.getIntExtra("level", -1);
579 if (false) {
580 Log.d(TAG, "updateBattery level=" + level
581 + " plugged=" + plugged
582 + " mBatteryPlugged=" + mBatteryPlugged
583 + " mBatteryLevel=" + mBatteryLevel
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800584 + " mBatteryFirst=" + mBatteryFirst);
585 }
586
587 boolean oldPlugged = mBatteryPlugged;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800588
589 mBatteryPlugged = plugged;
590 mBatteryLevel = level;
591
592 if (mBatteryFirst) {
593 mBatteryFirst = false;
594 }
595 /*
596 * No longer showing the battery view because it draws attention away
597 * from the USB storage notification. We could still show it when
598 * connected to a brick, but that could lead to the user into thinking
599 * the device does not charge when plugged into USB (since he/she would
600 * not see the same battery screen on USB as he sees on brick).
601 */
602 /* else {
603 if (plugged && !oldPlugged) {
604 showBatteryView();
605 }
606 }
607 */
608 if (false) {
Mihai Predaa82842f2009-04-29 15:05:56 +0200609 Log.d(TAG, "plugged=" + plugged + " oldPlugged=" + oldPlugged + " level=" + level);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800610 }
Mihai Predaa82842f2009-04-29 15:05:56 +0200611 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800612
Mihai Predaa82842f2009-04-29 15:05:56 +0200613 private void onBatteryLow(Intent intent) {
614 if (SHOW_LOW_BATTERY_WARNING) {
615 if (false) {
616 Log.d(TAG, "mPhoneState=" + mPhoneState
617 + " mLowBatteryDialog=" + mLowBatteryDialog
618 + " mBatteryShowLowOnEndCall=" + mBatteryShowLowOnEndCall);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800619 }
Mihai Predaa82842f2009-04-29 15:05:56 +0200620
621 if (mPhoneState == TelephonyManager.CALL_STATE_IDLE) {
622 showLowBatteryWarning();
623 } else {
624 mBatteryShowLowOnEndCall = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800625 }
626 }
627 }
628
Dianne Hackborn8ec5b832009-07-01 21:19:35 -0700629 private void onBatteryOkay(Intent intent) {
630 if (mLowBatteryDialog != null
631 && SHOW_LOW_BATTERY_WARNING) {
632 mLowBatteryDialog.dismiss();
633 mBatteryShowLowOnEndCall = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800634 }
635 }
636
637 private void showBatteryView() {
638 closeLastBatteryView();
639 if (mLowBatteryDialog != null) {
640 mLowBatteryDialog.dismiss();
641 }
642
643 int level = mBatteryLevel;
644
645 View v = View.inflate(mContext, com.android.internal.R.layout.battery_status, null);
646 mBatteryView = v;
647 int pixelFormat = PixelFormat.TRANSLUCENT;
648 Drawable bg = v.getBackground();
649 if (bg != null) {
650 pixelFormat = bg.getOpacity();
651 }
652
653 WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
654 ViewGroup.LayoutParams.WRAP_CONTENT,
655 ViewGroup.LayoutParams.WRAP_CONTENT,
656 WindowManager.LayoutParams.TYPE_TOAST,
657 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
658 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
659 | WindowManager.LayoutParams.FLAG_BLUR_BEHIND
660 | WindowManager.LayoutParams.FLAG_DIM_BEHIND,
661 pixelFormat);
662
663 // Get the dim amount from the theme
664 TypedArray a = mContext.obtainStyledAttributes(
665 com.android.internal.R.styleable.Theme);
666 lp.dimAmount = a.getFloat(android.R.styleable.Theme_backgroundDimAmount, 0.5f);
667 a.recycle();
Wink Saville04e71b32009-04-02 11:00:54 -0700668
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800669 lp.setTitle("Battery");
670
671 TextView levelTextView = (TextView)v.findViewById(com.android.internal.R.id.level_percent);
672 levelTextView.setText(mContext.getString(
673 com.android.internal.R.string.battery_status_text_percent_format, level));
674
675 setBatteryLevel(v, com.android.internal.R.id.spacer, 100-level, 0, 0);
676 setBatteryLevel(v, com.android.internal.R.id.level, level,
677 com.android.internal.R.drawable.battery_charge_fill, level);
678
679 WindowManagerImpl.getDefault().addView(v, lp);
680
681 scheduleCloseBatteryView();
682 }
683
684 private void setBatteryLevel(View parent, int id, int height, int background, int level) {
685 ImageView v = (ImageView)parent.findViewById(id);
686 LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)v.getLayoutParams();
687 lp.weight = height;
688 if (background != 0) {
689 v.setBackgroundResource(background);
690 Drawable bkg = v.getBackground();
691 bkg.setLevel(level);
692 }
693 }
694
695 private void showLowBatteryWarning() {
696 closeLastBatteryView();
697
Mihai Predaa82842f2009-04-29 15:05:56 +0200698 /* Show exact battery level.
699 * Add 1 because the text says "less than X%".
700 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800701 CharSequence levelText = mContext.getString(
Mihai Predaa82842f2009-04-29 15:05:56 +0200702 com.android.internal.R.string.battery_low_percent_format, mBatteryLevel + 1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800703
704 if (mBatteryLevelTextView != null) {
705 mBatteryLevelTextView.setText(levelText);
706 } else {
707 View v = View.inflate(mContext, com.android.internal.R.layout.battery_low, null);
708 mBatteryLevelTextView=(TextView)v.findViewById(com.android.internal.R.id.level_percent);
709
710 mBatteryLevelTextView.setText(levelText);
711
712 AlertDialog.Builder b = new AlertDialog.Builder(mContext);
713 b.setCancelable(true);
714 b.setTitle(com.android.internal.R.string.battery_low_title);
715 b.setView(v);
716 b.setIcon(android.R.drawable.ic_dialog_alert);
717 b.setPositiveButton(android.R.string.ok, null);
Dianne Hackborn3d74bb42009-06-19 10:35:21 -0700718
719 final Intent intent = new Intent(Intent.ACTION_POWER_USAGE_SUMMARY);
720 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
721 | Intent.FLAG_ACTIVITY_MULTIPLE_TASK
722 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
723 | Intent.FLAG_ACTIVITY_NO_HISTORY);
724 if (intent.resolveActivity(mContext.getPackageManager()) != null) {
725 b.setNegativeButton(com.android.internal.R.string.battery_low_why,
726 new DialogInterface.OnClickListener() {
727 public void onClick(DialogInterface dialog, int which) {
728 mContext.startActivity(intent);
729 if (mLowBatteryDialog != null) {
730 mLowBatteryDialog.dismiss();
731 }
732 }
733 });
734 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800735
736 AlertDialog d = b.create();
737 d.setOnDismissListener(mLowBatteryListener);
738 d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
739 d.show();
740 mLowBatteryDialog = d;
741 }
742 }
743
744 private final void updateCallState(int state) {
745 mPhoneState = state;
746 if (false) {
747 Log.d(TAG, "mPhoneState=" + mPhoneState
748 + " mLowBatteryDialog=" + mLowBatteryDialog
749 + " mBatteryShowLowOnEndCall=" + mBatteryShowLowOnEndCall);
750 }
751 if (mPhoneState == TelephonyManager.CALL_STATE_IDLE) {
752 if (mBatteryShowLowOnEndCall) {
753 if (!mBatteryPlugged) {
754 showLowBatteryWarning();
755 }
756 mBatteryShowLowOnEndCall = false;
757 }
758 } else {
759 if (mLowBatteryDialog != null) {
760 mLowBatteryDialog.dismiss();
761 mBatteryShowLowOnEndCall = true;
762 }
763 }
764 }
765
766 private DialogInterface.OnDismissListener mLowBatteryListener
767 = new DialogInterface.OnDismissListener() {
768 public void onDismiss(DialogInterface dialog) {
769 mLowBatteryDialog = null;
770 mBatteryLevelTextView = null;
771 }
772 };
773
774 private void scheduleCloseBatteryView() {
775 Message m = mHandler.obtainMessage(EVENT_BATTERY_CLOSE);
776 m.arg1 = (++mBatteryViewSequence);
777 mHandler.sendMessageDelayed(m, 3000);
778 }
779
780 private void closeLastBatteryView() {
781 if (mBatteryView != null) {
782 //mBatteryView.debug();
783 WindowManagerImpl.getDefault().removeView(mBatteryView);
784 mBatteryView = null;
785 }
786 }
787
788 private PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
789 @Override
Wink Savillee9b06d72009-05-18 21:47:50 -0700790 public void onSignalStrengthsChanged(SignalStrength signalStrength) {
791 mSignalStrength = signalStrength;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800792 updateSignalStrength();
793 }
794
795 @Override
796 public void onServiceStateChanged(ServiceState state) {
797 mServiceState = state;
798 updateSignalStrength();
Wink Savillee9b06d72009-05-18 21:47:50 -0700799 updateCdmaRoamingIcon();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800800 updateDataIcon();
801 }
802
803 @Override
804 public void onCallStateChanged(int state, String incomingNumber) {
805 updateCallState(state);
806 }
807
808 @Override
809 public void onDataConnectionStateChanged(int state) {
810 mDataState = state;
811 updateDataNetType();
812 updateDataIcon();
813 }
814
815 @Override
816 public void onDataActivity(int direction) {
817 mDataActivity = direction;
818 updateDataIcon();
819 }
820 };
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800821
822 private final void updateSimState(Intent intent) {
Wink Saville04e71b32009-04-02 11:00:54 -0700823 String stateExtra = intent.getStringExtra(IccCard.INTENT_KEY_ICC_STATE);
824 if (IccCard.INTENT_VALUE_ICC_ABSENT.equals(stateExtra)) {
825 mSimState = IccCard.State.ABSENT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800826 }
Wink Saville04e71b32009-04-02 11:00:54 -0700827 else if (IccCard.INTENT_VALUE_ICC_READY.equals(stateExtra)) {
828 mSimState = IccCard.State.READY;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800829 }
Wink Saville04e71b32009-04-02 11:00:54 -0700830 else if (IccCard.INTENT_VALUE_ICC_LOCKED.equals(stateExtra)) {
831 final String lockedReason = intent.getStringExtra(IccCard.INTENT_KEY_LOCKED_REASON);
832 if (IccCard.INTENT_VALUE_LOCKED_ON_PIN.equals(lockedReason)) {
833 mSimState = IccCard.State.PIN_REQUIRED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800834 }
Wink Saville04e71b32009-04-02 11:00:54 -0700835 else if (IccCard.INTENT_VALUE_LOCKED_ON_PUK.equals(lockedReason)) {
836 mSimState = IccCard.State.PUK_REQUIRED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800837 }
838 else {
Wink Saville04e71b32009-04-02 11:00:54 -0700839 mSimState = IccCard.State.NETWORK_LOCKED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800840 }
841 } else {
Wink Saville04e71b32009-04-02 11:00:54 -0700842 mSimState = IccCard.State.UNKNOWN;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800843 }
844 updateDataIcon();
845 }
846
Wink Savillee9b06d72009-05-18 21:47:50 -0700847 private boolean isCdma() {
Wink Savillef3152382009-06-01 14:39:20 -0700848 return ((mPhone != null) && (mPhone.getPhoneType() == TelephonyManager.PHONE_TYPE_CDMA));
Wink Savillee9b06d72009-05-18 21:47:50 -0700849 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800850
Wink Savillee9b06d72009-05-18 21:47:50 -0700851 private boolean hasService() {
852 if (mServiceState != null) {
853 switch (mServiceState.getState()) {
854 case ServiceState.STATE_OUT_OF_SERVICE:
855 case ServiceState.STATE_POWER_OFF:
856 return false;
857 default:
858 return true;
859 }
860 } else {
861 return false;
862 }
863 }
864
865 private final void updateSignalStrength() {
866 int iconLevel = -1;
867 int evdoIconLevel = -1;
868 int[] iconList;
869 int[] evdoIconList;
870
871 if (!hasService()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800872 //Log.d(TAG, "updateSignalStrength: no service");
873 if (Settings.System.getInt(mContext.getContentResolver(),
874 Settings.System.AIRPLANE_MODE_ON, 0) == 1) {
875 mPhoneData.iconId = com.android.internal.R.drawable.stat_sys_signal_flightmode;
876 } else {
877 mPhoneData.iconId = com.android.internal.R.drawable.stat_sys_signal_null;
878 }
879 mService.updateIcon(mPhoneIcon, mPhoneData, null);
Wink Savillee9b06d72009-05-18 21:47:50 -0700880 mService.setIconVisibility(mPhoneEvdoIcon,false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800881 return;
882 }
883
Wink Savillee9b06d72009-05-18 21:47:50 -0700884 if (!isCdma()) {
885 int asu = mSignalStrength.getGsmSignalStrength();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800886
Wink Savillee9b06d72009-05-18 21:47:50 -0700887 // ASU ranges from 0 to 31 - TS 27.007 Sec 8.5
888 // asu = 0 (-113dB or less) is very weak
889 // signal, its better to show 0 bars to the user in such cases.
890 // asu = 99 is a special case, where the signal strength is unknown.
891 if (asu <= 0 || asu == 99) iconLevel = 0;
892 else if (asu >= 16) iconLevel = 4;
893 else if (asu >= 8) iconLevel = 3;
894 else if (asu >= 4) iconLevel = 2;
895 else iconLevel = 1;
896
897 if (mPhone.isNetworkRoaming()) {
898 iconList = sSignalImages_r;
899 } else {
900 iconList = sSignalImages;
Wink Saville04e71b32009-04-02 11:00:54 -0700901 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800902 } else {
Wink Savillee9b06d72009-05-18 21:47:50 -0700903 iconList = this.sSignalImages_cdma;
904
905 int cdmaDbm = mSignalStrength.getCdmaDbm();
906 int cdmaEcio = mSignalStrength.getCdmaEcio();
907 int levelDbm = 0;
908 int levelEcio = 0;
909
910 if (cdmaDbm >= -75) levelDbm = 4;
911 else if (cdmaDbm >= -85) levelDbm = 3;
912 else if (cdmaDbm >= -95) levelDbm = 2;
913 else if (cdmaDbm >= -100) levelDbm = 1;
914 else levelDbm = 0;
915
916 // Ec/Io are in dB*10
917 if (cdmaEcio >= -90) levelEcio = 4;
918 else if (cdmaEcio >= -110) levelEcio = 3;
919 else if (cdmaEcio >= -130) levelEcio = 2;
920 else if (cdmaEcio >= -150) levelEcio = 1;
921 else levelEcio = 0;
922
923 iconLevel = (levelDbm < levelEcio) ? levelDbm : levelEcio;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800924 }
Wink Saville04e71b32009-04-02 11:00:54 -0700925
Wink Savillee9b06d72009-05-18 21:47:50 -0700926 if ((mServiceState.getRadioTechnology() == ServiceState.RADIO_TECHNOLOGY_EVDO_0)
927 || (mServiceState.getRadioTechnology() == ServiceState.RADIO_TECHNOLOGY_EVDO_A)) {
928 // Use Evdo icon
929 evdoIconList = this.sSignalImages_evdo;
930
Yong Zhang96f27472009-07-22 17:25:30 -0500931 int evdoDbm = mSignalStrength.getEvdoDbm();
Wink Savillee9b06d72009-05-18 21:47:50 -0700932 int evdoSnr = mSignalStrength.getEvdoSnr();
Yong Zhang96f27472009-07-22 17:25:30 -0500933 int levelEvdoDbm = 0;
Wink Savillee9b06d72009-05-18 21:47:50 -0700934 int levelEvdoSnr = 0;
935
Yong Zhang96f27472009-07-22 17:25:30 -0500936 if (evdoDbm >= -65) levelEvdoDbm = 4;
937 else if (evdoDbm >= -75) levelEvdoDbm = 3;
938 else if (evdoDbm >= -90) levelEvdoDbm = 2;
939 else if (evdoDbm >= -105) levelEvdoDbm = 1;
940 else levelEvdoDbm = 0;
Wink Savillee9b06d72009-05-18 21:47:50 -0700941
942 if (evdoSnr > 7) levelEvdoSnr = 4;
943 else if (evdoSnr > 5) levelEvdoSnr = 3;
944 else if (evdoSnr > 3) levelEvdoSnr = 2;
945 else if (evdoSnr > 1) levelEvdoSnr = 1;
946 else levelEvdoSnr = 0;
947
Yong Zhang96f27472009-07-22 17:25:30 -0500948 evdoIconLevel = (levelEvdoDbm < levelEvdoSnr) ? levelEvdoDbm : levelEvdoSnr;
Wink Savillee9b06d72009-05-18 21:47:50 -0700949
950 mPhoneEvdoData.iconId = evdoIconList[evdoIconLevel];
951 mService.updateIcon(mPhoneEvdoIcon, mPhoneEvdoData, null);
952 mService.setIconVisibility(mPhoneEvdoIcon,true);
953 } else {
954 mService.setIconVisibility(mPhoneEvdoIcon,false);
955 }
956
957 mPhoneData.iconId = iconList[iconLevel];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800958 mService.updateIcon(mPhoneIcon, mPhoneData, null);
959 }
960
961 private final void updateDataNetType() {
Wink Saville04e71b32009-04-02 11:00:54 -0700962 int net = mPhone.getNetworkType();
Wink Saville04e71b32009-04-02 11:00:54 -0700963
964 switch (net) {
Wink Saville04e71b32009-04-02 11:00:54 -0700965 case TelephonyManager.NETWORK_TYPE_EDGE:
966 mDataIconList = sDataNetType_e;
967 break;
968 case TelephonyManager.NETWORK_TYPE_UMTS:
969 mDataIconList = sDataNetType_3g;
970 break;
971 case TelephonyManager.NETWORK_TYPE_CDMA:
972 // display 1xRTT for IS95A/B
973 mDataIconList = this.sDataNetType_1xrtt;
974 break;
975 case TelephonyManager.NETWORK_TYPE_1xRTT:
976 mDataIconList = this.sDataNetType_1xrtt;
977 break;
978 case TelephonyManager.NETWORK_TYPE_EVDO_0: //fall through
979 case TelephonyManager.NETWORK_TYPE_EVDO_A:
980 mDataIconList = sDataNetType_evdo;
981 break;
982 default:
983 mDataIconList = sDataNetType_g;
984 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800985 }
986 }
987
988 private final void updateDataIcon() {
989 int iconId;
990 boolean visible = true;
991
Wink Savillee9b06d72009-05-18 21:47:50 -0700992 if (!isCdma()) {
993 // GSM case, we have to check also the sim state
994 if (mSimState == IccCard.State.READY || mSimState == IccCard.State.UNKNOWN) {
995 if (hasService() && mDataState == TelephonyManager.DATA_CONNECTED) {
996 switch (mDataActivity) {
997 case TelephonyManager.DATA_ACTIVITY_IN:
998 iconId = mDataIconList[1];
999 break;
1000 case TelephonyManager.DATA_ACTIVITY_OUT:
1001 iconId = mDataIconList[2];
1002 break;
1003 case TelephonyManager.DATA_ACTIVITY_INOUT:
1004 iconId = mDataIconList[3];
1005 break;
1006 default:
1007 iconId = mDataIconList[0];
1008 break;
1009 }
1010 mDataData.iconId = iconId;
1011 mService.updateIcon(mDataIcon, mDataData, null);
1012 } else {
1013 visible = false;
1014 }
1015 } else {
1016 mDataData.iconId = com.android.internal.R.drawable.stat_sys_no_sim;
1017 mService.updateIcon(mDataIcon, mDataData, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001018 }
Wink Savillee9b06d72009-05-18 21:47:50 -07001019 } else {
1020 // CDMA case, mDataActivity can be also DATA_ACTIVITY_DORMANT
1021 if (hasService() && mDataState == TelephonyManager.DATA_CONNECTED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001022 switch (mDataActivity) {
1023 case TelephonyManager.DATA_ACTIVITY_IN:
Wink Savillee9b06d72009-05-18 21:47:50 -07001024 iconId = mDataIconList[1];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001025 break;
1026 case TelephonyManager.DATA_ACTIVITY_OUT:
Wink Savillee9b06d72009-05-18 21:47:50 -07001027 iconId = mDataIconList[2];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001028 break;
1029 case TelephonyManager.DATA_ACTIVITY_INOUT:
Wink Savillee9b06d72009-05-18 21:47:50 -07001030 iconId = mDataIconList[3];
1031 break;
1032 case TelephonyManager.DATA_ACTIVITY_DORMANT:
1033 iconId = mDataIconList[4];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001034 break;
1035 default:
Wink Savillee9b06d72009-05-18 21:47:50 -07001036 iconId = mDataIconList[0];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001037 break;
1038 }
1039 mDataData.iconId = iconId;
1040 mService.updateIcon(mDataIcon, mDataData, null);
1041 } else {
1042 visible = false;
1043 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001044 }
Wink Savillee9b06d72009-05-18 21:47:50 -07001045
Dianne Hackborn4840e142009-03-24 22:40:29 -07001046 long ident = Binder.clearCallingIdentity();
1047 try {
Wink Saville04e71b32009-04-02 11:00:54 -07001048 mBatteryStats.notePhoneDataConnectionState(mPhone.getNetworkType(), visible);
Dianne Hackborn4840e142009-03-24 22:40:29 -07001049 } catch (RemoteException e) {
1050 } finally {
1051 Binder.restoreCallingIdentity(ident);
1052 }
Wink Savillee9b06d72009-05-18 21:47:50 -07001053
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001054 if (mDataIconVisible != visible) {
1055 mService.setIconVisibility(mDataIcon, visible);
1056 mDataIconVisible = visible;
1057 }
1058 }
1059
1060 private final void updateVolume() {
1061 AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
1062 final int ringerMode = audioManager.getRingerMode();
1063 final boolean visible = ringerMode == AudioManager.RINGER_MODE_SILENT ||
Wink Savillee9b06d72009-05-18 21:47:50 -07001064 ringerMode == AudioManager.RINGER_MODE_VIBRATE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001065 final int iconId = audioManager.shouldVibrate(AudioManager.VIBRATE_TYPE_RINGER)
1066 ? com.android.internal.R.drawable.stat_sys_ringer_vibrate
1067 : com.android.internal.R.drawable.stat_sys_ringer_silent;
1068
1069 if (visible) {
1070 mVolumeData.iconId = iconId;
1071 mService.updateIcon(mVolumeIcon, mVolumeData, null);
1072 }
1073 if (visible != mVolumeVisible) {
1074 mService.setIconVisibility(mVolumeIcon, visible);
1075 mVolumeVisible = visible;
1076 }
1077 }
1078
1079 private final void updateBluetooth(Intent intent) {
1080 int iconId = com.android.internal.R.drawable.stat_sys_data_bluetooth;
1081
1082 String action = intent.getAction();
The Android Open Source Project10592532009-03-18 17:39:46 -07001083 if (action.equals(BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION)) {
1084 int state = intent.getIntExtra(BluetoothIntent.BLUETOOTH_STATE,
1085 BluetoothError.ERROR);
Nick Pellybd022f42009-08-14 18:33:38 -07001086 mBluetoothEnabled = state == BluetoothAdapter.BLUETOOTH_STATE_ON;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001087 } else if (action.equals(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION)) {
1088 mBluetoothHeadsetState = intent.getIntExtra(BluetoothIntent.HEADSET_STATE,
1089 BluetoothHeadset.STATE_ERROR);
1090 } else if (action.equals(BluetoothA2dp.SINK_STATE_CHANGED_ACTION)) {
1091 mBluetoothA2dpState = intent.getIntExtra(BluetoothA2dp.SINK_STATE,
1092 BluetoothA2dp.STATE_DISCONNECTED);
Jiafa Liu3f416732009-07-02 16:36:02 +08001093 } else if (action.equals(BluetoothPbap.PBAP_STATE_CHANGED_ACTION)) {
1094 mBluetoothPbapState = intent.getIntExtra(BluetoothPbap.PBAP_STATE,
1095 BluetoothPbap.STATE_DISCONNECTED);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001096 } else {
1097 return;
1098 }
Wink Savillee9b06d72009-05-18 21:47:50 -07001099
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001100 if (mBluetoothHeadsetState == BluetoothHeadset.STATE_CONNECTED ||
1101 mBluetoothA2dpState == BluetoothA2dp.STATE_CONNECTED ||
Jiafa Liu3f416732009-07-02 16:36:02 +08001102 mBluetoothA2dpState == BluetoothA2dp.STATE_PLAYING ||
1103 mBluetoothPbapState == BluetoothPbap.STATE_CONNECTED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001104 iconId = com.android.internal.R.drawable.stat_sys_data_bluetooth_connected;
1105 }
1106
1107 mBluetoothData.iconId = iconId;
1108 mService.updateIcon(mBluetoothIcon, mBluetoothData, null);
1109 mService.setIconVisibility(mBluetoothIcon, mBluetoothEnabled);
1110 }
1111
1112 private final void updateWifi(Intent intent) {
1113 final String action = intent.getAction();
1114 if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
Wink Savillee9b06d72009-05-18 21:47:50 -07001115
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001116 final boolean enabled = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
1117 WifiManager.WIFI_STATE_UNKNOWN) == WifiManager.WIFI_STATE_ENABLED;
Wink Savillee9b06d72009-05-18 21:47:50 -07001118
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001119 if (!enabled) {
1120 // If disabled, hide the icon. (We show icon when connected.)
1121 mService.setIconVisibility(mWifiIcon, false);
1122 }
Wink Savillee9b06d72009-05-18 21:47:50 -07001123
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001124 } else if (action.equals(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION)) {
1125 final boolean enabled = intent.getBooleanExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED,
1126 false);
1127 if (!enabled) {
1128 mService.setIconVisibility(mWifiIcon, false);
1129 }
1130 } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
1131
Wink Savillee9b06d72009-05-18 21:47:50 -07001132 final NetworkInfo networkInfo = (NetworkInfo)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001133 intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
Wink Savillee9b06d72009-05-18 21:47:50 -07001134
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001135 int iconId;
1136 if (networkInfo != null && networkInfo.isConnected()) {
1137 mIsWifiConnected = true;
1138 if (mLastWifiSignalLevel == -1) {
1139 iconId = sWifiSignalImages[0];
1140 } else {
1141 iconId = sWifiSignalImages[mLastWifiSignalLevel];
1142 }
Wink Saville04e71b32009-04-02 11:00:54 -07001143
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001144 // Show the icon since wi-fi is connected
1145 mService.setIconVisibility(mWifiIcon, true);
Wink Saville04e71b32009-04-02 11:00:54 -07001146
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001147 } else {
1148 mLastWifiSignalLevel = -1;
1149 mIsWifiConnected = false;
1150 iconId = sWifiSignalImages[0];
1151
1152 // Hide the icon since we're not connected
1153 mService.setIconVisibility(mWifiIcon, false);
1154 }
1155
1156 mWifiData.iconId = iconId;
1157 mService.updateIcon(mWifiIcon, mWifiData, null);
1158 } else if (action.equals(WifiManager.RSSI_CHANGED_ACTION)) {
1159 final int newRssi = intent.getIntExtra(WifiManager.EXTRA_NEW_RSSI, -200);
1160 int newSignalLevel = WifiManager.calculateSignalLevel(newRssi,
1161 sWifiSignalImages.length);
1162 if (newSignalLevel != mLastWifiSignalLevel) {
1163 mLastWifiSignalLevel = newSignalLevel;
1164 if (mIsWifiConnected) {
1165 mWifiData.iconId = sWifiSignalImages[newSignalLevel];
1166 } else {
1167 mWifiData.iconId = sWifiTemporarilyNotConnectedImage;
1168 }
1169 mService.updateIcon(mWifiIcon, mWifiData, null);
1170 }
1171 }
1172 }
1173
1174 private final void updateGps(Intent intent) {
1175 final String action = intent.getAction();
1176 final boolean enabled = intent.getBooleanExtra(GpsLocationProvider.EXTRA_ENABLED, false);
1177
1178 if (action.equals(GpsLocationProvider.GPS_FIX_CHANGE_ACTION) && enabled) {
1179 // GPS is getting fixes
1180 mService.updateIcon(mGpsIcon, mGpsFixIconData, null);
Wink Savillee9b06d72009-05-18 21:47:50 -07001181 mService.setIconVisibility(mGpsIcon, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001182 } else if (action.equals(GpsLocationProvider.GPS_ENABLED_CHANGE_ACTION) && !enabled) {
1183 // GPS is off
Wink Savillee9b06d72009-05-18 21:47:50 -07001184 mService.setIconVisibility(mGpsIcon, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001185 } else {
1186 // GPS is on, but not receiving fixes
1187 mService.updateIcon(mGpsIcon, mGpsEnabledIconData, null);
Wink Savillee9b06d72009-05-18 21:47:50 -07001188 mService.setIconVisibility(mGpsIcon, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001189 }
1190 }
1191
Wink Savillee9b06d72009-05-18 21:47:50 -07001192 private final void updateTTY(Intent intent) {
Wink Saville04e71b32009-04-02 11:00:54 -07001193 final String action = intent.getAction();
1194 final boolean enabled = intent.getBooleanExtra(TtyIntent.TTY_ENABLED, false);
1195
1196 Log.i(TAG, "updateTTY: enabled: " + enabled);
1197
1198 if (enabled) {
1199 // TTY is on
1200 Log.i(TAG, "updateTTY: set TTY on");
1201 mService.updateIcon(mTTYModeIcon, mTTYModeEnableIconData, null);
Wink Savillee9b06d72009-05-18 21:47:50 -07001202 mService.setIconVisibility(mTTYModeIcon, true);
Wink Saville04e71b32009-04-02 11:00:54 -07001203 } else {
1204 // TTY is off
1205 Log.i(TAG, "updateTTY: set TTY off");
Wink Savillee9b06d72009-05-18 21:47:50 -07001206 mService.setIconVisibility(mTTYModeIcon, false);
Wink Saville04e71b32009-04-02 11:00:54 -07001207 }
1208 }
1209
Wink Savillee9b06d72009-05-18 21:47:50 -07001210 private final void updateCdmaRoamingIcon() {
1211 if (!hasService()) {
1212 mService.setIconVisibility(mCdmaRoamingIndicatorIcon, false);
Wink Savillef3152382009-06-01 14:39:20 -07001213 return;
Wink Savillee9b06d72009-05-18 21:47:50 -07001214 }
1215
1216 if (!isCdma()) {
1217 mService.setIconVisibility(mCdmaRoamingIndicatorIcon, false);
Wink Savillef3152382009-06-01 14:39:20 -07001218 return;
Wink Savillee9b06d72009-05-18 21:47:50 -07001219 }
1220
1221 int[] iconList = sRoamingIndicatorImages_cdma;
1222 int iconIndex = mPhone.getCdmaEriIconIndex();
1223 int iconMode = mPhone.getCdmaEriIconMode();
1224
1225 if (iconIndex == -1) {
1226 Log.e(TAG, "getCdmaEriIconIndex returned null, skipping ERI icon update");
1227 return;
1228 }
1229
1230 if (iconMode == -1) {
1231 Log.e(TAG, "getCdmeEriIconMode returned null, skipping ERI icon update");
1232 return;
1233 }
1234
1235 if (iconIndex == EriInfo.ROAMING_INDICATOR_OFF) {
1236 Log.d(TAG, "Cdma ROAMING_INDICATOR_OFF, removing ERI icon");
1237 mService.setIconVisibility(mCdmaRoamingIndicatorIcon, false);
1238 return;
1239 }
1240
1241 switch (iconMode) {
1242 case EriInfo.ROAMING_ICON_MODE_NORMAL:
1243 mCdmaRoamingIndicatorIconData.iconId = iconList[iconIndex];
1244 mService.updateIcon(mCdmaRoamingIndicatorIcon, mCdmaRoamingIndicatorIconData, null);
1245 mService.setIconVisibility(mCdmaRoamingIndicatorIcon, true);
1246 break;
1247 case EriInfo.ROAMING_ICON_MODE_FLASH:
Wink Savillef3152382009-06-01 14:39:20 -07001248 mCdmaRoamingIndicatorIconData.iconId =
1249 com.android.internal.R.drawable.stat_sys_roaming_cdma_flash;
Wink Savillee9b06d72009-05-18 21:47:50 -07001250 mService.updateIcon(mCdmaRoamingIndicatorIcon, mCdmaRoamingIndicatorIconData, null);
Wink Savillef3152382009-06-01 14:39:20 -07001251 mService.setIconVisibility(mCdmaRoamingIndicatorIcon, true);
Wink Savillee9b06d72009-05-18 21:47:50 -07001252 break;
1253
1254 }
1255 mService.updateIcon(mPhoneIcon, mPhoneData, null);
1256 }
1257
1258
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001259 private class StatusBarHandler extends Handler {
1260 @Override
1261 public void handleMessage(Message msg) {
1262 switch (msg.what) {
1263 case EVENT_BATTERY_CLOSE:
1264 if (msg.arg1 == mBatteryViewSequence) {
1265 closeLastBatteryView();
1266 }
1267 break;
1268 }
1269 }
1270 }
1271}