blob: 33e793b1c746d717be646ee153837b2948fe7f82 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.status;
18
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080019import android.app.AlertDialog;
20import android.bluetooth.BluetoothA2dp;
21import android.bluetooth.BluetoothDevice;
The Android Open Source Project10592532009-03-18 17:39:46 -070022import android.bluetooth.BluetoothError;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080023import android.bluetooth.BluetoothHeadset;
24import android.bluetooth.BluetoothIntent;
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 }
Dianne Hackborn8ec5b832009-07-01 21:19:35 -0700378 else if (action.equals(Intent.ACTION_BATTERY_OKAY)) {
379 onBatteryOkay(intent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800380 }
The Android Open Source Project10592532009-03-18 17:39:46 -0700381 else if (action.equals(BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION) ||
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800382 action.equals(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION) ||
Jiafa Liu3f416732009-07-02 16:36:02 +0800383 action.equals(BluetoothA2dp.SINK_STATE_CHANGED_ACTION) ||
384 action.equals(BluetoothPbap.PBAP_STATE_CHANGED_ACTION)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800385 updateBluetooth(intent);
386 }
387 else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION) ||
388 action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION) ||
389 action.equals(WifiManager.RSSI_CHANGED_ACTION)) {
390 updateWifi(intent);
391 }
392 else if (action.equals(GpsLocationProvider.GPS_ENABLED_CHANGE_ACTION) ||
393 action.equals(GpsLocationProvider.GPS_FIX_CHANGE_ACTION)) {
394 updateGps(intent);
395 }
396 else if (action.equals(AudioManager.RINGER_MODE_CHANGED_ACTION) ||
397 action.equals(AudioManager.VIBRATE_SETTING_CHANGED_ACTION)) {
398 updateVolume();
399 }
400 else if (action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) {
401 updateSimState(intent);
402 }
Wink Saville04e71b32009-04-02 11:00:54 -0700403 else if (action.equals(TtyIntent.TTY_ENABLED_CHANGE_ACTION)) {
404 updateTTY(intent);
405 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800406 }
407 };
408
409 private StatusBarPolicy(Context context, StatusBarService service) {
410 mContext = context;
411 mService = service;
Wink Savillee9b06d72009-05-18 21:47:50 -0700412 mSignalStrength = new SignalStrength();
Dianne Hackborn4840e142009-03-24 22:40:29 -0700413 mBatteryStats = BatteryStatsService.getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800414
415 // clock
416 mCalendar = Calendar.getInstance(TimeZone.getDefault());
417 mClockData = IconData.makeText("clock", "");
418 mClockIcon = service.addIcon(mClockData, null);
419 updateClock();
420
421 // battery
422 mBatteryData = IconData.makeIcon("battery",
423 null, com.android.internal.R.drawable.stat_sys_battery_unknown, 0, 0);
424 mBatteryIcon = service.addIcon(mBatteryData, null);
425
426 // phone_signal
427 mPhone = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
Wink Savillee9b06d72009-05-18 21:47:50 -0700428 mPhoneData = IconData.makeIcon("phone_signal",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800429 null, com.android.internal.R.drawable.stat_sys_signal_null, 0, 0);
430 mPhoneIcon = service.addIcon(mPhoneData, null);
Wink Savillee9b06d72009-05-18 21:47:50 -0700431
432 // phone_evdo_signal
433 mPhoneEvdoData = IconData.makeIcon("phone_evdo_signal",
434 null, com.android.internal.R.drawable.stat_sys_signal_evdo_0, 0, 0);
435 mPhoneEvdoIcon = service.addIcon(mPhoneEvdoData, null);
436 service.setIconVisibility(mPhoneEvdoIcon, false);
437
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800438 // register for phone state notifications.
439 ((TelephonyManager)mContext.getSystemService(Context.TELEPHONY_SERVICE))
440 .listen(mPhoneStateListener,
441 PhoneStateListener.LISTEN_SERVICE_STATE
Wink Savillee9b06d72009-05-18 21:47:50 -0700442 | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800443 | PhoneStateListener.LISTEN_CALL_STATE
444 | PhoneStateListener.LISTEN_DATA_CONNECTION_STATE
445 | PhoneStateListener.LISTEN_DATA_ACTIVITY);
446
447 // data_connection
448 mDataData = IconData.makeIcon("data_connection",
449 null, com.android.internal.R.drawable.stat_sys_data_connected_g, 0, 0);
450 mDataIcon = service.addIcon(mDataData, null);
451 service.setIconVisibility(mDataIcon, false);
452
453 // wifi
454 mWifiData = IconData.makeIcon("wifi", null, sWifiSignalImages[0], 0, 0);
455 mWifiIcon = service.addIcon(mWifiData, null);
456 service.setIconVisibility(mWifiIcon, false);
457 // wifi will get updated by the sticky intents
Wink Saville04e71b32009-04-02 11:00:54 -0700458
459 // TTY status
460 mTTYModeEnableIconData = IconData.makeIcon("tty",
461 null, com.android.internal.R.drawable.stat_sys_tty_mode, 0, 0);
462 mTTYModeIcon = service.addIcon(mTTYModeEnableIconData, null);
463 service.setIconVisibility(mTTYModeIcon, false);
464
Wink Savillee9b06d72009-05-18 21:47:50 -0700465 // Cdma Roaming Indicator, ERI
466 mCdmaRoamingIndicatorIconData = IconData.makeIcon("cdma_eri",
467 null, com.android.internal.R.drawable.stat_sys_roaming_cdma_0, 0, 0);
468 mCdmaRoamingIndicatorIcon = service.addIcon(mCdmaRoamingIndicatorIconData, null);
469 service.setIconVisibility(mCdmaRoamingIndicatorIcon, false);
470
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800471 // bluetooth status
472 mBluetoothData = IconData.makeIcon("bluetooth",
473 null, com.android.internal.R.drawable.stat_sys_data_bluetooth, 0, 0);
474 mBluetoothIcon = service.addIcon(mBluetoothData, null);
475 BluetoothDevice bluetooth =
476 (BluetoothDevice) mContext.getSystemService(Context.BLUETOOTH_SERVICE);
477 if (bluetooth != null) {
478 mBluetoothEnabled = bluetooth.isEnabled();
479 } else {
480 mBluetoothEnabled = false;
481 }
482 mBluetoothA2dpState = BluetoothA2dp.STATE_DISCONNECTED;
483 mBluetoothHeadsetState = BluetoothHeadset.STATE_DISCONNECTED;
Jiafa Liu3f416732009-07-02 16:36:02 +0800484 mBluetoothPbapState = BluetoothPbap.STATE_DISCONNECTED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800485 mService.setIconVisibility(mBluetoothIcon, mBluetoothEnabled);
486
487 // Gps status
488 mGpsEnabledIconData = IconData.makeIcon("gps",
489 null, com.android.internal.R.drawable.stat_sys_gps_acquiring_anim, 0, 0);
490 mGpsFixIconData = IconData.makeIcon("gps",
491 null, com.android.internal.R.drawable.stat_sys_gps_on, 0, 0);
492 mGpsIcon = service.addIcon(mGpsEnabledIconData, null);
493 service.setIconVisibility(mGpsIcon, false);
494
495 // Alarm clock
496 mAlarmClockIconData = IconData.makeIcon(
497 "alarm_clock",
498 null, com.android.internal.R.drawable.stat_notify_alarm, 0, 0);
499 mAlarmClockIcon = service.addIcon(mAlarmClockIconData, null);
500 service.setIconVisibility(mAlarmClockIcon, false);
501
502 // Sync state
503 mSyncActiveIcon = service.addIcon(IconData.makeIcon("sync_active",
504 null, R.drawable.stat_notify_sync_anim0, 0, 0), null);
505 mSyncFailingIcon = service.addIcon(IconData.makeIcon("sync_failing",
506 null, R.drawable.stat_notify_sync_error, 0, 0), null);
507 service.setIconVisibility(mSyncActiveIcon, false);
508 service.setIconVisibility(mSyncFailingIcon, false);
509
510 // volume
511 mVolumeData = IconData.makeIcon("volume",
512 null, com.android.internal.R.drawable.stat_sys_ringer_silent, 0, 0);
513 mVolumeIcon = service.addIcon(mVolumeData, null);
514 service.setIconVisibility(mVolumeIcon, false);
515 updateVolume();
516
517 IntentFilter filter = new IntentFilter();
518
519 // Register for Intent broadcasts for...
520 filter.addAction(Intent.ACTION_TIME_TICK);
521 filter.addAction(Intent.ACTION_TIME_CHANGED);
522 filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
523 filter.addAction(Intent.ACTION_BATTERY_CHANGED);
Mihai Predaa82842f2009-04-29 15:05:56 +0200524 filter.addAction(Intent.ACTION_BATTERY_LOW);
Dianne Hackborn8ec5b832009-07-01 21:19:35 -0700525 filter.addAction(Intent.ACTION_BATTERY_OKAY);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800526 filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
527 filter.addAction(Intent.ACTION_ALARM_CHANGED);
528 filter.addAction(Intent.ACTION_SYNC_STATE_CHANGED);
529 filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
530 filter.addAction(AudioManager.VIBRATE_SETTING_CHANGED_ACTION);
The Android Open Source Project10592532009-03-18 17:39:46 -0700531 filter.addAction(BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800532 filter.addAction(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION);
533 filter.addAction(BluetoothA2dp.SINK_STATE_CHANGED_ACTION);
Jiafa Liu3f416732009-07-02 16:36:02 +0800534 filter.addAction(BluetoothPbap.PBAP_STATE_CHANGED_ACTION);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800535 filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
536 filter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
537 filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
538 filter.addAction(WifiManager.RSSI_CHANGED_ACTION);
539 filter.addAction(GpsLocationProvider.GPS_ENABLED_CHANGE_ACTION);
540 filter.addAction(GpsLocationProvider.GPS_FIX_CHANGE_ACTION);
541 filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
Wink Saville04e71b32009-04-02 11:00:54 -0700542 filter.addAction(TtyIntent.TTY_ENABLED_CHANGE_ACTION);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800543 mContext.registerReceiver(mIntentReceiver, filter, null, mHandler);
544 }
545
546 public static void installIcons(Context context, StatusBarService service) {
547 sInstance = new StatusBarPolicy(context, service);
548 }
549
550 private final void updateClock() {
551 mCalendar.setTimeInMillis(System.currentTimeMillis());
552 mClockData.text = DateFormat.getTimeFormat(mContext)
553 .format(mCalendar.getTime());
554 mService.updateIcon(mClockIcon, mClockData, null);
555 }
556
557 private final void updateAlarm(Intent intent) {
558 boolean alarmSet = intent.getBooleanExtra("alarmSet", false);
559 mService.setIconVisibility(mAlarmClockIcon, alarmSet);
560 }
561
562 private final void updateSyncState(Intent intent) {
563 boolean isActive = intent.getBooleanExtra("active", false);
564 boolean isFailing = intent.getBooleanExtra("failing", false);
565 mService.setIconVisibility(mSyncActiveIcon, isActive);
566 // Don't display sync failing icon: BUG 1297963 Set sync error timeout to "never"
567 //mService.setIconVisibility(mSyncFailingIcon, isFailing && !isActive);
568 }
569
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800570 private final void updateBattery(Intent intent) {
571 mBatteryData.iconId = intent.getIntExtra("icon-small", 0);
572 mBatteryData.iconLevel = intent.getIntExtra("level", 0);
573 mService.updateIcon(mBatteryIcon, mBatteryData, null);
574
575 boolean plugged = intent.getIntExtra("plugged", 0) != 0;
576 int level = intent.getIntExtra("level", -1);
577 if (false) {
578 Log.d(TAG, "updateBattery level=" + level
579 + " plugged=" + plugged
580 + " mBatteryPlugged=" + mBatteryPlugged
581 + " mBatteryLevel=" + mBatteryLevel
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800582 + " mBatteryFirst=" + mBatteryFirst);
583 }
584
585 boolean oldPlugged = mBatteryPlugged;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800586
587 mBatteryPlugged = plugged;
588 mBatteryLevel = level;
589
590 if (mBatteryFirst) {
591 mBatteryFirst = false;
592 }
593 /*
594 * No longer showing the battery view because it draws attention away
595 * from the USB storage notification. We could still show it when
596 * connected to a brick, but that could lead to the user into thinking
597 * the device does not charge when plugged into USB (since he/she would
598 * not see the same battery screen on USB as he sees on brick).
599 */
600 /* else {
601 if (plugged && !oldPlugged) {
602 showBatteryView();
603 }
604 }
605 */
606 if (false) {
Mihai Predaa82842f2009-04-29 15:05:56 +0200607 Log.d(TAG, "plugged=" + plugged + " oldPlugged=" + oldPlugged + " level=" + level);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800608 }
Mihai Predaa82842f2009-04-29 15:05:56 +0200609 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800610
Mihai Predaa82842f2009-04-29 15:05:56 +0200611 private void onBatteryLow(Intent intent) {
612 if (SHOW_LOW_BATTERY_WARNING) {
613 if (false) {
614 Log.d(TAG, "mPhoneState=" + mPhoneState
615 + " mLowBatteryDialog=" + mLowBatteryDialog
616 + " mBatteryShowLowOnEndCall=" + mBatteryShowLowOnEndCall);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800617 }
Mihai Predaa82842f2009-04-29 15:05:56 +0200618
619 if (mPhoneState == TelephonyManager.CALL_STATE_IDLE) {
620 showLowBatteryWarning();
621 } else {
622 mBatteryShowLowOnEndCall = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800623 }
624 }
625 }
626
Dianne Hackborn8ec5b832009-07-01 21:19:35 -0700627 private void onBatteryOkay(Intent intent) {
628 if (mLowBatteryDialog != null
629 && SHOW_LOW_BATTERY_WARNING) {
630 mLowBatteryDialog.dismiss();
631 mBatteryShowLowOnEndCall = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800632 }
633 }
634
635 private void showBatteryView() {
636 closeLastBatteryView();
637 if (mLowBatteryDialog != null) {
638 mLowBatteryDialog.dismiss();
639 }
640
641 int level = mBatteryLevel;
642
643 View v = View.inflate(mContext, com.android.internal.R.layout.battery_status, null);
644 mBatteryView = v;
645 int pixelFormat = PixelFormat.TRANSLUCENT;
646 Drawable bg = v.getBackground();
647 if (bg != null) {
648 pixelFormat = bg.getOpacity();
649 }
650
651 WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
652 ViewGroup.LayoutParams.WRAP_CONTENT,
653 ViewGroup.LayoutParams.WRAP_CONTENT,
654 WindowManager.LayoutParams.TYPE_TOAST,
655 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
656 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
657 | WindowManager.LayoutParams.FLAG_BLUR_BEHIND
658 | WindowManager.LayoutParams.FLAG_DIM_BEHIND,
659 pixelFormat);
660
661 // Get the dim amount from the theme
662 TypedArray a = mContext.obtainStyledAttributes(
663 com.android.internal.R.styleable.Theme);
664 lp.dimAmount = a.getFloat(android.R.styleable.Theme_backgroundDimAmount, 0.5f);
665 a.recycle();
Wink Saville04e71b32009-04-02 11:00:54 -0700666
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800667 lp.setTitle("Battery");
668
669 TextView levelTextView = (TextView)v.findViewById(com.android.internal.R.id.level_percent);
670 levelTextView.setText(mContext.getString(
671 com.android.internal.R.string.battery_status_text_percent_format, level));
672
673 setBatteryLevel(v, com.android.internal.R.id.spacer, 100-level, 0, 0);
674 setBatteryLevel(v, com.android.internal.R.id.level, level,
675 com.android.internal.R.drawable.battery_charge_fill, level);
676
677 WindowManagerImpl.getDefault().addView(v, lp);
678
679 scheduleCloseBatteryView();
680 }
681
682 private void setBatteryLevel(View parent, int id, int height, int background, int level) {
683 ImageView v = (ImageView)parent.findViewById(id);
684 LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)v.getLayoutParams();
685 lp.weight = height;
686 if (background != 0) {
687 v.setBackgroundResource(background);
688 Drawable bkg = v.getBackground();
689 bkg.setLevel(level);
690 }
691 }
692
693 private void showLowBatteryWarning() {
694 closeLastBatteryView();
695
Mihai Predaa82842f2009-04-29 15:05:56 +0200696 /* Show exact battery level.
697 * Add 1 because the text says "less than X%".
698 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800699 CharSequence levelText = mContext.getString(
Mihai Predaa82842f2009-04-29 15:05:56 +0200700 com.android.internal.R.string.battery_low_percent_format, mBatteryLevel + 1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800701
702 if (mBatteryLevelTextView != null) {
703 mBatteryLevelTextView.setText(levelText);
704 } else {
705 View v = View.inflate(mContext, com.android.internal.R.layout.battery_low, null);
706 mBatteryLevelTextView=(TextView)v.findViewById(com.android.internal.R.id.level_percent);
707
708 mBatteryLevelTextView.setText(levelText);
709
710 AlertDialog.Builder b = new AlertDialog.Builder(mContext);
711 b.setCancelable(true);
712 b.setTitle(com.android.internal.R.string.battery_low_title);
713 b.setView(v);
714 b.setIcon(android.R.drawable.ic_dialog_alert);
715 b.setPositiveButton(android.R.string.ok, null);
Dianne Hackborn3d74bb42009-06-19 10:35:21 -0700716
717 final Intent intent = new Intent(Intent.ACTION_POWER_USAGE_SUMMARY);
718 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
719 | Intent.FLAG_ACTIVITY_MULTIPLE_TASK
720 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
721 | Intent.FLAG_ACTIVITY_NO_HISTORY);
722 if (intent.resolveActivity(mContext.getPackageManager()) != null) {
723 b.setNegativeButton(com.android.internal.R.string.battery_low_why,
724 new DialogInterface.OnClickListener() {
725 public void onClick(DialogInterface dialog, int which) {
726 mContext.startActivity(intent);
727 if (mLowBatteryDialog != null) {
728 mLowBatteryDialog.dismiss();
729 }
730 }
731 });
732 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800733
734 AlertDialog d = b.create();
735 d.setOnDismissListener(mLowBatteryListener);
736 d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
737 d.show();
738 mLowBatteryDialog = d;
739 }
740 }
741
742 private final void updateCallState(int state) {
743 mPhoneState = state;
744 if (false) {
745 Log.d(TAG, "mPhoneState=" + mPhoneState
746 + " mLowBatteryDialog=" + mLowBatteryDialog
747 + " mBatteryShowLowOnEndCall=" + mBatteryShowLowOnEndCall);
748 }
749 if (mPhoneState == TelephonyManager.CALL_STATE_IDLE) {
750 if (mBatteryShowLowOnEndCall) {
751 if (!mBatteryPlugged) {
752 showLowBatteryWarning();
753 }
754 mBatteryShowLowOnEndCall = false;
755 }
756 } else {
757 if (mLowBatteryDialog != null) {
758 mLowBatteryDialog.dismiss();
759 mBatteryShowLowOnEndCall = true;
760 }
761 }
762 }
763
764 private DialogInterface.OnDismissListener mLowBatteryListener
765 = new DialogInterface.OnDismissListener() {
766 public void onDismiss(DialogInterface dialog) {
767 mLowBatteryDialog = null;
768 mBatteryLevelTextView = null;
769 }
770 };
771
772 private void scheduleCloseBatteryView() {
773 Message m = mHandler.obtainMessage(EVENT_BATTERY_CLOSE);
774 m.arg1 = (++mBatteryViewSequence);
775 mHandler.sendMessageDelayed(m, 3000);
776 }
777
778 private void closeLastBatteryView() {
779 if (mBatteryView != null) {
780 //mBatteryView.debug();
781 WindowManagerImpl.getDefault().removeView(mBatteryView);
782 mBatteryView = null;
783 }
784 }
785
786 private PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
787 @Override
Wink Savillee9b06d72009-05-18 21:47:50 -0700788 public void onSignalStrengthsChanged(SignalStrength signalStrength) {
789 mSignalStrength = signalStrength;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800790 updateSignalStrength();
791 }
792
793 @Override
794 public void onServiceStateChanged(ServiceState state) {
795 mServiceState = state;
796 updateSignalStrength();
Wink Savillee9b06d72009-05-18 21:47:50 -0700797 updateCdmaRoamingIcon();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800798 updateDataIcon();
799 }
800
801 @Override
802 public void onCallStateChanged(int state, String incomingNumber) {
803 updateCallState(state);
804 }
805
806 @Override
807 public void onDataConnectionStateChanged(int state) {
808 mDataState = state;
809 updateDataNetType();
810 updateDataIcon();
811 }
812
813 @Override
814 public void onDataActivity(int direction) {
815 mDataActivity = direction;
816 updateDataIcon();
817 }
818 };
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800819
820 private final void updateSimState(Intent intent) {
Wink Saville04e71b32009-04-02 11:00:54 -0700821 String stateExtra = intent.getStringExtra(IccCard.INTENT_KEY_ICC_STATE);
822 if (IccCard.INTENT_VALUE_ICC_ABSENT.equals(stateExtra)) {
823 mSimState = IccCard.State.ABSENT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800824 }
Wink Saville04e71b32009-04-02 11:00:54 -0700825 else if (IccCard.INTENT_VALUE_ICC_READY.equals(stateExtra)) {
826 mSimState = IccCard.State.READY;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800827 }
Wink Saville04e71b32009-04-02 11:00:54 -0700828 else if (IccCard.INTENT_VALUE_ICC_LOCKED.equals(stateExtra)) {
829 final String lockedReason = intent.getStringExtra(IccCard.INTENT_KEY_LOCKED_REASON);
830 if (IccCard.INTENT_VALUE_LOCKED_ON_PIN.equals(lockedReason)) {
831 mSimState = IccCard.State.PIN_REQUIRED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800832 }
Wink Saville04e71b32009-04-02 11:00:54 -0700833 else if (IccCard.INTENT_VALUE_LOCKED_ON_PUK.equals(lockedReason)) {
834 mSimState = IccCard.State.PUK_REQUIRED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800835 }
836 else {
Wink Saville04e71b32009-04-02 11:00:54 -0700837 mSimState = IccCard.State.NETWORK_LOCKED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800838 }
839 } else {
Wink Saville04e71b32009-04-02 11:00:54 -0700840 mSimState = IccCard.State.UNKNOWN;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800841 }
842 updateDataIcon();
843 }
844
Wink Savillee9b06d72009-05-18 21:47:50 -0700845 private boolean isCdma() {
Wink Savillef3152382009-06-01 14:39:20 -0700846 return ((mPhone != null) && (mPhone.getPhoneType() == TelephonyManager.PHONE_TYPE_CDMA));
Wink Savillee9b06d72009-05-18 21:47:50 -0700847 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800848
Wink Savillee9b06d72009-05-18 21:47:50 -0700849 private boolean hasService() {
850 if (mServiceState != null) {
851 switch (mServiceState.getState()) {
852 case ServiceState.STATE_OUT_OF_SERVICE:
853 case ServiceState.STATE_POWER_OFF:
854 return false;
855 default:
856 return true;
857 }
858 } else {
859 return false;
860 }
861 }
862
863 private final void updateSignalStrength() {
864 int iconLevel = -1;
865 int evdoIconLevel = -1;
866 int[] iconList;
867 int[] evdoIconList;
868
869 if (!hasService()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800870 //Log.d(TAG, "updateSignalStrength: no service");
871 if (Settings.System.getInt(mContext.getContentResolver(),
872 Settings.System.AIRPLANE_MODE_ON, 0) == 1) {
873 mPhoneData.iconId = com.android.internal.R.drawable.stat_sys_signal_flightmode;
874 } else {
875 mPhoneData.iconId = com.android.internal.R.drawable.stat_sys_signal_null;
876 }
877 mService.updateIcon(mPhoneIcon, mPhoneData, null);
Wink Savillee9b06d72009-05-18 21:47:50 -0700878 mService.setIconVisibility(mPhoneEvdoIcon,false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800879 return;
880 }
881
Wink Savillee9b06d72009-05-18 21:47:50 -0700882 if (!isCdma()) {
883 int asu = mSignalStrength.getGsmSignalStrength();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800884
Wink Savillee9b06d72009-05-18 21:47:50 -0700885 // ASU ranges from 0 to 31 - TS 27.007 Sec 8.5
886 // asu = 0 (-113dB or less) is very weak
887 // signal, its better to show 0 bars to the user in such cases.
888 // asu = 99 is a special case, where the signal strength is unknown.
889 if (asu <= 0 || asu == 99) iconLevel = 0;
890 else if (asu >= 16) iconLevel = 4;
891 else if (asu >= 8) iconLevel = 3;
892 else if (asu >= 4) iconLevel = 2;
893 else iconLevel = 1;
894
895 if (mPhone.isNetworkRoaming()) {
896 iconList = sSignalImages_r;
897 } else {
898 iconList = sSignalImages;
Wink Saville04e71b32009-04-02 11:00:54 -0700899 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800900 } else {
Wink Savillee9b06d72009-05-18 21:47:50 -0700901 iconList = this.sSignalImages_cdma;
902
903 int cdmaDbm = mSignalStrength.getCdmaDbm();
904 int cdmaEcio = mSignalStrength.getCdmaEcio();
905 int levelDbm = 0;
906 int levelEcio = 0;
907
908 if (cdmaDbm >= -75) levelDbm = 4;
909 else if (cdmaDbm >= -85) levelDbm = 3;
910 else if (cdmaDbm >= -95) levelDbm = 2;
911 else if (cdmaDbm >= -100) levelDbm = 1;
912 else levelDbm = 0;
913
914 // Ec/Io are in dB*10
915 if (cdmaEcio >= -90) levelEcio = 4;
916 else if (cdmaEcio >= -110) levelEcio = 3;
917 else if (cdmaEcio >= -130) levelEcio = 2;
918 else if (cdmaEcio >= -150) levelEcio = 1;
919 else levelEcio = 0;
920
921 iconLevel = (levelDbm < levelEcio) ? levelDbm : levelEcio;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800922 }
Wink Saville04e71b32009-04-02 11:00:54 -0700923
Wink Savillee9b06d72009-05-18 21:47:50 -0700924 if ((mServiceState.getRadioTechnology() == ServiceState.RADIO_TECHNOLOGY_EVDO_0)
925 || (mServiceState.getRadioTechnology() == ServiceState.RADIO_TECHNOLOGY_EVDO_A)) {
926 // Use Evdo icon
927 evdoIconList = this.sSignalImages_evdo;
928
929 int evdoEcio = mSignalStrength.getEvdoEcio();
930 int evdoSnr = mSignalStrength.getEvdoSnr();
931 int levelEvdoEcio = 0;
932 int levelEvdoSnr = 0;
933
934 // Ec/Io are in dB*10
935 if (evdoEcio >= -650) levelEvdoEcio = 4;
936 else if (evdoEcio >= -750) levelEvdoEcio = 3;
937 else if (evdoEcio >= -900) levelEvdoEcio = 2;
938 else if (evdoEcio >= -1050) levelEvdoEcio = 1;
939 else levelEvdoEcio = 0;
940
941 if (evdoSnr > 7) levelEvdoSnr = 4;
942 else if (evdoSnr > 5) levelEvdoSnr = 3;
943 else if (evdoSnr > 3) levelEvdoSnr = 2;
944 else if (evdoSnr > 1) levelEvdoSnr = 1;
945 else levelEvdoSnr = 0;
946
947 evdoIconLevel = (levelEvdoEcio < levelEvdoSnr) ? levelEvdoEcio : levelEvdoSnr;
948
949 mPhoneEvdoData.iconId = evdoIconList[evdoIconLevel];
950 mService.updateIcon(mPhoneEvdoIcon, mPhoneEvdoData, null);
951 mService.setIconVisibility(mPhoneEvdoIcon,true);
952 } else {
953 mService.setIconVisibility(mPhoneEvdoIcon,false);
954 }
955
956 mPhoneData.iconId = iconList[iconLevel];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800957 mService.updateIcon(mPhoneIcon, mPhoneData, null);
958 }
959
960 private final void updateDataNetType() {
Wink Saville04e71b32009-04-02 11:00:54 -0700961 int net = mPhone.getNetworkType();
Wink Saville04e71b32009-04-02 11:00:54 -0700962
963 switch (net) {
Wink Saville04e71b32009-04-02 11:00:54 -0700964 case TelephonyManager.NETWORK_TYPE_EDGE:
965 mDataIconList = sDataNetType_e;
966 break;
967 case TelephonyManager.NETWORK_TYPE_UMTS:
968 mDataIconList = sDataNetType_3g;
969 break;
970 case TelephonyManager.NETWORK_TYPE_CDMA:
971 // display 1xRTT for IS95A/B
972 mDataIconList = this.sDataNetType_1xrtt;
973 break;
974 case TelephonyManager.NETWORK_TYPE_1xRTT:
975 mDataIconList = this.sDataNetType_1xrtt;
976 break;
977 case TelephonyManager.NETWORK_TYPE_EVDO_0: //fall through
978 case TelephonyManager.NETWORK_TYPE_EVDO_A:
979 mDataIconList = sDataNetType_evdo;
980 break;
981 default:
982 mDataIconList = sDataNetType_g;
983 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800984 }
985 }
986
987 private final void updateDataIcon() {
988 int iconId;
989 boolean visible = true;
990
Wink Savillee9b06d72009-05-18 21:47:50 -0700991 if (!isCdma()) {
992 // GSM case, we have to check also the sim state
993 if (mSimState == IccCard.State.READY || mSimState == IccCard.State.UNKNOWN) {
994 if (hasService() && mDataState == TelephonyManager.DATA_CONNECTED) {
995 switch (mDataActivity) {
996 case TelephonyManager.DATA_ACTIVITY_IN:
997 iconId = mDataIconList[1];
998 break;
999 case TelephonyManager.DATA_ACTIVITY_OUT:
1000 iconId = mDataIconList[2];
1001 break;
1002 case TelephonyManager.DATA_ACTIVITY_INOUT:
1003 iconId = mDataIconList[3];
1004 break;
1005 default:
1006 iconId = mDataIconList[0];
1007 break;
1008 }
1009 mDataData.iconId = iconId;
1010 mService.updateIcon(mDataIcon, mDataData, null);
1011 } else {
1012 visible = false;
1013 }
1014 } else {
1015 mDataData.iconId = com.android.internal.R.drawable.stat_sys_no_sim;
1016 mService.updateIcon(mDataIcon, mDataData, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001017 }
Wink Savillee9b06d72009-05-18 21:47:50 -07001018 } else {
1019 // CDMA case, mDataActivity can be also DATA_ACTIVITY_DORMANT
1020 if (hasService() && mDataState == TelephonyManager.DATA_CONNECTED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001021 switch (mDataActivity) {
1022 case TelephonyManager.DATA_ACTIVITY_IN:
Wink Savillee9b06d72009-05-18 21:47:50 -07001023 iconId = mDataIconList[1];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001024 break;
1025 case TelephonyManager.DATA_ACTIVITY_OUT:
Wink Savillee9b06d72009-05-18 21:47:50 -07001026 iconId = mDataIconList[2];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001027 break;
1028 case TelephonyManager.DATA_ACTIVITY_INOUT:
Wink Savillee9b06d72009-05-18 21:47:50 -07001029 iconId = mDataIconList[3];
1030 break;
1031 case TelephonyManager.DATA_ACTIVITY_DORMANT:
1032 iconId = mDataIconList[4];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001033 break;
1034 default:
Wink Savillee9b06d72009-05-18 21:47:50 -07001035 iconId = mDataIconList[0];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001036 break;
1037 }
1038 mDataData.iconId = iconId;
1039 mService.updateIcon(mDataIcon, mDataData, null);
1040 } else {
1041 visible = false;
1042 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001043 }
Wink Savillee9b06d72009-05-18 21:47:50 -07001044
Dianne Hackborn4840e142009-03-24 22:40:29 -07001045 long ident = Binder.clearCallingIdentity();
1046 try {
Wink Saville04e71b32009-04-02 11:00:54 -07001047 mBatteryStats.notePhoneDataConnectionState(mPhone.getNetworkType(), visible);
Dianne Hackborn4840e142009-03-24 22:40:29 -07001048 } catch (RemoteException e) {
1049 } finally {
1050 Binder.restoreCallingIdentity(ident);
1051 }
Wink Savillee9b06d72009-05-18 21:47:50 -07001052
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001053 if (mDataIconVisible != visible) {
1054 mService.setIconVisibility(mDataIcon, visible);
1055 mDataIconVisible = visible;
1056 }
1057 }
1058
1059 private final void updateVolume() {
1060 AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
1061 final int ringerMode = audioManager.getRingerMode();
1062 final boolean visible = ringerMode == AudioManager.RINGER_MODE_SILENT ||
Wink Savillee9b06d72009-05-18 21:47:50 -07001063 ringerMode == AudioManager.RINGER_MODE_VIBRATE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001064 final int iconId = audioManager.shouldVibrate(AudioManager.VIBRATE_TYPE_RINGER)
1065 ? com.android.internal.R.drawable.stat_sys_ringer_vibrate
1066 : com.android.internal.R.drawable.stat_sys_ringer_silent;
1067
1068 if (visible) {
1069 mVolumeData.iconId = iconId;
1070 mService.updateIcon(mVolumeIcon, mVolumeData, null);
1071 }
1072 if (visible != mVolumeVisible) {
1073 mService.setIconVisibility(mVolumeIcon, visible);
1074 mVolumeVisible = visible;
1075 }
1076 }
1077
1078 private final void updateBluetooth(Intent intent) {
1079 int iconId = com.android.internal.R.drawable.stat_sys_data_bluetooth;
1080
1081 String action = intent.getAction();
The Android Open Source Project10592532009-03-18 17:39:46 -07001082 if (action.equals(BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION)) {
1083 int state = intent.getIntExtra(BluetoothIntent.BLUETOOTH_STATE,
1084 BluetoothError.ERROR);
1085 mBluetoothEnabled = state == BluetoothDevice.BLUETOOTH_STATE_ON;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001086 } else if (action.equals(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION)) {
1087 mBluetoothHeadsetState = intent.getIntExtra(BluetoothIntent.HEADSET_STATE,
1088 BluetoothHeadset.STATE_ERROR);
1089 } else if (action.equals(BluetoothA2dp.SINK_STATE_CHANGED_ACTION)) {
1090 mBluetoothA2dpState = intent.getIntExtra(BluetoothA2dp.SINK_STATE,
1091 BluetoothA2dp.STATE_DISCONNECTED);
Jiafa Liu3f416732009-07-02 16:36:02 +08001092 } else if (action.equals(BluetoothPbap.PBAP_STATE_CHANGED_ACTION)) {
1093 mBluetoothPbapState = intent.getIntExtra(BluetoothPbap.PBAP_STATE,
1094 BluetoothPbap.STATE_DISCONNECTED);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001095 } else {
1096 return;
1097 }
Wink Savillee9b06d72009-05-18 21:47:50 -07001098
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001099 if (mBluetoothHeadsetState == BluetoothHeadset.STATE_CONNECTED ||
1100 mBluetoothA2dpState == BluetoothA2dp.STATE_CONNECTED ||
Jiafa Liu3f416732009-07-02 16:36:02 +08001101 mBluetoothA2dpState == BluetoothA2dp.STATE_PLAYING ||
1102 mBluetoothPbapState == BluetoothPbap.STATE_CONNECTED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001103 iconId = com.android.internal.R.drawable.stat_sys_data_bluetooth_connected;
1104 }
1105
1106 mBluetoothData.iconId = iconId;
1107 mService.updateIcon(mBluetoothIcon, mBluetoothData, null);
1108 mService.setIconVisibility(mBluetoothIcon, mBluetoothEnabled);
1109 }
1110
1111 private final void updateWifi(Intent intent) {
1112 final String action = intent.getAction();
1113 if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
Wink Savillee9b06d72009-05-18 21:47:50 -07001114
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001115 final boolean enabled = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
1116 WifiManager.WIFI_STATE_UNKNOWN) == WifiManager.WIFI_STATE_ENABLED;
Wink Savillee9b06d72009-05-18 21:47:50 -07001117
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001118 if (!enabled) {
1119 // If disabled, hide the icon. (We show icon when connected.)
1120 mService.setIconVisibility(mWifiIcon, false);
1121 }
Wink Savillee9b06d72009-05-18 21:47:50 -07001122
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001123 } else if (action.equals(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION)) {
1124 final boolean enabled = intent.getBooleanExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED,
1125 false);
1126 if (!enabled) {
1127 mService.setIconVisibility(mWifiIcon, false);
1128 }
1129 } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
1130
Wink Savillee9b06d72009-05-18 21:47:50 -07001131 final NetworkInfo networkInfo = (NetworkInfo)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001132 intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
Wink Savillee9b06d72009-05-18 21:47:50 -07001133
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001134 int iconId;
1135 if (networkInfo != null && networkInfo.isConnected()) {
1136 mIsWifiConnected = true;
1137 if (mLastWifiSignalLevel == -1) {
1138 iconId = sWifiSignalImages[0];
1139 } else {
1140 iconId = sWifiSignalImages[mLastWifiSignalLevel];
1141 }
Wink Saville04e71b32009-04-02 11:00:54 -07001142
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001143 // Show the icon since wi-fi is connected
1144 mService.setIconVisibility(mWifiIcon, true);
Wink Saville04e71b32009-04-02 11:00:54 -07001145
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001146 } else {
1147 mLastWifiSignalLevel = -1;
1148 mIsWifiConnected = false;
1149 iconId = sWifiSignalImages[0];
1150
1151 // Hide the icon since we're not connected
1152 mService.setIconVisibility(mWifiIcon, false);
1153 }
1154
1155 mWifiData.iconId = iconId;
1156 mService.updateIcon(mWifiIcon, mWifiData, null);
1157 } else if (action.equals(WifiManager.RSSI_CHANGED_ACTION)) {
1158 final int newRssi = intent.getIntExtra(WifiManager.EXTRA_NEW_RSSI, -200);
1159 int newSignalLevel = WifiManager.calculateSignalLevel(newRssi,
1160 sWifiSignalImages.length);
1161 if (newSignalLevel != mLastWifiSignalLevel) {
1162 mLastWifiSignalLevel = newSignalLevel;
1163 if (mIsWifiConnected) {
1164 mWifiData.iconId = sWifiSignalImages[newSignalLevel];
1165 } else {
1166 mWifiData.iconId = sWifiTemporarilyNotConnectedImage;
1167 }
1168 mService.updateIcon(mWifiIcon, mWifiData, null);
1169 }
1170 }
1171 }
1172
1173 private final void updateGps(Intent intent) {
1174 final String action = intent.getAction();
1175 final boolean enabled = intent.getBooleanExtra(GpsLocationProvider.EXTRA_ENABLED, false);
1176
1177 if (action.equals(GpsLocationProvider.GPS_FIX_CHANGE_ACTION) && enabled) {
1178 // GPS is getting fixes
1179 mService.updateIcon(mGpsIcon, mGpsFixIconData, null);
Wink Savillee9b06d72009-05-18 21:47:50 -07001180 mService.setIconVisibility(mGpsIcon, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001181 } else if (action.equals(GpsLocationProvider.GPS_ENABLED_CHANGE_ACTION) && !enabled) {
1182 // GPS is off
Wink Savillee9b06d72009-05-18 21:47:50 -07001183 mService.setIconVisibility(mGpsIcon, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001184 } else {
1185 // GPS is on, but not receiving fixes
1186 mService.updateIcon(mGpsIcon, mGpsEnabledIconData, null);
Wink Savillee9b06d72009-05-18 21:47:50 -07001187 mService.setIconVisibility(mGpsIcon, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001188 }
1189 }
1190
Wink Savillee9b06d72009-05-18 21:47:50 -07001191 private final void updateTTY(Intent intent) {
Wink Saville04e71b32009-04-02 11:00:54 -07001192 final String action = intent.getAction();
1193 final boolean enabled = intent.getBooleanExtra(TtyIntent.TTY_ENABLED, false);
1194
1195 Log.i(TAG, "updateTTY: enabled: " + enabled);
1196
1197 if (enabled) {
1198 // TTY is on
1199 Log.i(TAG, "updateTTY: set TTY on");
1200 mService.updateIcon(mTTYModeIcon, mTTYModeEnableIconData, null);
Wink Savillee9b06d72009-05-18 21:47:50 -07001201 mService.setIconVisibility(mTTYModeIcon, true);
Wink Saville04e71b32009-04-02 11:00:54 -07001202 } else {
1203 // TTY is off
1204 Log.i(TAG, "updateTTY: set TTY off");
Wink Savillee9b06d72009-05-18 21:47:50 -07001205 mService.setIconVisibility(mTTYModeIcon, false);
Wink Saville04e71b32009-04-02 11:00:54 -07001206 }
1207 }
1208
Wink Savillee9b06d72009-05-18 21:47:50 -07001209 private final void updateCdmaRoamingIcon() {
1210 if (!hasService()) {
1211 mService.setIconVisibility(mCdmaRoamingIndicatorIcon, false);
Wink Savillef3152382009-06-01 14:39:20 -07001212 return;
Wink Savillee9b06d72009-05-18 21:47:50 -07001213 }
1214
1215 if (!isCdma()) {
1216 mService.setIconVisibility(mCdmaRoamingIndicatorIcon, false);
Wink Savillef3152382009-06-01 14:39:20 -07001217 return;
Wink Savillee9b06d72009-05-18 21:47:50 -07001218 }
1219
1220 int[] iconList = sRoamingIndicatorImages_cdma;
1221 int iconIndex = mPhone.getCdmaEriIconIndex();
1222 int iconMode = mPhone.getCdmaEriIconMode();
1223
1224 if (iconIndex == -1) {
1225 Log.e(TAG, "getCdmaEriIconIndex returned null, skipping ERI icon update");
1226 return;
1227 }
1228
1229 if (iconMode == -1) {
1230 Log.e(TAG, "getCdmeEriIconMode returned null, skipping ERI icon update");
1231 return;
1232 }
1233
1234 if (iconIndex == EriInfo.ROAMING_INDICATOR_OFF) {
1235 Log.d(TAG, "Cdma ROAMING_INDICATOR_OFF, removing ERI icon");
1236 mService.setIconVisibility(mCdmaRoamingIndicatorIcon, false);
1237 return;
1238 }
1239
1240 switch (iconMode) {
1241 case EriInfo.ROAMING_ICON_MODE_NORMAL:
1242 mCdmaRoamingIndicatorIconData.iconId = iconList[iconIndex];
1243 mService.updateIcon(mCdmaRoamingIndicatorIcon, mCdmaRoamingIndicatorIconData, null);
1244 mService.setIconVisibility(mCdmaRoamingIndicatorIcon, true);
1245 break;
1246 case EriInfo.ROAMING_ICON_MODE_FLASH:
Wink Savillef3152382009-06-01 14:39:20 -07001247 mCdmaRoamingIndicatorIconData.iconId =
1248 com.android.internal.R.drawable.stat_sys_roaming_cdma_flash;
Wink Savillee9b06d72009-05-18 21:47:50 -07001249 mService.updateIcon(mCdmaRoamingIndicatorIcon, mCdmaRoamingIndicatorIconData, null);
Wink Savillef3152382009-06-01 14:39:20 -07001250 mService.setIconVisibility(mCdmaRoamingIndicatorIcon, true);
Wink Savillee9b06d72009-05-18 21:47:50 -07001251 break;
1252
1253 }
1254 mService.updateIcon(mPhoneIcon, mPhoneData, null);
1255 }
1256
1257
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001258 private class StatusBarHandler extends Handler {
1259 @Override
1260 public void handleMessage(Message msg) {
1261 switch (msg.what) {
1262 case EVENT_BATTERY_CLOSE:
1263 if (msg.arg1 == mBatteryViewSequence) {
1264 closeLastBatteryView();
1265 }
1266 break;
1267 }
1268 }
1269 }
1270}