blob: 65b2ddb4075ce1e7a9dc598797080dbd8000c65e [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.status;
18
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080019import android.app.AlertDialog;
20import android.bluetooth.BluetoothA2dp;
Nick Pellybd022f42009-08-14 18:33:38 -070021import android.bluetooth.BluetoothAdapter;
The Android Open Source Project10592532009-03-18 17:39:46 -070022import android.bluetooth.BluetoothError;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080023import android.bluetooth.BluetoothHeadset;
24import android.bluetooth.BluetoothIntent;
Jiafa Liu3f416732009-07-02 16:36:02 +080025import android.bluetooth.BluetoothPbap;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080026import android.content.BroadcastReceiver;
27import android.content.Context;
28import android.content.DialogInterface;
29import android.content.Intent;
30import android.content.IntentFilter;
31import android.content.res.TypedArray;
32import android.graphics.PixelFormat;
33import android.graphics.drawable.Drawable;
34import android.media.AudioManager;
35import android.net.NetworkInfo;
36import android.net.wifi.WifiManager;
Dianne Hackborn4840e142009-03-24 22:40:29 -070037import android.os.Binder;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080038import android.os.Handler;
39import android.os.IBinder;
40import android.os.Message;
Dianne Hackborn4840e142009-03-24 22:40:29 -070041import android.os.RemoteException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080042import android.provider.Settings;
43import android.telephony.PhoneStateListener;
44import android.telephony.ServiceState;
Wink Savillee9b06d72009-05-18 21:47:50 -070045import android.telephony.SignalStrength;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080046import android.telephony.TelephonyManager;
47import android.text.format.DateFormat;
48import android.util.Log;
49import android.view.View;
50import android.view.ViewGroup;
51import android.view.WindowManager;
52import android.view.WindowManagerImpl;
53import android.widget.ImageView;
54import android.widget.LinearLayout;
55import android.widget.TextView;
56
Wink Saville04e71b32009-04-02 11:00:54 -070057import com.android.internal.R;
58import com.android.internal.app.IBatteryStats;
59import com.android.internal.location.GpsLocationProvider;
60import com.android.internal.telephony.IccCard;
61import com.android.internal.telephony.TelephonyIntents;
Wink Savillee9b06d72009-05-18 21:47:50 -070062import com.android.internal.telephony.cdma.EriInfo;
Wink Saville04e71b32009-04-02 11:00:54 -070063import com.android.internal.telephony.cdma.TtyIntent;
64import com.android.server.am.BatteryStatsService;
65
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080066import java.util.Calendar;
67import java.util.TimeZone;
68
69/**
70 * This class contains all of the policy about which icons are installed in the status
71 * bar at boot time. In reality, it should go into the android.policy package, but
72 * putting it here is the first step from extracting it.
73 */
74public class StatusBarPolicy {
75 private static final String TAG = "StatusBarPolicy";
76
77 private static StatusBarPolicy sInstance;
78
79 // message codes for the handler
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080080 private static final int EVENT_BATTERY_CLOSE = 4;
81
Dianne Hackborn4840e142009-03-24 22:40:29 -070082 private final Context mContext;
83 private final StatusBarService mService;
84 private final Handler mHandler = new StatusBarHandler();
85 private final IBatteryStats mBatteryStats;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080086
87 // clock
88 private Calendar mCalendar;
89 private IBinder mClockIcon;
90 private IconData mClockData;
91
92 // battery
93 private IBinder mBatteryIcon;
94 private IconData mBatteryData;
95 private boolean mBatteryFirst = true;
96 private boolean mBatteryPlugged;
97 private int mBatteryLevel;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080098 private AlertDialog mLowBatteryDialog;
99 private TextView mBatteryLevelTextView;
100 private View mBatteryView;
101 private int mBatteryViewSequence;
102 private boolean mBatteryShowLowOnEndCall = false;
103 private static final boolean SHOW_LOW_BATTERY_WARNING = true;
104
105 // phone
106 private TelephonyManager mPhone;
107 private IBinder mPhoneIcon;
Wink Saville04e71b32009-04-02 11:00:54 -0700108
109 //***** Signal strength icons
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800110 private IconData mPhoneData;
Wink Saville04e71b32009-04-02 11:00:54 -0700111 //GSM/UMTS
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800112 private static final int[] sSignalImages = new int[] {
Wink Savillee9b06d72009-05-18 21:47:50 -0700113 com.android.internal.R.drawable.stat_sys_signal_0,
114 com.android.internal.R.drawable.stat_sys_signal_1,
115 com.android.internal.R.drawable.stat_sys_signal_2,
116 com.android.internal.R.drawable.stat_sys_signal_3,
117 com.android.internal.R.drawable.stat_sys_signal_4
118 };
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800119 private static final int[] sSignalImages_r = new int[] {
Wink Savillee9b06d72009-05-18 21:47:50 -0700120 com.android.internal.R.drawable.stat_sys_r_signal_0,
121 com.android.internal.R.drawable.stat_sys_r_signal_1,
122 com.android.internal.R.drawable.stat_sys_r_signal_2,
123 com.android.internal.R.drawable.stat_sys_r_signal_3,
124 com.android.internal.R.drawable.stat_sys_r_signal_4
125 };
Wink Savillee9b06d72009-05-18 21:47:50 -0700126 private static final int[] sRoamingIndicatorImages_cdma = new int[] {
127 com.android.internal.R.drawable.stat_sys_roaming_cdma_0, //Standard Roaming Indicator
128 // 1 is Standard Roaming Indicator OFF
129 // TODO T: image never used, remove and put 0 instead?
130 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
131
132 // 2 is Standard Roaming Indicator FLASHING
133 // TODO T: image never used, remove and put 0 instead?
134 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
135
136 // 3-12 Standard ERI
137 com.android.internal.R.drawable.stat_sys_roaming_cdma_0, //3
138 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
139 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
140 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
141 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
142 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
143 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
144 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
145 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
146 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
147
148 // 13-63 Reserved for Standard ERI
149 com.android.internal.R.drawable.stat_sys_roaming_cdma_0, //13
150 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
151 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
152 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
153 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
154 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
155 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
156 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
157 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
158 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
159 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
160 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
161 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
162 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
163 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
164 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
165 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
166 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
167 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
168 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
169 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
170 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
171 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
172 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
173 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
174 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
175 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
176 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
177 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
178 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
179 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
180 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
181 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
182 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
183 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
184 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
185 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
186 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
187 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
188 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
189 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
190 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
191 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
192 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
193 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
194 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
195 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
196 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
197 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
198 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
199 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
200
201 // 64-127 Reserved for Non Standard (Operator Specific) ERI
202 com.android.internal.R.drawable.stat_sys_roaming_cdma_0, //64
203 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
204 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
205 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
206 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
207 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
208 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
209 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
210 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
211 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
212 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
213 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
214 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
215 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
216 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
217 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
218 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
219 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
220 com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
221 com.android.internal.R.drawable.stat_sys_roaming_cdma_0 //83
222
223 // 128-255 Reserved
Wink Saville04e71b32009-04-02 11:00:54 -0700224 };
Wink Saville04e71b32009-04-02 11:00:54 -0700225
226 //***** Data connection icons
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800227 private int[] mDataIconList = sDataNetType_g;
Wink Saville04e71b32009-04-02 11:00:54 -0700228 //GSM/UMTS
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800229 private static final int[] sDataNetType_g = new int[] {
230 com.android.internal.R.drawable.stat_sys_data_connected_g,
231 com.android.internal.R.drawable.stat_sys_data_in_g,
232 com.android.internal.R.drawable.stat_sys_data_out_g,
233 com.android.internal.R.drawable.stat_sys_data_inandout_g,
234 };
235 private static final int[] sDataNetType_3g = new int[] {
236 com.android.internal.R.drawable.stat_sys_data_connected_3g,
237 com.android.internal.R.drawable.stat_sys_data_in_3g,
238 com.android.internal.R.drawable.stat_sys_data_out_3g,
239 com.android.internal.R.drawable.stat_sys_data_inandout_3g,
240 };
241 private static final int[] sDataNetType_e = new int[] {
242 com.android.internal.R.drawable.stat_sys_data_connected_e,
243 com.android.internal.R.drawable.stat_sys_data_in_e,
244 com.android.internal.R.drawable.stat_sys_data_out_e,
245 com.android.internal.R.drawable.stat_sys_data_inandout_e,
246 };
Li Zheebe66342009-08-14 19:22:16 +0800247 //3.5G
248 private static final int[] sDataNetType_h = new int[] {
249 com.android.internal.R.drawable.stat_sys_data_connected_h,
250 com.android.internal.R.drawable.stat_sys_data_in_h,
251 com.android.internal.R.drawable.stat_sys_data_out_h,
252 com.android.internal.R.drawable.stat_sys_data_inandout_h,
253 };
254
Wink Saville04e71b32009-04-02 11:00:54 -0700255 //CDMA
256 private static final int[] sDataNetType_evdo = new int[] {
257 com.android.internal.R.drawable.stat_sys_data_connected_evdo,
258 com.android.internal.R.drawable.stat_sys_data_in_evdo,
259 com.android.internal.R.drawable.stat_sys_data_out_evdo,
260 com.android.internal.R.drawable.stat_sys_data_inandout_evdo,
Wink Savillee9b06d72009-05-18 21:47:50 -0700261 com.android.internal.R.drawable.stat_sys_data_dormant_evdo,
Wink Saville04e71b32009-04-02 11:00:54 -0700262 };
263 private static final int[] sDataNetType_1xrtt = new int[] {
264 com.android.internal.R.drawable.stat_sys_data_connected_1xrtt,
265 com.android.internal.R.drawable.stat_sys_data_in_1xrtt,
266 com.android.internal.R.drawable.stat_sys_data_out_1xrtt,
267 com.android.internal.R.drawable.stat_sys_data_inandout_1xrtt,
Wink Savillee9b06d72009-05-18 21:47:50 -0700268 com.android.internal.R.drawable.stat_sys_data_dormant_1xrtt,
Wink Saville04e71b32009-04-02 11:00:54 -0700269 };
270
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800271 // Assume it's all good unless we hear otherwise. We don't always seem
272 // to get broadcasts that it *is* there.
Wink Saville04e71b32009-04-02 11:00:54 -0700273 IccCard.State mSimState = IccCard.State.READY;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800274 int mPhoneState = TelephonyManager.CALL_STATE_IDLE;
275 int mDataState = TelephonyManager.DATA_DISCONNECTED;
276 int mDataActivity = TelephonyManager.DATA_ACTIVITY_NONE;
277 ServiceState mServiceState;
Wink Savillee9b06d72009-05-18 21:47:50 -0700278 SignalStrength mSignalStrength;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800279
280 // data connection
281 private IBinder mDataIcon;
282 private IconData mDataData;
283 private boolean mDataIconVisible;
284
285 // ringer volume
286 private IBinder mVolumeIcon;
287 private IconData mVolumeData;
288 private boolean mVolumeVisible;
Wink Saville04e71b32009-04-02 11:00:54 -0700289
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800290 // bluetooth device status
291 private IBinder mBluetoothIcon;
292 private IconData mBluetoothData;
293 private int mBluetoothHeadsetState;
294 private int mBluetoothA2dpState;
Jiafa Liu3f416732009-07-02 16:36:02 +0800295 private int mBluetoothPbapState;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800296 private boolean mBluetoothEnabled;
297
298 // wifi
299 private static final int[] sWifiSignalImages = new int[] {
300 com.android.internal.R.drawable.stat_sys_wifi_signal_1,
301 com.android.internal.R.drawable.stat_sys_wifi_signal_2,
302 com.android.internal.R.drawable.stat_sys_wifi_signal_3,
303 com.android.internal.R.drawable.stat_sys_wifi_signal_4,
304 };
305 private static final int sWifiTemporarilyNotConnectedImage =
306 com.android.internal.R.drawable.stat_sys_wifi_signal_0;
307
308 private int mLastWifiSignalLevel = -1;
309 private boolean mIsWifiConnected = false;
310 private IBinder mWifiIcon;
311 private IconData mWifiData;
312
313 // gps
314 private IBinder mGpsIcon;
315 private IconData mGpsEnabledIconData;
316 private IconData mGpsFixIconData;
317
318 // alarm clock
319 // Icon lit when clock is set
320 private IBinder mAlarmClockIcon;
321 private IconData mAlarmClockIconData;
322
323 // sync state
324 // If sync is active the SyncActive icon is displayed. If sync is not active but
325 // sync is failing the SyncFailing icon is displayed. Otherwise neither are displayed.
326 private IBinder mSyncActiveIcon;
327 private IBinder mSyncFailingIcon;
328
Wink Saville04e71b32009-04-02 11:00:54 -0700329 // TTY mode
330 // Icon lit when TTY mode is enabled
331 private IBinder mTTYModeIcon;
332 private IconData mTTYModeEnableIconData;
333
Wink Savillee9b06d72009-05-18 21:47:50 -0700334 // Cdma Roaming Indicator, ERI
335 private IBinder mCdmaRoamingIndicatorIcon;
336 private IconData mCdmaRoamingIndicatorIconData;
337
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800338 private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
339 @Override
340 public void onReceive(Context context, Intent intent) {
341 String action = intent.getAction();
342 if (action.equals(Intent.ACTION_TIME_TICK)) {
343 updateClock();
344 }
345 else if (action.equals(Intent.ACTION_TIME_CHANGED)) {
346 updateClock();
347 }
Dianne Hackborn8ec5b832009-07-01 21:19:35 -0700348 else if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
349 updateBattery(intent);
350 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800351 else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
352 updateClock();
353 }
354 else if (action.equals(Intent.ACTION_TIMEZONE_CHANGED)) {
355 String tz = intent.getStringExtra("time-zone");
356 mCalendar = Calendar.getInstance(TimeZone.getTimeZone(tz));
357 updateClock();
358 }
359 else if (action.equals(Intent.ACTION_ALARM_CHANGED)) {
360 updateAlarm(intent);
361 }
362 else if (action.equals(Intent.ACTION_SYNC_STATE_CHANGED)) {
363 updateSyncState(intent);
364 }
Mihai Predaa82842f2009-04-29 15:05:56 +0200365 else if (action.equals(Intent.ACTION_BATTERY_LOW)) {
366 onBatteryLow(intent);
367 }
Mike Lockwood69eb0bf2009-08-01 23:02:28 -0400368 else if (action.equals(Intent.ACTION_BATTERY_OKAY)
369 || action.equals(Intent.ACTION_POWER_CONNECTED)) {
Dianne Hackborn8ec5b832009-07-01 21:19:35 -0700370 onBatteryOkay(intent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800371 }
The Android Open Source Project10592532009-03-18 17:39:46 -0700372 else if (action.equals(BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION) ||
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800373 action.equals(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION) ||
Jiafa Liu3f416732009-07-02 16:36:02 +0800374 action.equals(BluetoothA2dp.SINK_STATE_CHANGED_ACTION) ||
375 action.equals(BluetoothPbap.PBAP_STATE_CHANGED_ACTION)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800376 updateBluetooth(intent);
377 }
378 else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION) ||
379 action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION) ||
380 action.equals(WifiManager.RSSI_CHANGED_ACTION)) {
381 updateWifi(intent);
382 }
383 else if (action.equals(GpsLocationProvider.GPS_ENABLED_CHANGE_ACTION) ||
384 action.equals(GpsLocationProvider.GPS_FIX_CHANGE_ACTION)) {
385 updateGps(intent);
386 }
387 else if (action.equals(AudioManager.RINGER_MODE_CHANGED_ACTION) ||
388 action.equals(AudioManager.VIBRATE_SETTING_CHANGED_ACTION)) {
389 updateVolume();
390 }
391 else if (action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) {
392 updateSimState(intent);
393 }
Wink Saville04e71b32009-04-02 11:00:54 -0700394 else if (action.equals(TtyIntent.TTY_ENABLED_CHANGE_ACTION)) {
395 updateTTY(intent);
396 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800397 }
398 };
399
400 private StatusBarPolicy(Context context, StatusBarService service) {
401 mContext = context;
402 mService = service;
Wink Savillee9b06d72009-05-18 21:47:50 -0700403 mSignalStrength = new SignalStrength();
Dianne Hackborn4840e142009-03-24 22:40:29 -0700404 mBatteryStats = BatteryStatsService.getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800405
406 // clock
407 mCalendar = Calendar.getInstance(TimeZone.getDefault());
408 mClockData = IconData.makeText("clock", "");
409 mClockIcon = service.addIcon(mClockData, null);
410 updateClock();
411
412 // battery
413 mBatteryData = IconData.makeIcon("battery",
414 null, com.android.internal.R.drawable.stat_sys_battery_unknown, 0, 0);
415 mBatteryIcon = service.addIcon(mBatteryData, null);
416
417 // phone_signal
418 mPhone = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
Wink Savillee9b06d72009-05-18 21:47:50 -0700419 mPhoneData = IconData.makeIcon("phone_signal",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800420 null, com.android.internal.R.drawable.stat_sys_signal_null, 0, 0);
421 mPhoneIcon = service.addIcon(mPhoneData, null);
Wink Savillee9b06d72009-05-18 21:47:50 -0700422
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800423 // register for phone state notifications.
424 ((TelephonyManager)mContext.getSystemService(Context.TELEPHONY_SERVICE))
425 .listen(mPhoneStateListener,
426 PhoneStateListener.LISTEN_SERVICE_STATE
Wink Savillee9b06d72009-05-18 21:47:50 -0700427 | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800428 | PhoneStateListener.LISTEN_CALL_STATE
429 | PhoneStateListener.LISTEN_DATA_CONNECTION_STATE
430 | PhoneStateListener.LISTEN_DATA_ACTIVITY);
431
432 // data_connection
433 mDataData = IconData.makeIcon("data_connection",
434 null, com.android.internal.R.drawable.stat_sys_data_connected_g, 0, 0);
435 mDataIcon = service.addIcon(mDataData, null);
436 service.setIconVisibility(mDataIcon, false);
437
438 // wifi
439 mWifiData = IconData.makeIcon("wifi", null, sWifiSignalImages[0], 0, 0);
440 mWifiIcon = service.addIcon(mWifiData, null);
441 service.setIconVisibility(mWifiIcon, false);
442 // wifi will get updated by the sticky intents
Wink Saville04e71b32009-04-02 11:00:54 -0700443
444 // TTY status
445 mTTYModeEnableIconData = IconData.makeIcon("tty",
446 null, com.android.internal.R.drawable.stat_sys_tty_mode, 0, 0);
447 mTTYModeIcon = service.addIcon(mTTYModeEnableIconData, null);
448 service.setIconVisibility(mTTYModeIcon, false);
449
Wink Savillee9b06d72009-05-18 21:47:50 -0700450 // Cdma Roaming Indicator, ERI
451 mCdmaRoamingIndicatorIconData = IconData.makeIcon("cdma_eri",
452 null, com.android.internal.R.drawable.stat_sys_roaming_cdma_0, 0, 0);
453 mCdmaRoamingIndicatorIcon = service.addIcon(mCdmaRoamingIndicatorIconData, null);
454 service.setIconVisibility(mCdmaRoamingIndicatorIcon, false);
455
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800456 // bluetooth status
457 mBluetoothData = IconData.makeIcon("bluetooth",
458 null, com.android.internal.R.drawable.stat_sys_data_bluetooth, 0, 0);
459 mBluetoothIcon = service.addIcon(mBluetoothData, null);
Nick Pellybd022f42009-08-14 18:33:38 -0700460 BluetoothAdapter adapter =
461 (BluetoothAdapter) mContext.getSystemService(Context.BLUETOOTH_SERVICE);
462 if (adapter != null) {
463 mBluetoothEnabled = adapter.isEnabled();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800464 } else {
465 mBluetoothEnabled = false;
466 }
467 mBluetoothA2dpState = BluetoothA2dp.STATE_DISCONNECTED;
468 mBluetoothHeadsetState = BluetoothHeadset.STATE_DISCONNECTED;
Jiafa Liu3f416732009-07-02 16:36:02 +0800469 mBluetoothPbapState = BluetoothPbap.STATE_DISCONNECTED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800470 mService.setIconVisibility(mBluetoothIcon, mBluetoothEnabled);
471
472 // Gps status
473 mGpsEnabledIconData = IconData.makeIcon("gps",
474 null, com.android.internal.R.drawable.stat_sys_gps_acquiring_anim, 0, 0);
475 mGpsFixIconData = IconData.makeIcon("gps",
476 null, com.android.internal.R.drawable.stat_sys_gps_on, 0, 0);
477 mGpsIcon = service.addIcon(mGpsEnabledIconData, null);
johnwang347c5a22009-08-24 22:11:11 -0700478 service.setIconVisibility(mGpsIcon, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800479
480 // Alarm clock
481 mAlarmClockIconData = IconData.makeIcon(
482 "alarm_clock",
483 null, com.android.internal.R.drawable.stat_notify_alarm, 0, 0);
484 mAlarmClockIcon = service.addIcon(mAlarmClockIconData, null);
485 service.setIconVisibility(mAlarmClockIcon, false);
486
487 // Sync state
488 mSyncActiveIcon = service.addIcon(IconData.makeIcon("sync_active",
489 null, R.drawable.stat_notify_sync_anim0, 0, 0), null);
490 mSyncFailingIcon = service.addIcon(IconData.makeIcon("sync_failing",
491 null, R.drawable.stat_notify_sync_error, 0, 0), null);
492 service.setIconVisibility(mSyncActiveIcon, false);
493 service.setIconVisibility(mSyncFailingIcon, false);
494
495 // volume
496 mVolumeData = IconData.makeIcon("volume",
497 null, com.android.internal.R.drawable.stat_sys_ringer_silent, 0, 0);
498 mVolumeIcon = service.addIcon(mVolumeData, null);
499 service.setIconVisibility(mVolumeIcon, false);
500 updateVolume();
johnwang347c5a22009-08-24 22:11:11 -0700501
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800502 IntentFilter filter = new IntentFilter();
503
504 // Register for Intent broadcasts for...
505 filter.addAction(Intent.ACTION_TIME_TICK);
506 filter.addAction(Intent.ACTION_TIME_CHANGED);
507 filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
508 filter.addAction(Intent.ACTION_BATTERY_CHANGED);
Mihai Predaa82842f2009-04-29 15:05:56 +0200509 filter.addAction(Intent.ACTION_BATTERY_LOW);
Dianne Hackborn8ec5b832009-07-01 21:19:35 -0700510 filter.addAction(Intent.ACTION_BATTERY_OKAY);
Mike Lockwood69eb0bf2009-08-01 23:02:28 -0400511 filter.addAction(Intent.ACTION_POWER_CONNECTED);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800512 filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
513 filter.addAction(Intent.ACTION_ALARM_CHANGED);
514 filter.addAction(Intent.ACTION_SYNC_STATE_CHANGED);
515 filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
516 filter.addAction(AudioManager.VIBRATE_SETTING_CHANGED_ACTION);
The Android Open Source Project10592532009-03-18 17:39:46 -0700517 filter.addAction(BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800518 filter.addAction(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION);
519 filter.addAction(BluetoothA2dp.SINK_STATE_CHANGED_ACTION);
Jiafa Liu3f416732009-07-02 16:36:02 +0800520 filter.addAction(BluetoothPbap.PBAP_STATE_CHANGED_ACTION);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800521 filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
522 filter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
523 filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
524 filter.addAction(WifiManager.RSSI_CHANGED_ACTION);
525 filter.addAction(GpsLocationProvider.GPS_ENABLED_CHANGE_ACTION);
526 filter.addAction(GpsLocationProvider.GPS_FIX_CHANGE_ACTION);
527 filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
Wink Saville04e71b32009-04-02 11:00:54 -0700528 filter.addAction(TtyIntent.TTY_ENABLED_CHANGE_ACTION);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800529 mContext.registerReceiver(mIntentReceiver, filter, null, mHandler);
530 }
531
532 public static void installIcons(Context context, StatusBarService service) {
533 sInstance = new StatusBarPolicy(context, service);
534 }
535
536 private final void updateClock() {
537 mCalendar.setTimeInMillis(System.currentTimeMillis());
538 mClockData.text = DateFormat.getTimeFormat(mContext)
539 .format(mCalendar.getTime());
540 mService.updateIcon(mClockIcon, mClockData, null);
541 }
542
543 private final void updateAlarm(Intent intent) {
544 boolean alarmSet = intent.getBooleanExtra("alarmSet", false);
545 mService.setIconVisibility(mAlarmClockIcon, alarmSet);
546 }
547
548 private final void updateSyncState(Intent intent) {
549 boolean isActive = intent.getBooleanExtra("active", false);
550 boolean isFailing = intent.getBooleanExtra("failing", false);
551 mService.setIconVisibility(mSyncActiveIcon, isActive);
552 // Don't display sync failing icon: BUG 1297963 Set sync error timeout to "never"
553 //mService.setIconVisibility(mSyncFailingIcon, isFailing && !isActive);
554 }
555
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800556 private final void updateBattery(Intent intent) {
557 mBatteryData.iconId = intent.getIntExtra("icon-small", 0);
558 mBatteryData.iconLevel = intent.getIntExtra("level", 0);
559 mService.updateIcon(mBatteryIcon, mBatteryData, null);
560
561 boolean plugged = intent.getIntExtra("plugged", 0) != 0;
562 int level = intent.getIntExtra("level", -1);
563 if (false) {
564 Log.d(TAG, "updateBattery level=" + level
565 + " plugged=" + plugged
566 + " mBatteryPlugged=" + mBatteryPlugged
567 + " mBatteryLevel=" + mBatteryLevel
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800568 + " mBatteryFirst=" + mBatteryFirst);
569 }
570
571 boolean oldPlugged = mBatteryPlugged;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800572
573 mBatteryPlugged = plugged;
574 mBatteryLevel = level;
575
576 if (mBatteryFirst) {
577 mBatteryFirst = false;
578 }
579 /*
580 * No longer showing the battery view because it draws attention away
581 * from the USB storage notification. We could still show it when
582 * connected to a brick, but that could lead to the user into thinking
583 * the device does not charge when plugged into USB (since he/she would
584 * not see the same battery screen on USB as he sees on brick).
585 */
586 /* else {
587 if (plugged && !oldPlugged) {
588 showBatteryView();
589 }
590 }
591 */
592 if (false) {
Mihai Predaa82842f2009-04-29 15:05:56 +0200593 Log.d(TAG, "plugged=" + plugged + " oldPlugged=" + oldPlugged + " level=" + level);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800594 }
Mihai Predaa82842f2009-04-29 15:05:56 +0200595 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800596
Mihai Predaa82842f2009-04-29 15:05:56 +0200597 private void onBatteryLow(Intent intent) {
598 if (SHOW_LOW_BATTERY_WARNING) {
599 if (false) {
600 Log.d(TAG, "mPhoneState=" + mPhoneState
601 + " mLowBatteryDialog=" + mLowBatteryDialog
602 + " mBatteryShowLowOnEndCall=" + mBatteryShowLowOnEndCall);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800603 }
Mihai Predaa82842f2009-04-29 15:05:56 +0200604
605 if (mPhoneState == TelephonyManager.CALL_STATE_IDLE) {
606 showLowBatteryWarning();
607 } else {
608 mBatteryShowLowOnEndCall = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800609 }
610 }
611 }
612
Dianne Hackborn8ec5b832009-07-01 21:19:35 -0700613 private void onBatteryOkay(Intent intent) {
614 if (mLowBatteryDialog != null
615 && SHOW_LOW_BATTERY_WARNING) {
616 mLowBatteryDialog.dismiss();
617 mBatteryShowLowOnEndCall = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800618 }
619 }
620
johnwang347c5a22009-08-24 22:11:11 -0700621 private void showBatteryView() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800622 closeLastBatteryView();
623 if (mLowBatteryDialog != null) {
624 mLowBatteryDialog.dismiss();
625 }
626
627 int level = mBatteryLevel;
628
629 View v = View.inflate(mContext, com.android.internal.R.layout.battery_status, null);
630 mBatteryView = v;
631 int pixelFormat = PixelFormat.TRANSLUCENT;
632 Drawable bg = v.getBackground();
633 if (bg != null) {
634 pixelFormat = bg.getOpacity();
635 }
636
637 WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
638 ViewGroup.LayoutParams.WRAP_CONTENT,
639 ViewGroup.LayoutParams.WRAP_CONTENT,
640 WindowManager.LayoutParams.TYPE_TOAST,
641 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
642 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
643 | WindowManager.LayoutParams.FLAG_BLUR_BEHIND
644 | WindowManager.LayoutParams.FLAG_DIM_BEHIND,
645 pixelFormat);
646
647 // Get the dim amount from the theme
648 TypedArray a = mContext.obtainStyledAttributes(
649 com.android.internal.R.styleable.Theme);
650 lp.dimAmount = a.getFloat(android.R.styleable.Theme_backgroundDimAmount, 0.5f);
651 a.recycle();
Wink Saville04e71b32009-04-02 11:00:54 -0700652
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800653 lp.setTitle("Battery");
654
655 TextView levelTextView = (TextView)v.findViewById(com.android.internal.R.id.level_percent);
656 levelTextView.setText(mContext.getString(
657 com.android.internal.R.string.battery_status_text_percent_format, level));
658
659 setBatteryLevel(v, com.android.internal.R.id.spacer, 100-level, 0, 0);
660 setBatteryLevel(v, com.android.internal.R.id.level, level,
661 com.android.internal.R.drawable.battery_charge_fill, level);
662
663 WindowManagerImpl.getDefault().addView(v, lp);
664
665 scheduleCloseBatteryView();
666 }
667
668 private void setBatteryLevel(View parent, int id, int height, int background, int level) {
669 ImageView v = (ImageView)parent.findViewById(id);
670 LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)v.getLayoutParams();
671 lp.weight = height;
672 if (background != 0) {
673 v.setBackgroundResource(background);
674 Drawable bkg = v.getBackground();
675 bkg.setLevel(level);
676 }
677 }
678
679 private void showLowBatteryWarning() {
680 closeLastBatteryView();
681
Mihai Predaa82842f2009-04-29 15:05:56 +0200682 /* Show exact battery level.
683 * Add 1 because the text says "less than X%".
684 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800685 CharSequence levelText = mContext.getString(
Mihai Predaa82842f2009-04-29 15:05:56 +0200686 com.android.internal.R.string.battery_low_percent_format, mBatteryLevel + 1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800687
688 if (mBatteryLevelTextView != null) {
689 mBatteryLevelTextView.setText(levelText);
690 } else {
691 View v = View.inflate(mContext, com.android.internal.R.layout.battery_low, null);
692 mBatteryLevelTextView=(TextView)v.findViewById(com.android.internal.R.id.level_percent);
693
694 mBatteryLevelTextView.setText(levelText);
695
696 AlertDialog.Builder b = new AlertDialog.Builder(mContext);
697 b.setCancelable(true);
698 b.setTitle(com.android.internal.R.string.battery_low_title);
699 b.setView(v);
700 b.setIcon(android.R.drawable.ic_dialog_alert);
701 b.setPositiveButton(android.R.string.ok, null);
johnwang347c5a22009-08-24 22:11:11 -0700702
Dianne Hackborn3d74bb42009-06-19 10:35:21 -0700703 final Intent intent = new Intent(Intent.ACTION_POWER_USAGE_SUMMARY);
704 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
705 | Intent.FLAG_ACTIVITY_MULTIPLE_TASK
706 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
707 | Intent.FLAG_ACTIVITY_NO_HISTORY);
708 if (intent.resolveActivity(mContext.getPackageManager()) != null) {
709 b.setNegativeButton(com.android.internal.R.string.battery_low_why,
710 new DialogInterface.OnClickListener() {
711 public void onClick(DialogInterface dialog, int which) {
712 mContext.startActivity(intent);
713 if (mLowBatteryDialog != null) {
714 mLowBatteryDialog.dismiss();
715 }
716 }
717 });
718 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800719
720 AlertDialog d = b.create();
721 d.setOnDismissListener(mLowBatteryListener);
722 d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
723 d.show();
724 mLowBatteryDialog = d;
725 }
726 }
727
728 private final void updateCallState(int state) {
729 mPhoneState = state;
730 if (false) {
731 Log.d(TAG, "mPhoneState=" + mPhoneState
732 + " mLowBatteryDialog=" + mLowBatteryDialog
733 + " mBatteryShowLowOnEndCall=" + mBatteryShowLowOnEndCall);
734 }
735 if (mPhoneState == TelephonyManager.CALL_STATE_IDLE) {
736 if (mBatteryShowLowOnEndCall) {
737 if (!mBatteryPlugged) {
738 showLowBatteryWarning();
739 }
740 mBatteryShowLowOnEndCall = false;
741 }
742 } else {
743 if (mLowBatteryDialog != null) {
744 mLowBatteryDialog.dismiss();
745 mBatteryShowLowOnEndCall = true;
746 }
747 }
748 }
749
750 private DialogInterface.OnDismissListener mLowBatteryListener
751 = new DialogInterface.OnDismissListener() {
752 public void onDismiss(DialogInterface dialog) {
753 mLowBatteryDialog = null;
754 mBatteryLevelTextView = null;
755 }
756 };
757
758 private void scheduleCloseBatteryView() {
759 Message m = mHandler.obtainMessage(EVENT_BATTERY_CLOSE);
760 m.arg1 = (++mBatteryViewSequence);
761 mHandler.sendMessageDelayed(m, 3000);
762 }
763
764 private void closeLastBatteryView() {
765 if (mBatteryView != null) {
766 //mBatteryView.debug();
767 WindowManagerImpl.getDefault().removeView(mBatteryView);
768 mBatteryView = null;
769 }
770 }
771
772 private PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
773 @Override
Wink Savillee9b06d72009-05-18 21:47:50 -0700774 public void onSignalStrengthsChanged(SignalStrength signalStrength) {
775 mSignalStrength = signalStrength;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800776 updateSignalStrength();
777 }
778
779 @Override
780 public void onServiceStateChanged(ServiceState state) {
781 mServiceState = state;
782 updateSignalStrength();
Wink Savillee9b06d72009-05-18 21:47:50 -0700783 updateCdmaRoamingIcon();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800784 updateDataIcon();
785 }
786
787 @Override
788 public void onCallStateChanged(int state, String incomingNumber) {
789 updateCallState(state);
johnwang347c5a22009-08-24 22:11:11 -0700790 // In cdma, if a voice call is made, RSSI should switch to 1x.
791 if (isCdma()) {
792 updateSignalStrength();
793 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800794 }
795
796 @Override
797 public void onDataConnectionStateChanged(int state) {
798 mDataState = state;
799 updateDataNetType();
800 updateDataIcon();
801 }
802
803 @Override
804 public void onDataActivity(int direction) {
805 mDataActivity = direction;
806 updateDataIcon();
807 }
808 };
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800809
810 private final void updateSimState(Intent intent) {
Wink Saville04e71b32009-04-02 11:00:54 -0700811 String stateExtra = intent.getStringExtra(IccCard.INTENT_KEY_ICC_STATE);
812 if (IccCard.INTENT_VALUE_ICC_ABSENT.equals(stateExtra)) {
813 mSimState = IccCard.State.ABSENT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800814 }
Wink Saville04e71b32009-04-02 11:00:54 -0700815 else if (IccCard.INTENT_VALUE_ICC_READY.equals(stateExtra)) {
816 mSimState = IccCard.State.READY;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800817 }
Wink Saville04e71b32009-04-02 11:00:54 -0700818 else if (IccCard.INTENT_VALUE_ICC_LOCKED.equals(stateExtra)) {
819 final String lockedReason = intent.getStringExtra(IccCard.INTENT_KEY_LOCKED_REASON);
820 if (IccCard.INTENT_VALUE_LOCKED_ON_PIN.equals(lockedReason)) {
821 mSimState = IccCard.State.PIN_REQUIRED;
johnwang347c5a22009-08-24 22:11:11 -0700822 }
Wink Saville04e71b32009-04-02 11:00:54 -0700823 else if (IccCard.INTENT_VALUE_LOCKED_ON_PUK.equals(lockedReason)) {
824 mSimState = IccCard.State.PUK_REQUIRED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800825 }
826 else {
Wink Saville04e71b32009-04-02 11:00:54 -0700827 mSimState = IccCard.State.NETWORK_LOCKED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800828 }
829 } else {
Wink Saville04e71b32009-04-02 11:00:54 -0700830 mSimState = IccCard.State.UNKNOWN;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800831 }
832 updateDataIcon();
833 }
834
Wink Savillee9b06d72009-05-18 21:47:50 -0700835 private boolean isCdma() {
Wink Savillef3152382009-06-01 14:39:20 -0700836 return ((mPhone != null) && (mPhone.getPhoneType() == TelephonyManager.PHONE_TYPE_CDMA));
Wink Savillee9b06d72009-05-18 21:47:50 -0700837 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800838
johnwang347c5a22009-08-24 22:11:11 -0700839 private boolean isEvdo() {
840 return ( (mServiceState != null)
841 && ((mServiceState.getRadioTechnology()
842 == ServiceState.RADIO_TECHNOLOGY_EVDO_0)
843 || (mServiceState.getRadioTechnology()
844 == ServiceState.RADIO_TECHNOLOGY_EVDO_A)));
845 }
846
Wink Savillee9b06d72009-05-18 21:47:50 -0700847 private boolean hasService() {
848 if (mServiceState != null) {
849 switch (mServiceState.getState()) {
850 case ServiceState.STATE_OUT_OF_SERVICE:
851 case ServiceState.STATE_POWER_OFF:
852 return false;
853 default:
854 return true;
855 }
856 } else {
857 return false;
858 }
859 }
860
861 private final void updateSignalStrength() {
862 int iconLevel = -1;
Wink Savillee9b06d72009-05-18 21:47:50 -0700863 int[] iconList;
Wink Savillee9b06d72009-05-18 21:47:50 -0700864
865 if (!hasService()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800866 //Log.d(TAG, "updateSignalStrength: no service");
867 if (Settings.System.getInt(mContext.getContentResolver(),
868 Settings.System.AIRPLANE_MODE_ON, 0) == 1) {
869 mPhoneData.iconId = com.android.internal.R.drawable.stat_sys_signal_flightmode;
870 } else {
871 mPhoneData.iconId = com.android.internal.R.drawable.stat_sys_signal_null;
872 }
873 mService.updateIcon(mPhoneIcon, mPhoneData, null);
874 return;
875 }
876
Wink Savillee9b06d72009-05-18 21:47:50 -0700877 if (!isCdma()) {
878 int asu = mSignalStrength.getGsmSignalStrength();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800879
Wink Savillee9b06d72009-05-18 21:47:50 -0700880 // ASU ranges from 0 to 31 - TS 27.007 Sec 8.5
881 // asu = 0 (-113dB or less) is very weak
882 // signal, its better to show 0 bars to the user in such cases.
883 // asu = 99 is a special case, where the signal strength is unknown.
884 if (asu <= 0 || asu == 99) iconLevel = 0;
885 else if (asu >= 16) iconLevel = 4;
886 else if (asu >= 8) iconLevel = 3;
887 else if (asu >= 4) iconLevel = 2;
888 else iconLevel = 1;
889
890 if (mPhone.isNetworkRoaming()) {
891 iconList = sSignalImages_r;
892 } else {
893 iconList = sSignalImages;
Wink Saville04e71b32009-04-02 11:00:54 -0700894 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800895 } else {
johnwang347c5a22009-08-24 22:11:11 -0700896 iconList = this.sSignalImages;
Wink Savillee9b06d72009-05-18 21:47:50 -0700897
johnwang347c5a22009-08-24 22:11:11 -0700898 // If 3G(EV) and 1x network are available than 3G should be
899 // displayed, displayed RSSI should be from the EV side.
900 // If a voice call is made then RSSI should switch to 1x.
901 if ((mPhoneState == TelephonyManager.CALL_STATE_IDLE) && isEvdo()){
902 iconLevel = getEvdoLevel();
903 if (false) {
904 Log.d(TAG, "use Evdo level=" + iconLevel + " to replace Cdma Level=" + getCdmaLevel());
905 }
906 } else {
907 iconLevel = getCdmaLevel();
908 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800909 }
Wink Savillee9b06d72009-05-18 21:47:50 -0700910 mPhoneData.iconId = iconList[iconLevel];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800911 mService.updateIcon(mPhoneIcon, mPhoneData, null);
912 }
913
johnwang347c5a22009-08-24 22:11:11 -0700914 private int getCdmaLevel() {
915 final int cdmaDbm = mSignalStrength.getCdmaDbm();
916 final int cdmaEcio = mSignalStrength.getCdmaEcio();
917 int levelDbm = 0;
918 int levelEcio = 0;
919
920 if (cdmaDbm >= -75) levelDbm = 4;
921 else if (cdmaDbm >= -85) levelDbm = 3;
922 else if (cdmaDbm >= -95) levelDbm = 2;
923 else if (cdmaDbm >= -100) levelDbm = 1;
924 else levelDbm = 0;
925
926 // Ec/Io are in dB*10
927 if (cdmaEcio >= -90) levelEcio = 4;
928 else if (cdmaEcio >= -110) levelEcio = 3;
929 else if (cdmaEcio >= -130) levelEcio = 2;
930 else if (cdmaEcio >= -150) levelEcio = 1;
931 else levelEcio = 0;
932
933 return (levelDbm < levelEcio) ? levelDbm : levelEcio;
934 }
935
936 private int getEvdoLevel() {
937 int evdoDbm = mSignalStrength.getEvdoDbm();
938 int evdoSnr = mSignalStrength.getEvdoSnr();
939 int levelEvdoDbm = 0;
940 int levelEvdoSnr = 0;
941
942 if (evdoDbm >= -65) levelEvdoDbm = 4;
943 else if (evdoDbm >= -75) levelEvdoDbm = 3;
944 else if (evdoDbm >= -90) levelEvdoDbm = 2;
945 else if (evdoDbm >= -105) levelEvdoDbm = 1;
946 else levelEvdoDbm = 0;
947
948 if (evdoSnr > 7) levelEvdoSnr = 4;
949 else if (evdoSnr > 5) levelEvdoSnr = 3;
950 else if (evdoSnr > 3) levelEvdoSnr = 2;
951 else if (evdoSnr > 1) levelEvdoSnr = 1;
952 else levelEvdoSnr = 0;
953
954 return (levelEvdoDbm < levelEvdoSnr) ? levelEvdoDbm : levelEvdoSnr;
955 }
956
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800957 private final void updateDataNetType() {
Wink Saville04e71b32009-04-02 11:00:54 -0700958 int net = mPhone.getNetworkType();
Wink Saville04e71b32009-04-02 11:00:54 -0700959
960 switch (net) {
Wink Saville04e71b32009-04-02 11:00:54 -0700961 case TelephonyManager.NETWORK_TYPE_EDGE:
962 mDataIconList = sDataNetType_e;
963 break;
964 case TelephonyManager.NETWORK_TYPE_UMTS:
965 mDataIconList = sDataNetType_3g;
966 break;
Li Zheebe66342009-08-14 19:22:16 +0800967 case TelephonyManager.NETWORK_TYPE_HSDPA:
968 case TelephonyManager.NETWORK_TYPE_HSUPA:
969 case TelephonyManager.NETWORK_TYPE_HSPA:
970 mDataIconList = sDataNetType_h;
971 break;
Wink Saville04e71b32009-04-02 11:00:54 -0700972 case TelephonyManager.NETWORK_TYPE_CDMA:
973 // display 1xRTT for IS95A/B
974 mDataIconList = this.sDataNetType_1xrtt;
975 break;
976 case TelephonyManager.NETWORK_TYPE_1xRTT:
977 mDataIconList = this.sDataNetType_1xrtt;
978 break;
979 case TelephonyManager.NETWORK_TYPE_EVDO_0: //fall through
980 case TelephonyManager.NETWORK_TYPE_EVDO_A:
981 mDataIconList = sDataNetType_evdo;
982 break;
983 default:
984 mDataIconList = sDataNetType_g;
985 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800986 }
987 }
988
989 private final void updateDataIcon() {
990 int iconId;
991 boolean visible = true;
992
Wink Savillee9b06d72009-05-18 21:47:50 -0700993 if (!isCdma()) {
994 // GSM case, we have to check also the sim state
995 if (mSimState == IccCard.State.READY || mSimState == IccCard.State.UNKNOWN) {
996 if (hasService() && mDataState == TelephonyManager.DATA_CONNECTED) {
997 switch (mDataActivity) {
998 case TelephonyManager.DATA_ACTIVITY_IN:
999 iconId = mDataIconList[1];
1000 break;
1001 case TelephonyManager.DATA_ACTIVITY_OUT:
1002 iconId = mDataIconList[2];
1003 break;
1004 case TelephonyManager.DATA_ACTIVITY_INOUT:
1005 iconId = mDataIconList[3];
1006 break;
1007 default:
1008 iconId = mDataIconList[0];
1009 break;
1010 }
1011 mDataData.iconId = iconId;
1012 mService.updateIcon(mDataIcon, mDataData, null);
1013 } else {
1014 visible = false;
1015 }
1016 } else {
1017 mDataData.iconId = com.android.internal.R.drawable.stat_sys_no_sim;
1018 mService.updateIcon(mDataIcon, mDataData, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001019 }
Wink Savillee9b06d72009-05-18 21:47:50 -07001020 } else {
1021 // CDMA case, mDataActivity can be also DATA_ACTIVITY_DORMANT
1022 if (hasService() && mDataState == TelephonyManager.DATA_CONNECTED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001023 switch (mDataActivity) {
1024 case TelephonyManager.DATA_ACTIVITY_IN:
Wink Savillee9b06d72009-05-18 21:47:50 -07001025 iconId = mDataIconList[1];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001026 break;
1027 case TelephonyManager.DATA_ACTIVITY_OUT:
Wink Savillee9b06d72009-05-18 21:47:50 -07001028 iconId = mDataIconList[2];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001029 break;
1030 case TelephonyManager.DATA_ACTIVITY_INOUT:
Wink Savillee9b06d72009-05-18 21:47:50 -07001031 iconId = mDataIconList[3];
1032 break;
1033 case TelephonyManager.DATA_ACTIVITY_DORMANT:
1034 iconId = mDataIconList[4];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001035 break;
1036 default:
Wink Savillee9b06d72009-05-18 21:47:50 -07001037 iconId = mDataIconList[0];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001038 break;
1039 }
1040 mDataData.iconId = iconId;
1041 mService.updateIcon(mDataIcon, mDataData, null);
1042 } else {
1043 visible = false;
1044 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001045 }
Wink Savillee9b06d72009-05-18 21:47:50 -07001046
Dianne Hackborn4840e142009-03-24 22:40:29 -07001047 long ident = Binder.clearCallingIdentity();
1048 try {
Wink Saville04e71b32009-04-02 11:00:54 -07001049 mBatteryStats.notePhoneDataConnectionState(mPhone.getNetworkType(), visible);
Dianne Hackborn4840e142009-03-24 22:40:29 -07001050 } catch (RemoteException e) {
1051 } finally {
1052 Binder.restoreCallingIdentity(ident);
1053 }
Wink Savillee9b06d72009-05-18 21:47:50 -07001054
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001055 if (mDataIconVisible != visible) {
1056 mService.setIconVisibility(mDataIcon, visible);
1057 mDataIconVisible = visible;
1058 }
1059 }
1060
1061 private final void updateVolume() {
1062 AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
1063 final int ringerMode = audioManager.getRingerMode();
1064 final boolean visible = ringerMode == AudioManager.RINGER_MODE_SILENT ||
Wink Savillee9b06d72009-05-18 21:47:50 -07001065 ringerMode == AudioManager.RINGER_MODE_VIBRATE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001066 final int iconId = audioManager.shouldVibrate(AudioManager.VIBRATE_TYPE_RINGER)
1067 ? com.android.internal.R.drawable.stat_sys_ringer_vibrate
1068 : com.android.internal.R.drawable.stat_sys_ringer_silent;
1069
1070 if (visible) {
1071 mVolumeData.iconId = iconId;
1072 mService.updateIcon(mVolumeIcon, mVolumeData, null);
1073 }
1074 if (visible != mVolumeVisible) {
1075 mService.setIconVisibility(mVolumeIcon, visible);
1076 mVolumeVisible = visible;
1077 }
1078 }
1079
1080 private final void updateBluetooth(Intent intent) {
1081 int iconId = com.android.internal.R.drawable.stat_sys_data_bluetooth;
1082
1083 String action = intent.getAction();
The Android Open Source Project10592532009-03-18 17:39:46 -07001084 if (action.equals(BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION)) {
1085 int state = intent.getIntExtra(BluetoothIntent.BLUETOOTH_STATE,
1086 BluetoothError.ERROR);
Nick Pellybd022f42009-08-14 18:33:38 -07001087 mBluetoothEnabled = state == BluetoothAdapter.BLUETOOTH_STATE_ON;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001088 } else if (action.equals(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION)) {
1089 mBluetoothHeadsetState = intent.getIntExtra(BluetoothIntent.HEADSET_STATE,
1090 BluetoothHeadset.STATE_ERROR);
1091 } else if (action.equals(BluetoothA2dp.SINK_STATE_CHANGED_ACTION)) {
1092 mBluetoothA2dpState = intent.getIntExtra(BluetoothA2dp.SINK_STATE,
1093 BluetoothA2dp.STATE_DISCONNECTED);
Jiafa Liu3f416732009-07-02 16:36:02 +08001094 } else if (action.equals(BluetoothPbap.PBAP_STATE_CHANGED_ACTION)) {
1095 mBluetoothPbapState = intent.getIntExtra(BluetoothPbap.PBAP_STATE,
1096 BluetoothPbap.STATE_DISCONNECTED);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001097 } else {
1098 return;
1099 }
Wink Savillee9b06d72009-05-18 21:47:50 -07001100
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001101 if (mBluetoothHeadsetState == BluetoothHeadset.STATE_CONNECTED ||
1102 mBluetoothA2dpState == BluetoothA2dp.STATE_CONNECTED ||
Jiafa Liu3f416732009-07-02 16:36:02 +08001103 mBluetoothA2dpState == BluetoothA2dp.STATE_PLAYING ||
1104 mBluetoothPbapState == BluetoothPbap.STATE_CONNECTED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001105 iconId = com.android.internal.R.drawable.stat_sys_data_bluetooth_connected;
1106 }
1107
1108 mBluetoothData.iconId = iconId;
1109 mService.updateIcon(mBluetoothIcon, mBluetoothData, null);
1110 mService.setIconVisibility(mBluetoothIcon, mBluetoothEnabled);
1111 }
1112
1113 private final void updateWifi(Intent intent) {
1114 final String action = intent.getAction();
1115 if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
Wink Savillee9b06d72009-05-18 21:47:50 -07001116
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001117 final boolean enabled = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
1118 WifiManager.WIFI_STATE_UNKNOWN) == WifiManager.WIFI_STATE_ENABLED;
Wink Savillee9b06d72009-05-18 21:47:50 -07001119
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001120 if (!enabled) {
1121 // If disabled, hide the icon. (We show icon when connected.)
1122 mService.setIconVisibility(mWifiIcon, false);
1123 }
Wink Savillee9b06d72009-05-18 21:47:50 -07001124
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001125 } else if (action.equals(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION)) {
1126 final boolean enabled = intent.getBooleanExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED,
1127 false);
1128 if (!enabled) {
1129 mService.setIconVisibility(mWifiIcon, false);
1130 }
1131 } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
1132
Wink Savillee9b06d72009-05-18 21:47:50 -07001133 final NetworkInfo networkInfo = (NetworkInfo)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001134 intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
Wink Savillee9b06d72009-05-18 21:47:50 -07001135
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001136 int iconId;
1137 if (networkInfo != null && networkInfo.isConnected()) {
1138 mIsWifiConnected = true;
1139 if (mLastWifiSignalLevel == -1) {
1140 iconId = sWifiSignalImages[0];
1141 } else {
1142 iconId = sWifiSignalImages[mLastWifiSignalLevel];
1143 }
Wink Saville04e71b32009-04-02 11:00:54 -07001144
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001145 // Show the icon since wi-fi is connected
1146 mService.setIconVisibility(mWifiIcon, true);
Wink Saville04e71b32009-04-02 11:00:54 -07001147
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001148 } else {
1149 mLastWifiSignalLevel = -1;
1150 mIsWifiConnected = false;
1151 iconId = sWifiSignalImages[0];
1152
1153 // Hide the icon since we're not connected
1154 mService.setIconVisibility(mWifiIcon, false);
1155 }
1156
1157 mWifiData.iconId = iconId;
1158 mService.updateIcon(mWifiIcon, mWifiData, null);
1159 } else if (action.equals(WifiManager.RSSI_CHANGED_ACTION)) {
1160 final int newRssi = intent.getIntExtra(WifiManager.EXTRA_NEW_RSSI, -200);
1161 int newSignalLevel = WifiManager.calculateSignalLevel(newRssi,
1162 sWifiSignalImages.length);
1163 if (newSignalLevel != mLastWifiSignalLevel) {
1164 mLastWifiSignalLevel = newSignalLevel;
1165 if (mIsWifiConnected) {
1166 mWifiData.iconId = sWifiSignalImages[newSignalLevel];
1167 } else {
1168 mWifiData.iconId = sWifiTemporarilyNotConnectedImage;
1169 }
1170 mService.updateIcon(mWifiIcon, mWifiData, null);
1171 }
1172 }
1173 }
1174
1175 private final void updateGps(Intent intent) {
1176 final String action = intent.getAction();
1177 final boolean enabled = intent.getBooleanExtra(GpsLocationProvider.EXTRA_ENABLED, false);
1178
1179 if (action.equals(GpsLocationProvider.GPS_FIX_CHANGE_ACTION) && enabled) {
1180 // GPS is getting fixes
1181 mService.updateIcon(mGpsIcon, mGpsFixIconData, null);
Wink Savillee9b06d72009-05-18 21:47:50 -07001182 mService.setIconVisibility(mGpsIcon, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001183 } else if (action.equals(GpsLocationProvider.GPS_ENABLED_CHANGE_ACTION) && !enabled) {
1184 // GPS is off
Wink Savillee9b06d72009-05-18 21:47:50 -07001185 mService.setIconVisibility(mGpsIcon, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001186 } else {
1187 // GPS is on, but not receiving fixes
1188 mService.updateIcon(mGpsIcon, mGpsEnabledIconData, null);
Wink Savillee9b06d72009-05-18 21:47:50 -07001189 mService.setIconVisibility(mGpsIcon, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001190 }
1191 }
1192
Wink Savillee9b06d72009-05-18 21:47:50 -07001193 private final void updateTTY(Intent intent) {
Wink Saville04e71b32009-04-02 11:00:54 -07001194 final String action = intent.getAction();
1195 final boolean enabled = intent.getBooleanExtra(TtyIntent.TTY_ENABLED, false);
1196
1197 Log.i(TAG, "updateTTY: enabled: " + enabled);
1198
1199 if (enabled) {
1200 // TTY is on
1201 Log.i(TAG, "updateTTY: set TTY on");
1202 mService.updateIcon(mTTYModeIcon, mTTYModeEnableIconData, null);
Wink Savillee9b06d72009-05-18 21:47:50 -07001203 mService.setIconVisibility(mTTYModeIcon, true);
Wink Saville04e71b32009-04-02 11:00:54 -07001204 } else {
1205 // TTY is off
1206 Log.i(TAG, "updateTTY: set TTY off");
Wink Savillee9b06d72009-05-18 21:47:50 -07001207 mService.setIconVisibility(mTTYModeIcon, false);
Wink Saville04e71b32009-04-02 11:00:54 -07001208 }
1209 }
1210
Wink Savillee9b06d72009-05-18 21:47:50 -07001211 private final void updateCdmaRoamingIcon() {
1212 if (!hasService()) {
1213 mService.setIconVisibility(mCdmaRoamingIndicatorIcon, false);
Wink Savillef3152382009-06-01 14:39:20 -07001214 return;
Wink Savillee9b06d72009-05-18 21:47:50 -07001215 }
1216
1217 if (!isCdma()) {
1218 mService.setIconVisibility(mCdmaRoamingIndicatorIcon, false);
Wink Savillef3152382009-06-01 14:39:20 -07001219 return;
Wink Savillee9b06d72009-05-18 21:47:50 -07001220 }
1221
1222 int[] iconList = sRoamingIndicatorImages_cdma;
1223 int iconIndex = mPhone.getCdmaEriIconIndex();
1224 int iconMode = mPhone.getCdmaEriIconMode();
1225
1226 if (iconIndex == -1) {
1227 Log.e(TAG, "getCdmaEriIconIndex returned null, skipping ERI icon update");
1228 return;
1229 }
1230
1231 if (iconMode == -1) {
1232 Log.e(TAG, "getCdmeEriIconMode returned null, skipping ERI icon update");
1233 return;
1234 }
1235
1236 if (iconIndex == EriInfo.ROAMING_INDICATOR_OFF) {
1237 Log.d(TAG, "Cdma ROAMING_INDICATOR_OFF, removing ERI icon");
1238 mService.setIconVisibility(mCdmaRoamingIndicatorIcon, false);
1239 return;
1240 }
1241
1242 switch (iconMode) {
1243 case EriInfo.ROAMING_ICON_MODE_NORMAL:
1244 mCdmaRoamingIndicatorIconData.iconId = iconList[iconIndex];
1245 mService.updateIcon(mCdmaRoamingIndicatorIcon, mCdmaRoamingIndicatorIconData, null);
1246 mService.setIconVisibility(mCdmaRoamingIndicatorIcon, true);
1247 break;
1248 case EriInfo.ROAMING_ICON_MODE_FLASH:
Wink Savillef3152382009-06-01 14:39:20 -07001249 mCdmaRoamingIndicatorIconData.iconId =
1250 com.android.internal.R.drawable.stat_sys_roaming_cdma_flash;
Wink Savillee9b06d72009-05-18 21:47:50 -07001251 mService.updateIcon(mCdmaRoamingIndicatorIcon, mCdmaRoamingIndicatorIconData, null);
Wink Savillef3152382009-06-01 14:39:20 -07001252 mService.setIconVisibility(mCdmaRoamingIndicatorIcon, true);
Wink Savillee9b06d72009-05-18 21:47:50 -07001253 break;
1254
1255 }
1256 mService.updateIcon(mPhoneIcon, mPhoneData, null);
1257 }
1258
1259
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001260 private class StatusBarHandler extends Handler {
1261 @Override
1262 public void handleMessage(Message msg) {
1263 switch (msg.what) {
1264 case EVENT_BATTERY_CLOSE:
1265 if (msg.arg1 == mBatteryViewSequence) {
1266 closeLastBatteryView();
1267 }
1268 break;
1269 }
1270 }
1271 }
1272}