/* * Copyright (C) 2008 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.status; import com.android.internal.R; import com.android.internal.app.IBatteryStats; import com.android.internal.location.GpsLocationProvider; import com.android.internal.telephony.SimCard; import com.android.internal.telephony.TelephonyIntents; import com.android.server.am.BatteryStatsService; import android.app.AlertDialog; import android.bluetooth.BluetoothA2dp; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothError; import android.bluetooth.BluetoothHeadset; import android.bluetooth.BluetoothIntent; import android.content.BroadcastReceiver; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.IntentFilter; import android.content.res.TypedArray; import android.graphics.PixelFormat; import android.graphics.drawable.Drawable; import android.media.AudioManager; import android.net.NetworkInfo; import android.net.wifi.WifiManager; import android.os.Binder; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.os.RemoteException; import android.provider.Settings; import android.telephony.PhoneStateListener; import android.telephony.ServiceState; import android.telephony.TelephonyManager; import android.text.format.DateFormat; import android.util.Log; import android.view.View; import android.view.ViewGroup; import android.view.WindowManager; import android.view.WindowManagerImpl; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; import java.util.Calendar; import java.util.TimeZone; /** * This class contains all of the policy about which icons are installed in the status * bar at boot time. In reality, it should go into the android.policy package, but * putting it here is the first step from extracting it. */ public class StatusBarPolicy { private static final String TAG = "StatusBarPolicy"; private static StatusBarPolicy sInstance; // message codes for the handler private static final int EVENT_DATA_CONN_STATE_CHANGED = 2; private static final int EVENT_DATA_ACTIVITY = 3; private static final int EVENT_BATTERY_CLOSE = 4; // indices into mBatteryThresholds private static final int BATTERY_THRESHOLD_CLOSE_WARNING = 0; private static final int BATTERY_THRESHOLD_WARNING = 1; private static final int BATTERY_THRESHOLD_EMPTY = 2; private final Context mContext; private final StatusBarService mService; private final Handler mHandler = new StatusBarHandler(); private final IBatteryStats mBatteryStats; // clock private Calendar mCalendar; private IBinder mClockIcon; private IconData mClockData; // battery private IBinder mBatteryIcon; private IconData mBatteryData; private boolean mBatteryFirst = true; private boolean mBatteryPlugged; private int mBatteryLevel; private int mBatteryThreshold = 0; // index into mBatteryThresholds private int[] mBatteryThresholds = new int[] { 20, 15, -1 }; private AlertDialog mLowBatteryDialog; private TextView mBatteryLevelTextView; private View mBatteryView; private int mBatteryViewSequence; private boolean mBatteryShowLowOnEndCall = false; private static final boolean SHOW_LOW_BATTERY_WARNING = true; // phone private TelephonyManager mPhone; private IBinder mPhoneIcon; private IconData mPhoneData; private static final int[] sSignalImages = new int[] { com.android.internal.R.drawable.stat_sys_signal_0, com.android.internal.R.drawable.stat_sys_signal_1, com.android.internal.R.drawable.stat_sys_signal_2, com.android.internal.R.drawable.stat_sys_signal_3, com.android.internal.R.drawable.stat_sys_signal_4 }; private static final int[] sSignalImages_r = new int[] { com.android.internal.R.drawable.stat_sys_r_signal_0, com.android.internal.R.drawable.stat_sys_r_signal_1, com.android.internal.R.drawable.stat_sys_r_signal_2, com.android.internal.R.drawable.stat_sys_r_signal_3, com.android.internal.R.drawable.stat_sys_r_signal_4 }; private int[] mDataIconList = sDataNetType_g; private static final int[] sDataNetType_g = new int[] { com.android.internal.R.drawable.stat_sys_data_connected_g, com.android.internal.R.drawable.stat_sys_data_in_g, com.android.internal.R.drawable.stat_sys_data_out_g, com.android.internal.R.drawable.stat_sys_data_inandout_g, }; private static final int[] sDataNetType_3g = new int[] { com.android.internal.R.drawable.stat_sys_data_connected_3g, com.android.internal.R.drawable.stat_sys_data_in_3g, com.android.internal.R.drawable.stat_sys_data_out_3g, com.android.internal.R.drawable.stat_sys_data_inandout_3g, }; private static final int[] sDataNetType_e = new int[] { com.android.internal.R.drawable.stat_sys_data_connected_e, com.android.internal.R.drawable.stat_sys_data_in_e, com.android.internal.R.drawable.stat_sys_data_out_e, com.android.internal.R.drawable.stat_sys_data_inandout_e, }; // Assume it's all good unless we hear otherwise. We don't always seem // to get broadcasts that it *is* there. SimCard.State mSimState = SimCard.State.READY; int mPhoneState = TelephonyManager.CALL_STATE_IDLE; int mDataState = TelephonyManager.DATA_DISCONNECTED; int mDataNetType = TelephonyManager.NETWORK_TYPE_UNKNOWN; int mDataActivity = TelephonyManager.DATA_ACTIVITY_NONE; ServiceState mServiceState; int mSignalAsu = -1; // data connection private IBinder mDataIcon; private IconData mDataData; private boolean mDataIconVisible; // ringer volume private IBinder mVolumeIcon; private IconData mVolumeData; private boolean mVolumeVisible; // bluetooth device status private IBinder mBluetoothIcon; private IconData mBluetoothData; private int mBluetoothHeadsetState; private int mBluetoothA2dpState; private boolean mBluetoothEnabled; // wifi private static final int[] sWifiSignalImages = new int[] { com.android.internal.R.drawable.stat_sys_wifi_signal_1, com.android.internal.R.drawable.stat_sys_wifi_signal_2, com.android.internal.R.drawable.stat_sys_wifi_signal_3, com.android.internal.R.drawable.stat_sys_wifi_signal_4, }; private static final int sWifiTemporarilyNotConnectedImage = com.android.internal.R.drawable.stat_sys_wifi_signal_0; private int mLastWifiSignalLevel = -1; private boolean mIsWifiConnected = false; private IBinder mWifiIcon; private IconData mWifiData; // gps private IBinder mGpsIcon; private IconData mGpsEnabledIconData; private IconData mGpsFixIconData; // alarm clock // Icon lit when clock is set private IBinder mAlarmClockIcon; private IconData mAlarmClockIconData; // sync state // If sync is active the SyncActive icon is displayed. If sync is not active but // sync is failing the SyncFailing icon is displayed. Otherwise neither are displayed. private IBinder mSyncActiveIcon; private IBinder mSyncFailingIcon; private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (action.equals(Intent.ACTION_TIME_TICK)) { updateClock(); } else if (action.equals(Intent.ACTION_TIME_CHANGED)) { updateClock(); } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) { updateClock(); } else if (action.equals(Intent.ACTION_TIMEZONE_CHANGED)) { String tz = intent.getStringExtra("time-zone"); mCalendar = Calendar.getInstance(TimeZone.getTimeZone(tz)); updateClock(); } else if (action.equals(Intent.ACTION_ALARM_CHANGED)) { updateAlarm(intent); } else if (action.equals(Intent.ACTION_SYNC_STATE_CHANGED)) { updateSyncState(intent); } else if (action.equals(Intent.ACTION_BATTERY_CHANGED)) { updateBattery(intent); } else if (action.equals(BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION) || action.equals(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION) || action.equals(BluetoothA2dp.SINK_STATE_CHANGED_ACTION)) { updateBluetooth(intent); } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION) || action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION) || action.equals(WifiManager.RSSI_CHANGED_ACTION)) { updateWifi(intent); } else if (action.equals(GpsLocationProvider.GPS_ENABLED_CHANGE_ACTION) || action.equals(GpsLocationProvider.GPS_FIX_CHANGE_ACTION)) { updateGps(intent); } else if (action.equals(AudioManager.RINGER_MODE_CHANGED_ACTION) || action.equals(AudioManager.VIBRATE_SETTING_CHANGED_ACTION)) { updateVolume(); } else if (action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) { updateSimState(intent); } } }; private StatusBarPolicy(Context context, StatusBarService service) { mContext = context; mService = service; mBatteryStats = BatteryStatsService.getService(); // clock mCalendar = Calendar.getInstance(TimeZone.getDefault()); mClockData = IconData.makeText("clock", ""); mClockIcon = service.addIcon(mClockData, null); updateClock(); // battery mBatteryData = IconData.makeIcon("battery", null, com.android.internal.R.drawable.stat_sys_battery_unknown, 0, 0); mBatteryIcon = service.addIcon(mBatteryData, null); // phone_signal mPhone = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE); mPhoneData = IconData.makeIcon("phone_signal", null, com.android.internal.R.drawable.stat_sys_signal_null, 0, 0); mPhoneIcon = service.addIcon(mPhoneData, null); // register for phone state notifications. ((TelephonyManager)mContext.getSystemService(Context.TELEPHONY_SERVICE)) .listen(mPhoneStateListener, PhoneStateListener.LISTEN_SERVICE_STATE | PhoneStateListener.LISTEN_SIGNAL_STRENGTH | PhoneStateListener.LISTEN_CALL_STATE | PhoneStateListener.LISTEN_DATA_CONNECTION_STATE | PhoneStateListener.LISTEN_DATA_ACTIVITY); // data_connection mDataData = IconData.makeIcon("data_connection", null, com.android.internal.R.drawable.stat_sys_data_connected_g, 0, 0); mDataIcon = service.addIcon(mDataData, null); service.setIconVisibility(mDataIcon, false); // wifi mWifiData = IconData.makeIcon("wifi", null, sWifiSignalImages[0], 0, 0); mWifiIcon = service.addIcon(mWifiData, null); service.setIconVisibility(mWifiIcon, false); // wifi will get updated by the sticky intents // bluetooth status mBluetoothData = IconData.makeIcon("bluetooth", null, com.android.internal.R.drawable.stat_sys_data_bluetooth, 0, 0); mBluetoothIcon = service.addIcon(mBluetoothData, null); BluetoothDevice bluetooth = (BluetoothDevice) mContext.getSystemService(Context.BLUETOOTH_SERVICE); if (bluetooth != null) { mBluetoothEnabled = bluetooth.isEnabled(); } else { mBluetoothEnabled = false; } mBluetoothA2dpState = BluetoothA2dp.STATE_DISCONNECTED; mBluetoothHeadsetState = BluetoothHeadset.STATE_DISCONNECTED; mService.setIconVisibility(mBluetoothIcon, mBluetoothEnabled); // Gps status mGpsEnabledIconData = IconData.makeIcon("gps", null, com.android.internal.R.drawable.stat_sys_gps_acquiring_anim, 0, 0); mGpsFixIconData = IconData.makeIcon("gps", null, com.android.internal.R.drawable.stat_sys_gps_on, 0, 0); mGpsIcon = service.addIcon(mGpsEnabledIconData, null); service.setIconVisibility(mGpsIcon, false); // Alarm clock mAlarmClockIconData = IconData.makeIcon( "alarm_clock", null, com.android.internal.R.drawable.stat_notify_alarm, 0, 0); mAlarmClockIcon = service.addIcon(mAlarmClockIconData, null); service.setIconVisibility(mAlarmClockIcon, false); // Sync state mSyncActiveIcon = service.addIcon(IconData.makeIcon("sync_active", null, R.drawable.stat_notify_sync_anim0, 0, 0), null); mSyncFailingIcon = service.addIcon(IconData.makeIcon("sync_failing", null, R.drawable.stat_notify_sync_error, 0, 0), null); service.setIconVisibility(mSyncActiveIcon, false); service.setIconVisibility(mSyncFailingIcon, false); // volume mVolumeData = IconData.makeIcon("volume", null, com.android.internal.R.drawable.stat_sys_ringer_silent, 0, 0); mVolumeIcon = service.addIcon(mVolumeData, null); service.setIconVisibility(mVolumeIcon, false); updateVolume(); IntentFilter filter = new IntentFilter(); // Register for Intent broadcasts for... filter.addAction(Intent.ACTION_TIME_TICK); filter.addAction(Intent.ACTION_TIME_CHANGED); filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED); filter.addAction(Intent.ACTION_BATTERY_CHANGED); filter.addAction(Intent.ACTION_TIMEZONE_CHANGED); filter.addAction(Intent.ACTION_ALARM_CHANGED); filter.addAction(Intent.ACTION_SYNC_STATE_CHANGED); filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION); filter.addAction(AudioManager.VIBRATE_SETTING_CHANGED_ACTION); filter.addAction(BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION); filter.addAction(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION); filter.addAction(BluetoothA2dp.SINK_STATE_CHANGED_ACTION); filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); filter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION); filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); filter.addAction(WifiManager.RSSI_CHANGED_ACTION); filter.addAction(GpsLocationProvider.GPS_ENABLED_CHANGE_ACTION); filter.addAction(GpsLocationProvider.GPS_FIX_CHANGE_ACTION); filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED); mContext.registerReceiver(mIntentReceiver, filter, null, mHandler); } public static void installIcons(Context context, StatusBarService service) { sInstance = new StatusBarPolicy(context, service); } private final void updateClock() { mCalendar.setTimeInMillis(System.currentTimeMillis()); mClockData.text = DateFormat.getTimeFormat(mContext) .format(mCalendar.getTime()); mService.updateIcon(mClockIcon, mClockData, null); } private final void updateAlarm(Intent intent) { boolean alarmSet = intent.getBooleanExtra("alarmSet", false); mService.setIconVisibility(mAlarmClockIcon, alarmSet); } private final void updateSyncState(Intent intent) { boolean isActive = intent.getBooleanExtra("active", false); boolean isFailing = intent.getBooleanExtra("failing", false); mService.setIconVisibility(mSyncActiveIcon, isActive); // Don't display sync failing icon: BUG 1297963 Set sync error timeout to "never" //mService.setIconVisibility(mSyncFailingIcon, isFailing && !isActive); } private void pickNextBatteryLevel(int level) { final int N = mBatteryThresholds.length; for (int i=0; i<N; i++) { if (level >= mBatteryThresholds[i]) { mBatteryThreshold = i; break; } } if (mBatteryThreshold >= N) { mBatteryThreshold = N-1; } } private final void updateBattery(Intent intent) { mBatteryData.iconId = intent.getIntExtra("icon-small", 0); mBatteryData.iconLevel = intent.getIntExtra("level", 0); mService.updateIcon(mBatteryIcon, mBatteryData, null); boolean plugged = intent.getIntExtra("plugged", 0) != 0; int level = intent.getIntExtra("level", -1); if (false) { Log.d(TAG, "updateBattery level=" + level + " plugged=" + plugged + " mBatteryPlugged=" + mBatteryPlugged + " mBatteryLevel=" + mBatteryLevel + " mBatteryThreshold=" + mBatteryThreshold + " mBatteryFirst=" + mBatteryFirst); } boolean oldPlugged = mBatteryPlugged; int oldThreshold = mBatteryThreshold; pickNextBatteryLevel(level); mBatteryPlugged = plugged; mBatteryLevel = level; if (mBatteryFirst) { mBatteryFirst = false; } /* * No longer showing the battery view because it draws attention away * from the USB storage notification. We could still show it when * connected to a brick, but that could lead to the user into thinking * the device does not charge when plugged into USB (since he/she would * not see the same battery screen on USB as he sees on brick). */ /* else { if (plugged && !oldPlugged) { showBatteryView(); } } */ if (false) { Log.d(TAG, "plugged=" + plugged + " oldPlugged=" + oldPlugged + " level=" + level + " mBatteryThreshold=" + mBatteryThreshold + " oldThreshold=" + oldThreshold); } if (!plugged && ((oldPlugged && level < mBatteryThresholds[BATTERY_THRESHOLD_WARNING]) || (mBatteryThreshold > oldThreshold && mBatteryThreshold > BATTERY_THRESHOLD_WARNING))) { // Broadcast the low battery warning mContext.sendBroadcast(new Intent(Intent.ACTION_BATTERY_LOW)); if (SHOW_LOW_BATTERY_WARNING) { if (false) { Log.d(TAG, "mPhoneState=" + mPhoneState + " mLowBatteryDialog=" + mLowBatteryDialog + " mBatteryShowLowOnEndCall=" + mBatteryShowLowOnEndCall); } if (mPhoneState == TelephonyManager.CALL_STATE_IDLE) { showLowBatteryWarning(); } else { mBatteryShowLowOnEndCall = true; } } } else if (mBatteryThreshold == BATTERY_THRESHOLD_CLOSE_WARNING) { if (SHOW_LOW_BATTERY_WARNING) { if (mLowBatteryDialog != null) { mLowBatteryDialog.dismiss(); mBatteryShowLowOnEndCall = false; } } } } private void showBatteryView() { closeLastBatteryView(); if (mLowBatteryDialog != null) { mLowBatteryDialog.dismiss(); } int level = mBatteryLevel; View v = View.inflate(mContext, com.android.internal.R.layout.battery_status, null); mBatteryView = v; int pixelFormat = PixelFormat.TRANSLUCENT; Drawable bg = v.getBackground(); if (bg != null) { pixelFormat = bg.getOpacity(); } WindowManager.LayoutParams lp = new WindowManager.LayoutParams( ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.TYPE_TOAST, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE | WindowManager.LayoutParams.FLAG_BLUR_BEHIND | WindowManager.LayoutParams.FLAG_DIM_BEHIND, pixelFormat); // Get the dim amount from the theme TypedArray a = mContext.obtainStyledAttributes( com.android.internal.R.styleable.Theme); lp.dimAmount = a.getFloat(android.R.styleable.Theme_backgroundDimAmount, 0.5f); a.recycle(); lp.setTitle("Battery"); TextView levelTextView = (TextView)v.findViewById(com.android.internal.R.id.level_percent); levelTextView.setText(mContext.getString( com.android.internal.R.string.battery_status_text_percent_format, level)); setBatteryLevel(v, com.android.internal.R.id.spacer, 100-level, 0, 0); setBatteryLevel(v, com.android.internal.R.id.level, level, com.android.internal.R.drawable.battery_charge_fill, level); WindowManagerImpl.getDefault().addView(v, lp); scheduleCloseBatteryView(); } private void setBatteryLevel(View parent, int id, int height, int background, int level) { ImageView v = (ImageView)parent.findViewById(id); LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)v.getLayoutParams(); lp.weight = height; if (background != 0) { v.setBackgroundResource(background); Drawable bkg = v.getBackground(); bkg.setLevel(level); } } private void showLowBatteryWarning() { closeLastBatteryView(); int level = mBatteryThresholds[mBatteryThreshold > 1 ? mBatteryThreshold - 1 : 0]; CharSequence levelText = mContext.getString( com.android.internal.R.string.battery_low_percent_format, level); if (mBatteryLevelTextView != null) { mBatteryLevelTextView.setText(levelText); } else { View v = View.inflate(mContext, com.android.internal.R.layout.battery_low, null); mBatteryLevelTextView=(TextView)v.findViewById(com.android.internal.R.id.level_percent); mBatteryLevelTextView.setText(levelText); AlertDialog.Builder b = new AlertDialog.Builder(mContext); b.setCancelable(true); b.setTitle(com.android.internal.R.string.battery_low_title); b.setView(v); b.setIcon(android.R.drawable.ic_dialog_alert); b.setPositiveButton(android.R.string.ok, null); AlertDialog d = b.create(); d.setOnDismissListener(mLowBatteryListener); d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); d.show(); mLowBatteryDialog = d; } } private final void updateCallState(int state) { mPhoneState = state; if (false) { Log.d(TAG, "mPhoneState=" + mPhoneState + " mLowBatteryDialog=" + mLowBatteryDialog + " mBatteryShowLowOnEndCall=" + mBatteryShowLowOnEndCall); } if (mPhoneState == TelephonyManager.CALL_STATE_IDLE) { if (mBatteryShowLowOnEndCall) { if (!mBatteryPlugged) { showLowBatteryWarning(); } mBatteryShowLowOnEndCall = false; } } else { if (mLowBatteryDialog != null) { mLowBatteryDialog.dismiss(); mBatteryShowLowOnEndCall = true; } } } private DialogInterface.OnDismissListener mLowBatteryListener = new DialogInterface.OnDismissListener() { public void onDismiss(DialogInterface dialog) { mLowBatteryDialog = null; mBatteryLevelTextView = null; } }; private void scheduleCloseBatteryView() { Message m = mHandler.obtainMessage(EVENT_BATTERY_CLOSE); m.arg1 = (++mBatteryViewSequence); mHandler.sendMessageDelayed(m, 3000); } private void closeLastBatteryView() { if (mBatteryView != null) { //mBatteryView.debug(); WindowManagerImpl.getDefault().removeView(mBatteryView); mBatteryView = null; } } private PhoneStateListener mPhoneStateListener = new PhoneStateListener() { @Override public void onSignalStrengthChanged(int asu) { mSignalAsu = asu; updateSignalStrength(); } @Override public void onServiceStateChanged(ServiceState state) { mServiceState = state; updateSignalStrength(); updateDataIcon(); } @Override public void onCallStateChanged(int state, String incomingNumber) { updateCallState(state); } @Override public void onDataConnectionStateChanged(int state) { mDataState = state; updateDataNetType(); updateDataIcon(); } @Override public void onDataActivity(int direction) { mDataActivity = direction; updateDataIcon(); } }; private final void updateSimState(Intent intent) { String stateExtra = intent.getStringExtra(SimCard.INTENT_KEY_SIM_STATE); if (SimCard.INTENT_VALUE_SIM_ABSENT.equals(stateExtra)) { mSimState = SimCard.State.ABSENT; } else if (SimCard.INTENT_VALUE_SIM_READY.equals(stateExtra)) { mSimState = SimCard.State.READY; } else if (SimCard.INTENT_VALUE_SIM_LOCKED.equals(stateExtra)) { final String lockedReason = intent.getStringExtra(SimCard.INTENT_KEY_LOCKED_REASON); if (SimCard.INTENT_VALUE_LOCKED_ON_PIN.equals(lockedReason)) { mSimState = SimCard.State.PIN_REQUIRED; } else if (SimCard.INTENT_VALUE_LOCKED_ON_PUK.equals(lockedReason)) { mSimState = SimCard.State.PUK_REQUIRED; } else { mSimState = SimCard.State.NETWORK_LOCKED; } } else { mSimState = SimCard.State.UNKNOWN; } updateDataIcon(); } private final void updateSignalStrength() { int asu = mSignalAsu; ServiceState ss = mServiceState; boolean hasService = true; if (ss != null) { int state = ss.getState(); switch (state) { case ServiceState.STATE_OUT_OF_SERVICE: case ServiceState.STATE_POWER_OFF: hasService = false; break; } } else { hasService = false; } if (!hasService) { //Log.d(TAG, "updateSignalStrength: no service"); if (Settings.System.getInt(mContext.getContentResolver(), Settings.System.AIRPLANE_MODE_ON, 0) == 1) { mPhoneData.iconId = com.android.internal.R.drawable.stat_sys_signal_flightmode; } else { mPhoneData.iconId = com.android.internal.R.drawable.stat_sys_signal_null; } mService.updateIcon(mPhoneIcon, mPhoneData, null); return; } // ASU ranges from 0 to 31 - TS 27.007 Sec 8.5 // asu = 0 (-113dB or less) is very weak // signal, its better to show 0 bars to the user in such cases. // asu = 99 is a special case, where the signal strength is unknown. if (asu <= 0 || asu == 99) asu = 0; else if (asu >= 16) asu = 4; else if (asu >= 8) asu = 3; else if (asu >= 4) asu = 2; else asu = 1; int[] iconList; if (mPhone.isNetworkRoaming()) { iconList = sSignalImages_r; } else { iconList = sSignalImages; } mPhoneData.iconId = iconList[asu]; mService.updateIcon(mPhoneIcon, mPhoneData, null); } private final void updateDataNetType() { mDataNetType = mPhone.getNetworkType(); switch (mDataNetType) { case TelephonyManager.NETWORK_TYPE_EDGE: mDataIconList = sDataNetType_e; break; case TelephonyManager.NETWORK_TYPE_UMTS: mDataIconList = sDataNetType_3g; break; default: mDataIconList = sDataNetType_g; break; } } private final void updateDataIcon() { int iconId; boolean visible = true; if (mSimState == SimCard.State.READY || mSimState == SimCard.State.UNKNOWN) { int data = mDataState; int[] list = mDataIconList; ServiceState ss = mServiceState; boolean hasService = false; if (ss != null) { hasService = (ss.getState() == ServiceState.STATE_IN_SERVICE); } if (hasService && data == TelephonyManager.DATA_CONNECTED) { switch (mDataActivity) { case TelephonyManager.DATA_ACTIVITY_IN: iconId = list[1]; break; case TelephonyManager.DATA_ACTIVITY_OUT: iconId = list[2]; break; case TelephonyManager.DATA_ACTIVITY_INOUT: iconId = list[3]; break; default: iconId = list[0]; break; } mDataData.iconId = iconId; mService.updateIcon(mDataIcon, mDataData, null); } else { visible = false; } } else { mDataData.iconId = com.android.internal.R.drawable.stat_sys_no_sim; mService.updateIcon(mDataIcon, mDataData, null); } long ident = Binder.clearCallingIdentity(); try { mBatteryStats.notePhoneDataConnectionState(mDataNetType, visible); } catch (RemoteException e) { } finally { Binder.restoreCallingIdentity(ident); } if (mDataIconVisible != visible) { mService.setIconVisibility(mDataIcon, visible); mDataIconVisible = visible; } } private final void updateVolume() { AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); final int ringerMode = audioManager.getRingerMode(); final boolean visible = ringerMode == AudioManager.RINGER_MODE_SILENT || ringerMode == AudioManager.RINGER_MODE_VIBRATE; final int iconId = audioManager.shouldVibrate(AudioManager.VIBRATE_TYPE_RINGER) ? com.android.internal.R.drawable.stat_sys_ringer_vibrate : com.android.internal.R.drawable.stat_sys_ringer_silent; if (visible) { mVolumeData.iconId = iconId; mService.updateIcon(mVolumeIcon, mVolumeData, null); } if (visible != mVolumeVisible) { mService.setIconVisibility(mVolumeIcon, visible); mVolumeVisible = visible; } } private final void updateBluetooth(Intent intent) { int iconId = com.android.internal.R.drawable.stat_sys_data_bluetooth; String action = intent.getAction(); if (action.equals(BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION)) { int state = intent.getIntExtra(BluetoothIntent.BLUETOOTH_STATE, BluetoothError.ERROR); mBluetoothEnabled = state == BluetoothDevice.BLUETOOTH_STATE_ON; } else if (action.equals(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION)) { mBluetoothHeadsetState = intent.getIntExtra(BluetoothIntent.HEADSET_STATE, BluetoothHeadset.STATE_ERROR); } else if (action.equals(BluetoothA2dp.SINK_STATE_CHANGED_ACTION)) { mBluetoothA2dpState = intent.getIntExtra(BluetoothA2dp.SINK_STATE, BluetoothA2dp.STATE_DISCONNECTED); } else { return; } if (mBluetoothHeadsetState == BluetoothHeadset.STATE_CONNECTED || mBluetoothA2dpState == BluetoothA2dp.STATE_CONNECTED || mBluetoothA2dpState == BluetoothA2dp.STATE_PLAYING) { iconId = com.android.internal.R.drawable.stat_sys_data_bluetooth_connected; } mBluetoothData.iconId = iconId; mService.updateIcon(mBluetoothIcon, mBluetoothData, null); mService.setIconVisibility(mBluetoothIcon, mBluetoothEnabled); } private final void updateWifi(Intent intent) { final String action = intent.getAction(); if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) { final boolean enabled = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_UNKNOWN) == WifiManager.WIFI_STATE_ENABLED; if (!enabled) { // If disabled, hide the icon. (We show icon when connected.) mService.setIconVisibility(mWifiIcon, false); } } else if (action.equals(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION)) { final boolean enabled = intent.getBooleanExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED, false); if (!enabled) { mService.setIconVisibility(mWifiIcon, false); } } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) { final NetworkInfo networkInfo = (NetworkInfo) intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO); int iconId; if (networkInfo != null && networkInfo.isConnected()) { mIsWifiConnected = true; if (mLastWifiSignalLevel == -1) { iconId = sWifiSignalImages[0]; } else { iconId = sWifiSignalImages[mLastWifiSignalLevel]; } // Show the icon since wi-fi is connected mService.setIconVisibility(mWifiIcon, true); } else { mLastWifiSignalLevel = -1; mIsWifiConnected = false; iconId = sWifiSignalImages[0]; // Hide the icon since we're not connected mService.setIconVisibility(mWifiIcon, false); } mWifiData.iconId = iconId; mService.updateIcon(mWifiIcon, mWifiData, null); } else if (action.equals(WifiManager.RSSI_CHANGED_ACTION)) { final int newRssi = intent.getIntExtra(WifiManager.EXTRA_NEW_RSSI, -200); int newSignalLevel = WifiManager.calculateSignalLevel(newRssi, sWifiSignalImages.length); if (newSignalLevel != mLastWifiSignalLevel) { mLastWifiSignalLevel = newSignalLevel; if (mIsWifiConnected) { mWifiData.iconId = sWifiSignalImages[newSignalLevel]; } else { mWifiData.iconId = sWifiTemporarilyNotConnectedImage; } mService.updateIcon(mWifiIcon, mWifiData, null); } } } private final void updateGps(Intent intent) { final String action = intent.getAction(); final boolean enabled = intent.getBooleanExtra(GpsLocationProvider.EXTRA_ENABLED, false); if (action.equals(GpsLocationProvider.GPS_FIX_CHANGE_ACTION) && enabled) { // GPS is getting fixes mService.updateIcon(mGpsIcon, mGpsFixIconData, null); mService.setIconVisibility(mGpsIcon, true); } else if (action.equals(GpsLocationProvider.GPS_ENABLED_CHANGE_ACTION) && !enabled) { // GPS is off mService.setIconVisibility(mGpsIcon, false); } else { // GPS is on, but not receiving fixes mService.updateIcon(mGpsIcon, mGpsEnabledIconData, null); mService.setIconVisibility(mGpsIcon, true); } } private class StatusBarHandler extends Handler { @Override public void handleMessage(Message msg) { switch (msg.what) { case EVENT_BATTERY_CLOSE: if (msg.arg1 == mBatteryViewSequence) { closeLastBatteryView(); } break; } } } }