StatusBarPolicy.java revision d24b8183b93e781080b2c16c487e60d51c12da31
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(intent); 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 330 IntentFilter filter = new IntentFilter(); 331 332 // Register for Intent broadcasts for... 333 filter.addAction(Intent.ACTION_TIME_TICK); 334 filter.addAction(Intent.ACTION_TIME_CHANGED); 335 filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED); 336 filter.addAction(Intent.ACTION_BATTERY_CHANGED); 337 filter.addAction(Intent.ACTION_TIMEZONE_CHANGED); 338 filter.addAction(Intent.ACTION_ALARM_CHANGED); 339 filter.addAction(Intent.ACTION_SYNC_STATE_CHANGED); 340 filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION); 341 filter.addAction(AudioManager.VIBRATE_SETTING_CHANGED_ACTION); 342 filter.addAction(BluetoothIntent.ENABLED_ACTION); 343 filter.addAction(BluetoothIntent.DISABLED_ACTION); 344 filter.addAction(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION); 345 filter.addAction(BluetoothA2dp.SINK_STATE_CHANGED_ACTION); 346 filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); 347 filter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION); 348 filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); 349 filter.addAction(WifiManager.RSSI_CHANGED_ACTION); 350 filter.addAction(GpsLocationProvider.GPS_ENABLED_CHANGE_ACTION); 351 filter.addAction(GpsLocationProvider.GPS_FIX_CHANGE_ACTION); 352 filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED); 353 mContext.registerReceiver(mIntentReceiver, filter, null, mHandler); 354 } 355 356 public static void installIcons(Context context, StatusBarService service) { 357 sInstance = new StatusBarPolicy(context, service); 358 } 359 360 private final void updateClock() { 361 mCalendar.setTimeInMillis(System.currentTimeMillis()); 362 mClockData.text = DateFormat.getTimeFormat(mContext) 363 .format(mCalendar.getTime()); 364 mService.updateIcon(mClockIcon, mClockData, null); 365 } 366 367 private final void updateAlarm(Intent intent) { 368 boolean alarmSet = intent.getBooleanExtra("alarmSet", false); 369 mService.setIconVisibility(mAlarmClockIcon, alarmSet); 370 } 371 372 private final void updateSyncState(Intent intent) { 373 boolean isActive = intent.getBooleanExtra("active", false); 374 boolean isFailing = intent.getBooleanExtra("failing", false); 375 mService.setIconVisibility(mSyncActiveIcon, isActive); 376 // Don't display sync failing icon: BUG 1297963 Set sync error timeout to "never" 377 //mService.setIconVisibility(mSyncFailingIcon, isFailing && !isActive); 378 } 379 380 private void pickNextBatteryLevel(int level) { 381 final int N = mBatteryThresholds.length; 382 for (int i=0; i<N; i++) { 383 if (level >= mBatteryThresholds[i]) { 384 mBatteryThreshold = i; 385 break; 386 } 387 } 388 if (mBatteryThreshold >= N) { 389 mBatteryThreshold = N-1; 390 } 391 } 392 393 private final void updateBattery(Intent intent) { 394 mBatteryData.iconId = intent.getIntExtra("icon-small", 0); 395 mBatteryData.iconLevel = intent.getIntExtra("level", 0); 396 mService.updateIcon(mBatteryIcon, mBatteryData, null); 397 398 boolean plugged = intent.getIntExtra("plugged", 0) != 0; 399 int level = intent.getIntExtra("level", -1); 400 if (false) { 401 Log.d(TAG, "updateBattery level=" + level 402 + " plugged=" + plugged 403 + " mBatteryPlugged=" + mBatteryPlugged 404 + " mBatteryLevel=" + mBatteryLevel 405 + " mBatteryThreshold=" + mBatteryThreshold 406 + " mBatteryFirst=" + mBatteryFirst); 407 } 408 409 boolean oldPlugged = mBatteryPlugged; 410 int oldThreshold = mBatteryThreshold; 411 pickNextBatteryLevel(level); 412 413 mBatteryPlugged = plugged; 414 mBatteryLevel = level; 415 416 if (mBatteryFirst) { 417 mBatteryFirst = false; 418 } 419 /* 420 * No longer showing the battery view because it draws attention away 421 * from the USB storage notification. We could still show it when 422 * connected to a brick, but that could lead to the user into thinking 423 * the device does not charge when plugged into USB (since he/she would 424 * not see the same battery screen on USB as he sees on brick). 425 */ 426 /* else { 427 if (plugged && !oldPlugged) { 428 showBatteryView(); 429 } 430 } 431 */ 432 if (!plugged 433 && ((oldPlugged && level <= mBatteryThresholds[0]) 434 || (mBatteryThreshold > oldThreshold))) { 435 // Broadcast the low battery warning 436 mContext.sendBroadcast(new Intent(Intent.ACTION_BATTERY_LOW)); 437 438 if (SHOW_LOW_BATTERY_WARNING) { 439 if (false) { 440 Log.d(TAG, "mPhoneState=" + mPhoneState 441 + " mLowBatteryDialog=" + mLowBatteryDialog 442 + " mBatteryShowLowOnEndCall=" + mBatteryShowLowOnEndCall); 443 } 444 445 if (mPhoneState == TelephonyManager.CALL_STATE_IDLE) { 446 showLowBatteryWarning(); 447 } else { 448 mBatteryShowLowOnEndCall = true; 449 } 450 } 451 } 452 } 453 454 private void showBatteryView() { 455 closeLastBatteryView(); 456 if (mLowBatteryDialog != null) { 457 mLowBatteryDialog.dismiss(); 458 } 459 460 int level = mBatteryLevel; 461 462 View v = View.inflate(mContext, com.android.internal.R.layout.battery_status, null); 463 mBatteryView = v; 464 int pixelFormat = PixelFormat.TRANSLUCENT; 465 Drawable bg = v.getBackground(); 466 if (bg != null) { 467 pixelFormat = bg.getOpacity(); 468 } 469 470 WindowManager.LayoutParams lp = new WindowManager.LayoutParams( 471 ViewGroup.LayoutParams.WRAP_CONTENT, 472 ViewGroup.LayoutParams.WRAP_CONTENT, 473 WindowManager.LayoutParams.TYPE_TOAST, 474 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE 475 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE 476 | WindowManager.LayoutParams.FLAG_BLUR_BEHIND 477 | WindowManager.LayoutParams.FLAG_DIM_BEHIND, 478 pixelFormat); 479 480 // Get the dim amount from the theme 481 TypedArray a = mContext.obtainStyledAttributes( 482 com.android.internal.R.styleable.Theme); 483 lp.dimAmount = a.getFloat(android.R.styleable.Theme_backgroundDimAmount, 0.5f); 484 a.recycle(); 485 486 lp.setTitle("Battery"); 487 488 TextView levelTextView = (TextView)v.findViewById(com.android.internal.R.id.level_percent); 489 levelTextView.setText(mContext.getString( 490 com.android.internal.R.string.battery_status_text_percent_format, level)); 491 492 setBatteryLevel(v, com.android.internal.R.id.spacer, 100-level, 0, 0); 493 setBatteryLevel(v, com.android.internal.R.id.level, level, 494 com.android.internal.R.drawable.battery_charge_fill, level); 495 496 WindowManagerImpl.getDefault().addView(v, lp); 497 498 scheduleCloseBatteryView(); 499 } 500 501 private void setBatteryLevel(View parent, int id, int height, int background, int level) { 502 ImageView v = (ImageView)parent.findViewById(id); 503 LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)v.getLayoutParams(); 504 lp.weight = height; 505 if (background != 0) { 506 v.setBackgroundResource(background); 507 Drawable bkg = v.getBackground(); 508 bkg.setLevel(level); 509 } 510 } 511 512 private void showLowBatteryWarning() { 513 closeLastBatteryView(); 514 515 int level = mBatteryThresholds[mBatteryThreshold > 1 ? mBatteryThreshold - 1 : 0]; 516 CharSequence levelText = mContext.getString( 517 com.android.internal.R.string.battery_low_percent_format, level); 518 519 if (mBatteryLevelTextView != null) { 520 mBatteryLevelTextView.setText(levelText); 521 } else { 522 View v = View.inflate(mContext, com.android.internal.R.layout.battery_low, null); 523 mBatteryLevelTextView=(TextView)v.findViewById(com.android.internal.R.id.level_percent); 524 525 mBatteryLevelTextView.setText(levelText); 526 527 AlertDialog.Builder b = new AlertDialog.Builder(mContext); 528 b.setCancelable(true); 529 b.setTitle(com.android.internal.R.string.battery_low_title); 530 b.setView(v); 531 b.setIcon(android.R.drawable.ic_dialog_alert); 532 b.setPositiveButton(android.R.string.ok, null); 533 534 AlertDialog d = b.create(); 535 d.setOnDismissListener(mLowBatteryListener); 536 d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); 537 d.show(); 538 mLowBatteryDialog = d; 539 } 540 } 541 542 private final void updateCallState(int state) { 543 mPhoneState = state; 544 if (false) { 545 Log.d(TAG, "mPhoneState=" + mPhoneState 546 + " mLowBatteryDialog=" + mLowBatteryDialog 547 + " mBatteryShowLowOnEndCall=" + mBatteryShowLowOnEndCall); 548 } 549 if (mPhoneState == TelephonyManager.CALL_STATE_IDLE) { 550 if (mBatteryShowLowOnEndCall) { 551 if (!mBatteryPlugged) { 552 showLowBatteryWarning(); 553 } 554 mBatteryShowLowOnEndCall = false; 555 } 556 } else { 557 if (mLowBatteryDialog != null) { 558 mLowBatteryDialog.dismiss(); 559 mBatteryShowLowOnEndCall = true; 560 } 561 } 562 } 563 564 private DialogInterface.OnDismissListener mLowBatteryListener 565 = new DialogInterface.OnDismissListener() { 566 public void onDismiss(DialogInterface dialog) { 567 mLowBatteryDialog = null; 568 mBatteryLevelTextView = null; 569 } 570 }; 571 572 private void scheduleCloseBatteryView() { 573 Message m = mHandler.obtainMessage(EVENT_BATTERY_CLOSE); 574 m.arg1 = (++mBatteryViewSequence); 575 mHandler.sendMessageDelayed(m, 3000); 576 } 577 578 private void closeLastBatteryView() { 579 if (mBatteryView != null) { 580 //mBatteryView.debug(); 581 WindowManagerImpl.getDefault().removeView(mBatteryView); 582 mBatteryView = null; 583 } 584 } 585 586 private PhoneStateListener mPhoneStateListener = new PhoneStateListener() { 587 @Override 588 public void onSignalStrengthChanged(int asu) { 589 mSignalAsu = asu; 590 updateSignalStrength(); 591 } 592 593 @Override 594 public void onServiceStateChanged(ServiceState state) { 595 mServiceState = state; 596 updateSignalStrength(); 597 updateDataIcon(); 598 } 599 600 @Override 601 public void onCallStateChanged(int state, String incomingNumber) { 602 updateCallState(state); 603 } 604 605 @Override 606 public void onDataConnectionStateChanged(int state) { 607 mDataState = state; 608 updateDataNetType(); 609 updateDataIcon(); 610 } 611 612 @Override 613 public void onDataActivity(int direction) { 614 mDataActivity = direction; 615 updateDataIcon(); 616 } 617 }; 618 619 620 private final void updateSimState(Intent intent) { 621 String stateExtra = intent.getStringExtra(SimCard.INTENT_KEY_SIM_STATE); 622 if (SimCard.INTENT_VALUE_SIM_ABSENT.equals(stateExtra)) { 623 mSimState = SimCard.State.ABSENT; 624 } 625 else if (SimCard.INTENT_VALUE_SIM_READY.equals(stateExtra)) { 626 mSimState = SimCard.State.READY; 627 } 628 else if (SimCard.INTENT_VALUE_SIM_LOCKED.equals(stateExtra)) { 629 final String lockedReason = intent.getStringExtra(SimCard.INTENT_KEY_LOCKED_REASON); 630 if (SimCard.INTENT_VALUE_LOCKED_ON_PIN.equals(lockedReason)) { 631 mSimState = SimCard.State.PIN_REQUIRED; 632 } 633 else if (SimCard.INTENT_VALUE_LOCKED_ON_PUK.equals(lockedReason)) { 634 mSimState = SimCard.State.PUK_REQUIRED; 635 } 636 else { 637 mSimState = SimCard.State.NETWORK_LOCKED; 638 } 639 } else { 640 mSimState = SimCard.State.UNKNOWN; 641 } 642 updateDataIcon(); 643 } 644 645 private final void updateSignalStrength() { 646 int asu = mSignalAsu; 647 ServiceState ss = mServiceState; 648 649 boolean hasService = true; 650 651 if (ss != null) { 652 int state = ss.getState(); 653 switch (state) { 654 case ServiceState.STATE_OUT_OF_SERVICE: 655 case ServiceState.STATE_POWER_OFF: 656 hasService = false; 657 break; 658 } 659 } else { 660 hasService = false; 661 } 662 663 if (!hasService) { 664 //Log.d(TAG, "updateSignalStrength: no service"); 665 if (Settings.System.getInt(mContext.getContentResolver(), 666 Settings.System.AIRPLANE_MODE_ON, 0) == 1) { 667 mPhoneData.iconId = com.android.internal.R.drawable.stat_sys_signal_flightmode; 668 } else { 669 mPhoneData.iconId = com.android.internal.R.drawable.stat_sys_signal_null; 670 } 671 mService.updateIcon(mPhoneIcon, mPhoneData, null); 672 return; 673 } 674 675 // ASU ranges from 0 to 31 - TS 27.007 Sec 8.5 676 // asu = 0 (-113dB or less) is very weak 677 // signal, its better to show 0 bars to the user in such cases. 678 // asu = 99 is a special case, where the signal strength is unknown. 679 if (asu <= 0 || asu == 99) asu = 0; 680 else if (asu >= 16) asu = 4; 681 else if (asu >= 8) asu = 3; 682 else if (asu >= 4) asu = 2; 683 else asu = 1; 684 685 int[] iconList; 686 if (mPhone.isNetworkRoaming()) { 687 iconList = sSignalImages_r; 688 } else { 689 iconList = sSignalImages; 690 } 691 692 mPhoneData.iconId = iconList[asu]; 693 mService.updateIcon(mPhoneIcon, mPhoneData, null); 694 } 695 696 private final void updateDataNetType() { 697 int net = mPhone.getNetworkType(); 698 switch (net) { 699 case TelephonyManager.NETWORK_TYPE_EDGE: 700 mDataIconList = sDataNetType_e; 701 break; 702 case TelephonyManager.NETWORK_TYPE_UMTS: 703 mDataIconList = sDataNetType_3g; 704 break; 705 default: 706 mDataIconList = sDataNetType_g; 707 break; 708 } 709 } 710 711 private final void updateDataIcon() { 712 int iconId; 713 boolean visible = true; 714 715 if (mSimState == SimCard.State.READY || mSimState == SimCard.State.UNKNOWN) { 716 int data = mDataState; 717 718 int[] list = mDataIconList; 719 720 ServiceState ss = mServiceState; 721 722 boolean hasService = false; 723 724 if (ss != null) { 725 hasService = (ss.getState() == ServiceState.STATE_IN_SERVICE); 726 } 727 728 if (hasService && data == TelephonyManager.DATA_CONNECTED) { 729 switch (mDataActivity) { 730 case TelephonyManager.DATA_ACTIVITY_IN: 731 iconId = list[1]; 732 break; 733 case TelephonyManager.DATA_ACTIVITY_OUT: 734 iconId = list[2]; 735 break; 736 case TelephonyManager.DATA_ACTIVITY_INOUT: 737 iconId = list[3]; 738 break; 739 default: 740 iconId = list[0]; 741 break; 742 } 743 mDataData.iconId = iconId; 744 mService.updateIcon(mDataIcon, mDataData, null); 745 } else { 746 visible = false; 747 } 748 } else { 749 mDataData.iconId = com.android.internal.R.drawable.stat_sys_no_sim; 750 mService.updateIcon(mDataIcon, mDataData, null); 751 } 752 if (mDataIconVisible != visible) { 753 mService.setIconVisibility(mDataIcon, visible); 754 mDataIconVisible = visible; 755 } 756 } 757 758 private final void updateVolume(Intent intent) { 759 // This can be called from two different received intents, so don't use extras. 760 761 AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); 762 final int ringerMode = audioManager.getRingerMode(); 763 final boolean visible = ringerMode == AudioManager.RINGER_MODE_SILENT || 764 ringerMode == AudioManager.RINGER_MODE_VIBRATE; 765 final int iconId = audioManager.shouldVibrate(AudioManager.VIBRATE_TYPE_RINGER) 766 ? com.android.internal.R.drawable.stat_sys_ringer_vibrate 767 : com.android.internal.R.drawable.stat_sys_ringer_silent; 768 769 if (visible) { 770 mVolumeData.iconId = iconId; 771 mService.updateIcon(mVolumeIcon, mVolumeData, null); 772 } 773 if (visible != mVolumeVisible) { 774 mService.setIconVisibility(mVolumeIcon, visible); 775 mVolumeVisible = visible; 776 } 777 } 778 779 private final void updateBluetooth(Intent intent) { 780 int iconId = com.android.internal.R.drawable.stat_sys_data_bluetooth; 781 782 String action = intent.getAction(); 783 if (action.equals(BluetoothIntent.DISABLED_ACTION)) { 784 mBluetoothEnabled = false; 785 } else if (action.equals(BluetoothIntent.ENABLED_ACTION)) { 786 mBluetoothEnabled = true; 787 } else if (action.equals(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION)) { 788 mBluetoothHeadsetState = intent.getIntExtra(BluetoothIntent.HEADSET_STATE, 789 BluetoothHeadset.STATE_ERROR); 790 } else if (action.equals(BluetoothA2dp.SINK_STATE_CHANGED_ACTION)) { 791 mBluetoothA2dpState = intent.getIntExtra(BluetoothA2dp.SINK_STATE, 792 BluetoothA2dp.STATE_DISCONNECTED); 793 } else { 794 return; 795 } 796 797 if (mBluetoothHeadsetState == BluetoothHeadset.STATE_CONNECTED || 798 mBluetoothA2dpState == BluetoothA2dp.STATE_CONNECTED || 799 mBluetoothA2dpState == BluetoothA2dp.STATE_PLAYING) { 800 iconId = com.android.internal.R.drawable.stat_sys_data_bluetooth_connected; 801 } 802 803 mBluetoothData.iconId = iconId; 804 mService.updateIcon(mBluetoothIcon, mBluetoothData, null); 805 mService.setIconVisibility(mBluetoothIcon, mBluetoothEnabled); 806 } 807 808 private final void updateWifi(Intent intent) { 809 final String action = intent.getAction(); 810 if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) { 811 812 final boolean enabled = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, 813 WifiManager.WIFI_STATE_UNKNOWN) == WifiManager.WIFI_STATE_ENABLED; 814 815 if (!enabled) { 816 // If disabled, hide the icon. (We show icon when connected.) 817 mService.setIconVisibility(mWifiIcon, false); 818 } 819 820 } else if (action.equals(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION)) { 821 final boolean enabled = intent.getBooleanExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED, 822 false); 823 if (!enabled) { 824 mService.setIconVisibility(mWifiIcon, false); 825 } 826 } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) { 827 828 final NetworkInfo networkInfo = (NetworkInfo) 829 intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO); 830 831 int iconId; 832 if (networkInfo != null && networkInfo.isConnected()) { 833 mIsWifiConnected = true; 834 if (mLastWifiSignalLevel == -1) { 835 iconId = sWifiSignalImages[0]; 836 } else { 837 iconId = sWifiSignalImages[mLastWifiSignalLevel]; 838 } 839 840 // Show the icon since wi-fi is connected 841 mService.setIconVisibility(mWifiIcon, true); 842 843 } else { 844 mLastWifiSignalLevel = -1; 845 mIsWifiConnected = false; 846 iconId = sWifiSignalImages[0]; 847 848 // Hide the icon since we're not connected 849 mService.setIconVisibility(mWifiIcon, false); 850 } 851 852 mWifiData.iconId = iconId; 853 mService.updateIcon(mWifiIcon, mWifiData, null); 854 } else if (action.equals(WifiManager.RSSI_CHANGED_ACTION)) { 855 final int newRssi = intent.getIntExtra(WifiManager.EXTRA_NEW_RSSI, -200); 856 int newSignalLevel = WifiManager.calculateSignalLevel(newRssi, 857 sWifiSignalImages.length); 858 if (newSignalLevel != mLastWifiSignalLevel) { 859 mLastWifiSignalLevel = newSignalLevel; 860 if (mIsWifiConnected) { 861 mWifiData.iconId = sWifiSignalImages[newSignalLevel]; 862 } else { 863 mWifiData.iconId = sWifiTemporarilyNotConnectedImage; 864 } 865 mService.updateIcon(mWifiIcon, mWifiData, null); 866 } 867 } 868 } 869 870 private final void updateGps(Intent intent) { 871 final String action = intent.getAction(); 872 final boolean enabled = intent.getBooleanExtra(GpsLocationProvider.EXTRA_ENABLED, false); 873 874 if (action.equals(GpsLocationProvider.GPS_FIX_CHANGE_ACTION) && enabled) { 875 // GPS is getting fixes 876 mService.updateIcon(mGpsIcon, mGpsFixIconData, null); 877 mService.setIconVisibility(mGpsIcon, true); 878 } else if (action.equals(GpsLocationProvider.GPS_ENABLED_CHANGE_ACTION) && !enabled) { 879 // GPS is off 880 mService.setIconVisibility(mGpsIcon, false); 881 } else { 882 // GPS is on, but not receiving fixes 883 mService.updateIcon(mGpsIcon, mGpsEnabledIconData, null); 884 mService.setIconVisibility(mGpsIcon, true); 885 } 886 } 887 888 private class StatusBarHandler extends Handler { 889 @Override 890 public void handleMessage(Message msg) { 891 switch (msg.what) { 892 case EVENT_BATTERY_CLOSE: 893 if (msg.arg1 == mBatteryViewSequence) { 894 closeLastBatteryView(); 895 } 896 break; 897 } 898 } 899 } 900} 901