StatusBarPolicy.java revision 3dec7d563a2f3e1eb967ce2054a00b6620e3558c
1/* 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 19import com.android.internal.R; 20import com.android.internal.location.GpsLocationProvider; 21import com.android.internal.telephony.SimCard; 22import com.android.internal.telephony.TelephonyIntents; 23 24import android.app.AlertDialog; 25import android.bluetooth.BluetoothA2dp; 26import android.bluetooth.BluetoothDevice; 27import android.bluetooth.BluetoothHeadset; 28import android.bluetooth.BluetoothIntent; 29import android.content.BroadcastReceiver; 30import android.content.Context; 31import android.content.DialogInterface; 32import android.content.Intent; 33import android.content.IntentFilter; 34import android.content.res.TypedArray; 35import android.graphics.PixelFormat; 36import android.graphics.drawable.Drawable; 37import android.media.AudioManager; 38import android.net.NetworkInfo; 39import android.net.wifi.WifiManager; 40import android.os.Handler; 41import android.os.IBinder; 42import android.os.Message; 43import android.provider.Settings; 44import android.telephony.PhoneStateListener; 45import android.telephony.ServiceState; 46import 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 57import java.util.Calendar; 58import java.util.TimeZone; 59 60/** 61 * This class contains all of the policy about which icons are installed in the status 62 * bar at boot time. In reality, it should go into the android.policy package, but 63 * putting it here is the first step from extracting it. 64 */ 65public class StatusBarPolicy { 66 private static final String TAG = "StatusBarPolicy"; 67 68 private static StatusBarPolicy sInstance; 69 70 // message codes for the handler 71 private static final int EVENT_DATA_CONN_STATE_CHANGED = 2; 72 private static final int EVENT_DATA_ACTIVITY = 3; 73 private static final int EVENT_BATTERY_CLOSE = 4; 74 75 private Context mContext; 76 private StatusBarService mService; 77 private Handler mHandler = new StatusBarHandler(); 78 79 // clock 80 private Calendar mCalendar; 81 private IBinder mClockIcon; 82 private IconData mClockData; 83 84 // battery 85 private IBinder mBatteryIcon; 86 private IconData mBatteryData; 87 private boolean mBatteryFirst = true; 88 private boolean mBatteryPlugged; 89 private int mBatteryLevel; 90 private int mBatteryThreshold = 0; // index into mBatteryThresholds 91 private int[] mBatteryThresholds = new int[] { 15, -1 }; 92 private AlertDialog mLowBatteryDialog; 93 private TextView mBatteryLevelTextView; 94 private View mBatteryView; 95 private int mBatteryViewSequence; 96 private boolean mBatteryShowLowOnEndCall = false; 97 private static final boolean SHOW_LOW_BATTERY_WARNING = true; 98 99 // phone 100 private TelephonyManager mPhone; 101 private IBinder mPhoneIcon; 102 private IconData mPhoneData; 103 private static final int[] sSignalImages = new int[] { 104 com.android.internal.R.drawable.stat_sys_signal_0, 105 com.android.internal.R.drawable.stat_sys_signal_1, 106 com.android.internal.R.drawable.stat_sys_signal_2, 107 com.android.internal.R.drawable.stat_sys_signal_3, 108 com.android.internal.R.drawable.stat_sys_signal_4 109 }; 110 private static final int[] sSignalImages_r = new int[] { 111 com.android.internal.R.drawable.stat_sys_r_signal_0, 112 com.android.internal.R.drawable.stat_sys_r_signal_1, 113 com.android.internal.R.drawable.stat_sys_r_signal_2, 114 com.android.internal.R.drawable.stat_sys_r_signal_3, 115 com.android.internal.R.drawable.stat_sys_r_signal_4 116 }; 117 private int[] mDataIconList = sDataNetType_g; 118 private static final int[] sDataNetType_g = new int[] { 119 com.android.internal.R.drawable.stat_sys_data_connected_g, 120 com.android.internal.R.drawable.stat_sys_data_in_g, 121 com.android.internal.R.drawable.stat_sys_data_out_g, 122 com.android.internal.R.drawable.stat_sys_data_inandout_g, 123 }; 124 private static final int[] sDataNetType_3g = new int[] { 125 com.android.internal.R.drawable.stat_sys_data_connected_3g, 126 com.android.internal.R.drawable.stat_sys_data_in_3g, 127 com.android.internal.R.drawable.stat_sys_data_out_3g, 128 com.android.internal.R.drawable.stat_sys_data_inandout_3g, 129 }; 130 private static final int[] sDataNetType_e = new int[] { 131 com.android.internal.R.drawable.stat_sys_data_connected_e, 132 com.android.internal.R.drawable.stat_sys_data_in_e, 133 com.android.internal.R.drawable.stat_sys_data_out_e, 134 com.android.internal.R.drawable.stat_sys_data_inandout_e, 135 }; 136 // Assume it's all good unless we hear otherwise. We don't always seem 137 // to get broadcasts that it *is* there. 138 SimCard.State mSimState = SimCard.State.READY; 139 int mPhoneState = TelephonyManager.CALL_STATE_IDLE; 140 int mDataState = TelephonyManager.DATA_DISCONNECTED; 141 int mDataActivity = TelephonyManager.DATA_ACTIVITY_NONE; 142 ServiceState mServiceState; 143 int mSignalAsu = -1; 144 145 // data connection 146 private IBinder mDataIcon; 147 private IconData mDataData; 148 private boolean mDataIconVisible; 149 150 // ringer volume 151 private IBinder mVolumeIcon; 152 private IconData mVolumeData; 153 private boolean mVolumeVisible; 154 155 // bluetooth device status 156 private IBinder mBluetoothIcon; 157 private IconData mBluetoothData; 158 private int mBluetoothHeadsetState; 159 private int mBluetoothA2dpState; 160 private boolean mBluetoothEnabled; 161 162 // wifi 163 private static final int[] sWifiSignalImages = new int[] { 164 com.android.internal.R.drawable.stat_sys_wifi_signal_1, 165 com.android.internal.R.drawable.stat_sys_wifi_signal_2, 166 com.android.internal.R.drawable.stat_sys_wifi_signal_3, 167 com.android.internal.R.drawable.stat_sys_wifi_signal_4, 168 }; 169 private static final int sWifiTemporarilyNotConnectedImage = 170 com.android.internal.R.drawable.stat_sys_wifi_signal_0; 171 172 private int mLastWifiSignalLevel = -1; 173 private boolean mIsWifiConnected = false; 174 private IBinder mWifiIcon; 175 private IconData mWifiData; 176 177 // gps 178 private IBinder mGpsIcon; 179 private IconData mGpsEnabledIconData; 180 private IconData mGpsFixIconData; 181 182 // alarm clock 183 // Icon lit when clock is set 184 private IBinder mAlarmClockIcon; 185 private IconData mAlarmClockIconData; 186 187 // sync state 188 // If sync is active the SyncActive icon is displayed. If sync is not active but 189 // sync is failing the SyncFailing icon is displayed. Otherwise neither are displayed. 190 private IBinder mSyncActiveIcon; 191 private IBinder mSyncFailingIcon; 192 193 private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { 194 @Override 195 public void onReceive(Context context, Intent intent) { 196 String action = intent.getAction(); 197 if (action.equals(Intent.ACTION_TIME_TICK)) { 198 updateClock(); 199 } 200 else if (action.equals(Intent.ACTION_TIME_CHANGED)) { 201 updateClock(); 202 } 203 else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) { 204 updateClock(); 205 } 206 else if (action.equals(Intent.ACTION_TIMEZONE_CHANGED)) { 207 String tz = intent.getStringExtra("time-zone"); 208 mCalendar = Calendar.getInstance(TimeZone.getTimeZone(tz)); 209 updateClock(); 210 } 211 else if (action.equals(Intent.ACTION_ALARM_CHANGED)) { 212 updateAlarm(intent); 213 } 214 else if (action.equals(Intent.ACTION_SYNC_STATE_CHANGED)) { 215 updateSyncState(intent); 216 } 217 else if (action.equals(Intent.ACTION_BATTERY_CHANGED)) { 218 updateBattery(intent); 219 } 220 else if (action.equals(BluetoothIntent.ENABLED_ACTION) || 221 action.equals(BluetoothIntent.DISABLED_ACTION) || 222 action.equals(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION) || 223 action.equals(BluetoothA2dp.SINK_STATE_CHANGED_ACTION)) { 224 updateBluetooth(intent); 225 } 226 else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION) || 227 action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION) || 228 action.equals(WifiManager.RSSI_CHANGED_ACTION)) { 229 updateWifi(intent); 230 } 231 else if (action.equals(GpsLocationProvider.GPS_ENABLED_CHANGE_ACTION) || 232 action.equals(GpsLocationProvider.GPS_FIX_CHANGE_ACTION)) { 233 updateGps(intent); 234 } 235 else if (action.equals(AudioManager.RINGER_MODE_CHANGED_ACTION) || 236 action.equals(AudioManager.VIBRATE_SETTING_CHANGED_ACTION)) { 237 updateVolume(); 238 } 239 else if (action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) { 240 updateSimState(intent); 241 } 242 } 243 }; 244 245 private StatusBarPolicy(Context context, StatusBarService service) { 246 mContext = context; 247 mService = service; 248 249 // clock 250 mCalendar = Calendar.getInstance(TimeZone.getDefault()); 251 mClockData = IconData.makeText("clock", ""); 252 mClockIcon = service.addIcon(mClockData, null); 253 updateClock(); 254 255 // battery 256 mBatteryData = IconData.makeIcon("battery", 257 null, com.android.internal.R.drawable.stat_sys_battery_unknown, 0, 0); 258 mBatteryIcon = service.addIcon(mBatteryData, null); 259 260 // phone_signal 261 mPhone = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE); 262 mPhoneData = IconData.makeIcon("phone_signal", 263 null, com.android.internal.R.drawable.stat_sys_signal_null, 0, 0); 264 mPhoneIcon = service.addIcon(mPhoneData, null); 265 // register for phone state notifications. 266 ((TelephonyManager)mContext.getSystemService(Context.TELEPHONY_SERVICE)) 267 .listen(mPhoneStateListener, 268 PhoneStateListener.LISTEN_SERVICE_STATE 269 | PhoneStateListener.LISTEN_SIGNAL_STRENGTH 270 | PhoneStateListener.LISTEN_CALL_STATE 271 | PhoneStateListener.LISTEN_DATA_CONNECTION_STATE 272 | PhoneStateListener.LISTEN_DATA_ACTIVITY); 273 274 // data_connection 275 mDataData = IconData.makeIcon("data_connection", 276 null, com.android.internal.R.drawable.stat_sys_data_connected_g, 0, 0); 277 mDataIcon = service.addIcon(mDataData, null); 278 service.setIconVisibility(mDataIcon, false); 279 280 // wifi 281 mWifiData = IconData.makeIcon("wifi", null, sWifiSignalImages[0], 0, 0); 282 mWifiIcon = service.addIcon(mWifiData, null); 283 service.setIconVisibility(mWifiIcon, false); 284 // wifi will get updated by the sticky intents 285 286 // bluetooth status 287 mBluetoothData = IconData.makeIcon("bluetooth", 288 null, com.android.internal.R.drawable.stat_sys_data_bluetooth, 0, 0); 289 mBluetoothIcon = service.addIcon(mBluetoothData, null); 290 BluetoothDevice bluetooth = 291 (BluetoothDevice) mContext.getSystemService(Context.BLUETOOTH_SERVICE); 292 if (bluetooth != null) { 293 mBluetoothEnabled = bluetooth.isEnabled(); 294 } else { 295 mBluetoothEnabled = false; 296 } 297 mBluetoothA2dpState = BluetoothA2dp.STATE_DISCONNECTED; 298 mBluetoothHeadsetState = BluetoothHeadset.STATE_DISCONNECTED; 299 mService.setIconVisibility(mBluetoothIcon, mBluetoothEnabled); 300 301 // Gps status 302 mGpsEnabledIconData = IconData.makeIcon("gps", 303 null, com.android.internal.R.drawable.stat_sys_gps_acquiring_anim, 0, 0); 304 mGpsFixIconData = IconData.makeIcon("gps", 305 null, com.android.internal.R.drawable.stat_sys_gps_on, 0, 0); 306 mGpsIcon = service.addIcon(mGpsEnabledIconData, null); 307 service.setIconVisibility(mGpsIcon, false); 308 309 // Alarm clock 310 mAlarmClockIconData = IconData.makeIcon( 311 "alarm_clock", 312 null, com.android.internal.R.drawable.stat_notify_alarm, 0, 0); 313 mAlarmClockIcon = service.addIcon(mAlarmClockIconData, null); 314 service.setIconVisibility(mAlarmClockIcon, false); 315 316 // Sync state 317 mSyncActiveIcon = service.addIcon(IconData.makeIcon("sync_active", 318 null, R.drawable.stat_notify_sync_anim0, 0, 0), null); 319 mSyncFailingIcon = service.addIcon(IconData.makeIcon("sync_failing", 320 null, R.drawable.stat_notify_sync_error, 0, 0), null); 321 service.setIconVisibility(mSyncActiveIcon, false); 322 service.setIconVisibility(mSyncFailingIcon, false); 323 324 // volume 325 mVolumeData = IconData.makeIcon("volume", 326 null, com.android.internal.R.drawable.stat_sys_ringer_silent, 0, 0); 327 mVolumeIcon = service.addIcon(mVolumeData, null); 328 service.setIconVisibility(mVolumeIcon, false); 329 updateVolume(); 330 331 IntentFilter filter = new IntentFilter(); 332 333 // Register for Intent broadcasts for... 334 filter.addAction(Intent.ACTION_TIME_TICK); 335 filter.addAction(Intent.ACTION_TIME_CHANGED); 336 filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED); 337 filter.addAction(Intent.ACTION_BATTERY_CHANGED); 338 filter.addAction(Intent.ACTION_TIMEZONE_CHANGED); 339 filter.addAction(Intent.ACTION_ALARM_CHANGED); 340 filter.addAction(Intent.ACTION_SYNC_STATE_CHANGED); 341 filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION); 342 filter.addAction(AudioManager.VIBRATE_SETTING_CHANGED_ACTION); 343 filter.addAction(BluetoothIntent.ENABLED_ACTION); 344 filter.addAction(BluetoothIntent.DISABLED_ACTION); 345 filter.addAction(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION); 346 filter.addAction(BluetoothA2dp.SINK_STATE_CHANGED_ACTION); 347 filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); 348 filter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION); 349 filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); 350 filter.addAction(WifiManager.RSSI_CHANGED_ACTION); 351 filter.addAction(GpsLocationProvider.GPS_ENABLED_CHANGE_ACTION); 352 filter.addAction(GpsLocationProvider.GPS_FIX_CHANGE_ACTION); 353 filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED); 354 mContext.registerReceiver(mIntentReceiver, filter, null, mHandler); 355 } 356 357 public static void installIcons(Context context, StatusBarService service) { 358 sInstance = new StatusBarPolicy(context, service); 359 } 360 361 private final void updateClock() { 362 mCalendar.setTimeInMillis(System.currentTimeMillis()); 363 mClockData.text = DateFormat.getTimeFormat(mContext) 364 .format(mCalendar.getTime()); 365 mService.updateIcon(mClockIcon, mClockData, null); 366 } 367 368 private final void updateAlarm(Intent intent) { 369 boolean alarmSet = intent.getBooleanExtra("alarmSet", false); 370 mService.setIconVisibility(mAlarmClockIcon, alarmSet); 371 } 372 373 private final void updateSyncState(Intent intent) { 374 boolean isActive = intent.getBooleanExtra("active", false); 375 boolean isFailing = intent.getBooleanExtra("failing", false); 376 mService.setIconVisibility(mSyncActiveIcon, isActive); 377 // Don't display sync failing icon: BUG 1297963 Set sync error timeout to "never" 378 //mService.setIconVisibility(mSyncFailingIcon, isFailing && !isActive); 379 } 380 381 private void pickNextBatteryLevel(int level) { 382 final int N = mBatteryThresholds.length; 383 for (int i=0; i<N; i++) { 384 if (level >= mBatteryThresholds[i]) { 385 mBatteryThreshold = i; 386 break; 387 } 388 } 389 if (mBatteryThreshold >= N) { 390 mBatteryThreshold = N-1; 391 } 392 } 393 394 private final void updateBattery(Intent intent) { 395 mBatteryData.iconId = intent.getIntExtra("icon-small", 0); 396 mBatteryData.iconLevel = intent.getIntExtra("level", 0); 397 mService.updateIcon(mBatteryIcon, mBatteryData, null); 398 399 boolean plugged = intent.getIntExtra("plugged", 0) != 0; 400 int level = intent.getIntExtra("level", -1); 401 if (false) { 402 Log.d(TAG, "updateBattery level=" + level 403 + " plugged=" + plugged 404 + " mBatteryPlugged=" + mBatteryPlugged 405 + " mBatteryLevel=" + mBatteryLevel 406 + " mBatteryThreshold=" + mBatteryThreshold 407 + " mBatteryFirst=" + mBatteryFirst); 408 } 409 410 boolean oldPlugged = mBatteryPlugged; 411 int oldThreshold = mBatteryThreshold; 412 pickNextBatteryLevel(level); 413 414 mBatteryPlugged = plugged; 415 mBatteryLevel = level; 416 417 if (mBatteryFirst) { 418 mBatteryFirst = false; 419 } 420 /* 421 * No longer showing the battery view because it draws attention away 422 * from the USB storage notification. We could still show it when 423 * connected to a brick, but that could lead to the user into thinking 424 * the device does not charge when plugged into USB (since he/she would 425 * not see the same battery screen on USB as he sees on brick). 426 */ 427 /* else { 428 if (plugged && !oldPlugged) { 429 showBatteryView(); 430 } 431 } 432 */ 433 if (!plugged 434 && ((oldPlugged && level <= mBatteryThresholds[0]) 435 || (mBatteryThreshold > oldThreshold))) { 436 // Broadcast the low battery warning 437 mContext.sendBroadcast(new Intent(Intent.ACTION_BATTERY_LOW)); 438 439 if (SHOW_LOW_BATTERY_WARNING) { 440 if (false) { 441 Log.d(TAG, "mPhoneState=" + mPhoneState 442 + " mLowBatteryDialog=" + mLowBatteryDialog 443 + " mBatteryShowLowOnEndCall=" + mBatteryShowLowOnEndCall); 444 } 445 446 if (mPhoneState == TelephonyManager.CALL_STATE_IDLE) { 447 showLowBatteryWarning(); 448 } else { 449 mBatteryShowLowOnEndCall = true; 450 } 451 } 452 } 453 } 454 455 private void showBatteryView() { 456 closeLastBatteryView(); 457 if (mLowBatteryDialog != null) { 458 mLowBatteryDialog.dismiss(); 459 } 460 461 int level = mBatteryLevel; 462 463 View v = View.inflate(mContext, com.android.internal.R.layout.battery_status, null); 464 mBatteryView = v; 465 int pixelFormat = PixelFormat.TRANSLUCENT; 466 Drawable bg = v.getBackground(); 467 if (bg != null) { 468 pixelFormat = bg.getOpacity(); 469 } 470 471 WindowManager.LayoutParams lp = new WindowManager.LayoutParams( 472 ViewGroup.LayoutParams.WRAP_CONTENT, 473 ViewGroup.LayoutParams.WRAP_CONTENT, 474 WindowManager.LayoutParams.TYPE_TOAST, 475 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE 476 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE 477 | WindowManager.LayoutParams.FLAG_BLUR_BEHIND 478 | WindowManager.LayoutParams.FLAG_DIM_BEHIND, 479 pixelFormat); 480 481 // Get the dim amount from the theme 482 TypedArray a = mContext.obtainStyledAttributes( 483 com.android.internal.R.styleable.Theme); 484 lp.dimAmount = a.getFloat(android.R.styleable.Theme_backgroundDimAmount, 0.5f); 485 a.recycle(); 486 487 lp.setTitle("Battery"); 488 489 TextView levelTextView = (TextView)v.findViewById(com.android.internal.R.id.level_percent); 490 levelTextView.setText(mContext.getString( 491 com.android.internal.R.string.battery_status_text_percent_format, level)); 492 493 setBatteryLevel(v, com.android.internal.R.id.spacer, 100-level, 0, 0); 494 setBatteryLevel(v, com.android.internal.R.id.level, level, 495 com.android.internal.R.drawable.battery_charge_fill, level); 496 497 WindowManagerImpl.getDefault().addView(v, lp); 498 499 scheduleCloseBatteryView(); 500 } 501 502 private void setBatteryLevel(View parent, int id, int height, int background, int level) { 503 ImageView v = (ImageView)parent.findViewById(id); 504 LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)v.getLayoutParams(); 505 lp.weight = height; 506 if (background != 0) { 507 v.setBackgroundResource(background); 508 Drawable bkg = v.getBackground(); 509 bkg.setLevel(level); 510 } 511 } 512 513 private void showLowBatteryWarning() { 514 closeLastBatteryView(); 515 516 int level = mBatteryThresholds[mBatteryThreshold > 1 ? mBatteryThreshold - 1 : 0]; 517 CharSequence levelText = mContext.getString( 518 com.android.internal.R.string.battery_low_percent_format, level); 519 520 if (mBatteryLevelTextView != null) { 521 mBatteryLevelTextView.setText(levelText); 522 } else { 523 View v = View.inflate(mContext, com.android.internal.R.layout.battery_low, null); 524 mBatteryLevelTextView=(TextView)v.findViewById(com.android.internal.R.id.level_percent); 525 526 mBatteryLevelTextView.setText(levelText); 527 528 AlertDialog.Builder b = new AlertDialog.Builder(mContext); 529 b.setCancelable(true); 530 b.setTitle(com.android.internal.R.string.battery_low_title); 531 b.setView(v); 532 b.setIcon(android.R.drawable.ic_dialog_alert); 533 b.setPositiveButton(android.R.string.ok, null); 534 535 AlertDialog d = b.create(); 536 d.setOnDismissListener(mLowBatteryListener); 537 d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); 538 d.show(); 539 mLowBatteryDialog = d; 540 } 541 } 542 543 private final void updateCallState(int state) { 544 mPhoneState = state; 545 if (false) { 546 Log.d(TAG, "mPhoneState=" + mPhoneState 547 + " mLowBatteryDialog=" + mLowBatteryDialog 548 + " mBatteryShowLowOnEndCall=" + mBatteryShowLowOnEndCall); 549 } 550 if (mPhoneState == TelephonyManager.CALL_STATE_IDLE) { 551 if (mBatteryShowLowOnEndCall) { 552 if (!mBatteryPlugged) { 553 showLowBatteryWarning(); 554 } 555 mBatteryShowLowOnEndCall = false; 556 } 557 } else { 558 if (mLowBatteryDialog != null) { 559 mLowBatteryDialog.dismiss(); 560 mBatteryShowLowOnEndCall = true; 561 } 562 } 563 } 564 565 private DialogInterface.OnDismissListener mLowBatteryListener 566 = new DialogInterface.OnDismissListener() { 567 public void onDismiss(DialogInterface dialog) { 568 mLowBatteryDialog = null; 569 mBatteryLevelTextView = null; 570 } 571 }; 572 573 private void scheduleCloseBatteryView() { 574 Message m = mHandler.obtainMessage(EVENT_BATTERY_CLOSE); 575 m.arg1 = (++mBatteryViewSequence); 576 mHandler.sendMessageDelayed(m, 3000); 577 } 578 579 private void closeLastBatteryView() { 580 if (mBatteryView != null) { 581 //mBatteryView.debug(); 582 WindowManagerImpl.getDefault().removeView(mBatteryView); 583 mBatteryView = null; 584 } 585 } 586 587 private PhoneStateListener mPhoneStateListener = new PhoneStateListener() { 588 @Override 589 public void onSignalStrengthChanged(int asu) { 590 mSignalAsu = asu; 591 updateSignalStrength(); 592 } 593 594 @Override 595 public void onServiceStateChanged(ServiceState state) { 596 mServiceState = state; 597 updateSignalStrength(); 598 updateDataIcon(); 599 } 600 601 @Override 602 public void onCallStateChanged(int state, String incomingNumber) { 603 updateCallState(state); 604 } 605 606 @Override 607 public void onDataConnectionStateChanged(int state) { 608 mDataState = state; 609 updateDataNetType(); 610 updateDataIcon(); 611 } 612 613 @Override 614 public void onDataActivity(int direction) { 615 mDataActivity = direction; 616 updateDataIcon(); 617 } 618 }; 619 620 621 private final void updateSimState(Intent intent) { 622 String stateExtra = intent.getStringExtra(SimCard.INTENT_KEY_SIM_STATE); 623 if (SimCard.INTENT_VALUE_SIM_ABSENT.equals(stateExtra)) { 624 mSimState = SimCard.State.ABSENT; 625 } 626 else if (SimCard.INTENT_VALUE_SIM_READY.equals(stateExtra)) { 627 mSimState = SimCard.State.READY; 628 } 629 else if (SimCard.INTENT_VALUE_SIM_LOCKED.equals(stateExtra)) { 630 final String lockedReason = intent.getStringExtra(SimCard.INTENT_KEY_LOCKED_REASON); 631 if (SimCard.INTENT_VALUE_LOCKED_ON_PIN.equals(lockedReason)) { 632 mSimState = SimCard.State.PIN_REQUIRED; 633 } 634 else if (SimCard.INTENT_VALUE_LOCKED_ON_PUK.equals(lockedReason)) { 635 mSimState = SimCard.State.PUK_REQUIRED; 636 } 637 else { 638 mSimState = SimCard.State.NETWORK_LOCKED; 639 } 640 } else { 641 mSimState = SimCard.State.UNKNOWN; 642 } 643 updateDataIcon(); 644 } 645 646 private final void updateSignalStrength() { 647 int asu = mSignalAsu; 648 ServiceState ss = mServiceState; 649 650 boolean hasService = true; 651 652 if (ss != null) { 653 int state = ss.getState(); 654 switch (state) { 655 case ServiceState.STATE_OUT_OF_SERVICE: 656 case ServiceState.STATE_POWER_OFF: 657 hasService = false; 658 break; 659 } 660 } else { 661 hasService = false; 662 } 663 664 if (!hasService) { 665 //Log.d(TAG, "updateSignalStrength: no service"); 666 if (Settings.System.getInt(mContext.getContentResolver(), 667 Settings.System.AIRPLANE_MODE_ON, 0) == 1) { 668 mPhoneData.iconId = com.android.internal.R.drawable.stat_sys_signal_flightmode; 669 } else { 670 mPhoneData.iconId = com.android.internal.R.drawable.stat_sys_signal_null; 671 } 672 mService.updateIcon(mPhoneIcon, mPhoneData, null); 673 return; 674 } 675 676 // ASU ranges from 0 to 31 - TS 27.007 Sec 8.5 677 // asu = 0 (-113dB or less) is very weak 678 // signal, its better to show 0 bars to the user in such cases. 679 // asu = 99 is a special case, where the signal strength is unknown. 680 if (asu <= 0 || asu == 99) asu = 0; 681 else if (asu >= 16) asu = 4; 682 else if (asu >= 8) asu = 3; 683 else if (asu >= 4) asu = 2; 684 else asu = 1; 685 686 int[] iconList; 687 if (mPhone.isNetworkRoaming()) { 688 iconList = sSignalImages_r; 689 } else { 690 iconList = sSignalImages; 691 } 692 693 mPhoneData.iconId = iconList[asu]; 694 mService.updateIcon(mPhoneIcon, mPhoneData, null); 695 } 696 697 private final void updateDataNetType() { 698 int net = mPhone.getNetworkType(); 699 switch (net) { 700 case TelephonyManager.NETWORK_TYPE_EDGE: 701 mDataIconList = sDataNetType_e; 702 break; 703 case TelephonyManager.NETWORK_TYPE_UMTS: 704 mDataIconList = sDataNetType_3g; 705 break; 706 default: 707 mDataIconList = sDataNetType_g; 708 break; 709 } 710 } 711 712 private final void updateDataIcon() { 713 int iconId; 714 boolean visible = true; 715 716 if (mSimState == SimCard.State.READY || mSimState == SimCard.State.UNKNOWN) { 717 int data = mDataState; 718 719 int[] list = mDataIconList; 720 721 ServiceState ss = mServiceState; 722 723 boolean hasService = false; 724 725 if (ss != null) { 726 hasService = (ss.getState() == ServiceState.STATE_IN_SERVICE); 727 } 728 729 if (hasService && data == TelephonyManager.DATA_CONNECTED) { 730 switch (mDataActivity) { 731 case TelephonyManager.DATA_ACTIVITY_IN: 732 iconId = list[1]; 733 break; 734 case TelephonyManager.DATA_ACTIVITY_OUT: 735 iconId = list[2]; 736 break; 737 case TelephonyManager.DATA_ACTIVITY_INOUT: 738 iconId = list[3]; 739 break; 740 default: 741 iconId = list[0]; 742 break; 743 } 744 mDataData.iconId = iconId; 745 mService.updateIcon(mDataIcon, mDataData, null); 746 } else { 747 visible = false; 748 } 749 } else { 750 mDataData.iconId = com.android.internal.R.drawable.stat_sys_no_sim; 751 mService.updateIcon(mDataIcon, mDataData, null); 752 } 753 if (mDataIconVisible != visible) { 754 mService.setIconVisibility(mDataIcon, visible); 755 mDataIconVisible = visible; 756 } 757 } 758 759 private final void updateVolume() { 760 AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); 761 final int ringerMode = audioManager.getRingerMode(); 762 final boolean visible = ringerMode == AudioManager.RINGER_MODE_SILENT || 763 ringerMode == AudioManager.RINGER_MODE_VIBRATE; 764 final int iconId = audioManager.shouldVibrate(AudioManager.VIBRATE_TYPE_RINGER) 765 ? com.android.internal.R.drawable.stat_sys_ringer_vibrate 766 : com.android.internal.R.drawable.stat_sys_ringer_silent; 767 768 if (visible) { 769 mVolumeData.iconId = iconId; 770 mService.updateIcon(mVolumeIcon, mVolumeData, null); 771 } 772 if (visible != mVolumeVisible) { 773 mService.setIconVisibility(mVolumeIcon, visible); 774 mVolumeVisible = visible; 775 } 776 } 777 778 private final void updateBluetooth(Intent intent) { 779 int iconId = com.android.internal.R.drawable.stat_sys_data_bluetooth; 780 781 String action = intent.getAction(); 782 if (action.equals(BluetoothIntent.DISABLED_ACTION)) { 783 mBluetoothEnabled = false; 784 } else if (action.equals(BluetoothIntent.ENABLED_ACTION)) { 785 mBluetoothEnabled = true; 786 } else if (action.equals(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION)) { 787 mBluetoothHeadsetState = intent.getIntExtra(BluetoothIntent.HEADSET_STATE, 788 BluetoothHeadset.STATE_ERROR); 789 } else if (action.equals(BluetoothA2dp.SINK_STATE_CHANGED_ACTION)) { 790 mBluetoothA2dpState = intent.getIntExtra(BluetoothA2dp.SINK_STATE, 791 BluetoothA2dp.STATE_DISCONNECTED); 792 } else { 793 return; 794 } 795 796 if (mBluetoothHeadsetState == BluetoothHeadset.STATE_CONNECTED || 797 mBluetoothA2dpState == BluetoothA2dp.STATE_CONNECTED || 798 mBluetoothA2dpState == BluetoothA2dp.STATE_PLAYING) { 799 iconId = com.android.internal.R.drawable.stat_sys_data_bluetooth_connected; 800 } 801 802 mBluetoothData.iconId = iconId; 803 mService.updateIcon(mBluetoothIcon, mBluetoothData, null); 804 mService.setIconVisibility(mBluetoothIcon, mBluetoothEnabled); 805 } 806 807 private final void updateWifi(Intent intent) { 808 final String action = intent.getAction(); 809 if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) { 810 811 final boolean enabled = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, 812 WifiManager.WIFI_STATE_UNKNOWN) == WifiManager.WIFI_STATE_ENABLED; 813 814 if (!enabled) { 815 // If disabled, hide the icon. (We show icon when connected.) 816 mService.setIconVisibility(mWifiIcon, false); 817 } 818 819 } else if (action.equals(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION)) { 820 final boolean enabled = intent.getBooleanExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED, 821 false); 822 if (!enabled) { 823 mService.setIconVisibility(mWifiIcon, false); 824 } 825 } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) { 826 827 final NetworkInfo networkInfo = (NetworkInfo) 828 intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO); 829 830 int iconId; 831 if (networkInfo != null && networkInfo.isConnected()) { 832 mIsWifiConnected = true; 833 if (mLastWifiSignalLevel == -1) { 834 iconId = sWifiSignalImages[0]; 835 } else { 836 iconId = sWifiSignalImages[mLastWifiSignalLevel]; 837 } 838 839 // Show the icon since wi-fi is connected 840 mService.setIconVisibility(mWifiIcon, true); 841 842 } else { 843 mLastWifiSignalLevel = -1; 844 mIsWifiConnected = false; 845 iconId = sWifiSignalImages[0]; 846 847 // Hide the icon since we're not connected 848 mService.setIconVisibility(mWifiIcon, false); 849 } 850 851 mWifiData.iconId = iconId; 852 mService.updateIcon(mWifiIcon, mWifiData, null); 853 } else if (action.equals(WifiManager.RSSI_CHANGED_ACTION)) { 854 final int newRssi = intent.getIntExtra(WifiManager.EXTRA_NEW_RSSI, -200); 855 int newSignalLevel = WifiManager.calculateSignalLevel(newRssi, 856 sWifiSignalImages.length); 857 if (newSignalLevel != mLastWifiSignalLevel) { 858 mLastWifiSignalLevel = newSignalLevel; 859 if (mIsWifiConnected) { 860 mWifiData.iconId = sWifiSignalImages[newSignalLevel]; 861 } else { 862 mWifiData.iconId = sWifiTemporarilyNotConnectedImage; 863 } 864 mService.updateIcon(mWifiIcon, mWifiData, null); 865 } 866 } 867 } 868 869 private final void updateGps(Intent intent) { 870 final String action = intent.getAction(); 871 final boolean enabled = intent.getBooleanExtra(GpsLocationProvider.EXTRA_ENABLED, false); 872 873 if (action.equals(GpsLocationProvider.GPS_FIX_CHANGE_ACTION) && enabled) { 874 // GPS is getting fixes 875 mService.updateIcon(mGpsIcon, mGpsFixIconData, null); 876 mService.setIconVisibility(mGpsIcon, true); 877 } else if (action.equals(GpsLocationProvider.GPS_ENABLED_CHANGE_ACTION) && !enabled) { 878 // GPS is off 879 mService.setIconVisibility(mGpsIcon, false); 880 } else { 881 // GPS is on, but not receiving fixes 882 mService.updateIcon(mGpsIcon, mGpsEnabledIconData, null); 883 mService.setIconVisibility(mGpsIcon, true); 884 } 885 } 886 887 private class StatusBarHandler extends Handler { 888 @Override 889 public void handleMessage(Message msg) { 890 switch (msg.what) { 891 case EVENT_BATTERY_CLOSE: 892 if (msg.arg1 == mBatteryViewSequence) { 893 closeLastBatteryView(); 894 } 895 break; 896 } 897 } 898 } 899} 900