和传统终端的状态栏一样,Android状态栏同样提供了电量信息、蜂窝信息、SMS、MMS、邮件、WiFi信号、蓝牙信号、闹钟等系统的状态信息。另外,Android状态栏还提供了应用的安装、数据的下载等智能终端特有的状态信息。除此之外,Android状态栏还承担着通知栏的功能,使用户能以最少的操作查看收到的信息。状态栏的框架如图1-10所示。
在状态栏框架中,起主要作用的是StatusBarPolicy,它承担着接收系统发来的Intent信息、更新状态显示的功能,它是服务StatusBarManagerService的客户端。 StatusBarManagerService在创建时会加载config_statusBarIcons数组。在frameworks\base\core\res\res\values\目录下的config.xml中定义的config_statusBarIcons数组确定了状态图标的加载顺序。
整个状态栏框架是通过StatusBarService来实现的。在StatusBarService初始化时初始化了一个用于显示statusbar 的StatusBarView。在StatusBarView中定义了状态栏的实现布局,而具体的布局文件是在frameworks\base\packages\systemui\res\layout\ status_bar.xml中实现的。
下面介绍状态栏的隐藏及几种重要状态的更新实现。
1. 状态栏的隐藏
通过AndroidManifest.xml设置全屏的方法如下:
<activity android:name="GL2JNIActivity"
android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen">
...
</activity>
下面是通过Java设置全屏的方法:
//将视图设为全屏,隐藏状态栏
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
requestWindowFeature(Window.FEATURE_NO_TITLE); //隐藏标题栏
考虑到在执行onCreate()方法时,已经加载了视图,在通过Java代码实现隐藏状态栏、标题栏时,用户在视觉上可以感受到隐藏的过程。如果不希望用户有这样的感受,可通过AndroidManifest.xml设置全屏。
以上隐藏状态栏的方法只适合静态场景,在隐藏标题栏后再动态显示状态栏已经超出以上两种方法的能力了。此时,可通过下面的方法实现动态隐藏和显示状态栏:
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);//隐藏
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);//显示
2. 电量信息
当StatusBarPolicy收到Action为ACTION_BATTERY_CHANGED的Intent时,StatusBarPolicy会通知StatusBarManager进行电量图标的更新,示例如下:
private final void updateBattery(Intent intent) {
final int id = intent.getIntExtra("icon-small", 0);
int level = intent.getIntExtra("level", 0);
mService.setIcon("battery", id, level);
boolean plugged = intent.getIntExtra("plugged", 0) != 0;
level = intent.getIntExtra("level", -1);
if (false) {
Slog.d(TAG, "updateBattery level=" + level
+ " plugged=" + plugged
+ " mBatteryPlugged=" + mBatteryPlugged
+ " mBatteryLevel=" + mBatteryLevel
+ " mBatteryFirst=" + mBatteryFirst);
}
boolean oldPlugged = mBatteryPlugged;
mBatteryPlugged = plugged;
mBatteryLevel = level;
if (mBatteryFirst) {
mBatteryFirst = false;
}
if (false) {
Slog.d(TAG, "plugged=" + plugged + " oldPlugged=" + oldPlugged + " level=" + level);
}
}
除了Action为ACTION_BATTERY_CHANGED的Intent外,StatusBarPolicy还能响应Action为ACTION_BATTERY_LOW、ACTION_BATTERY_OKAY、ACTION_POWER_CONNECTED的Intent。
3. 蜂窝信息
Android对蜂窝协议的支持十分充分,目前内置的支持包括GSM、UMTS、CDMA、4G等。
4. WiFi信号
对于WiFi信号,Android可以响应Action为WifiManager.NETWORK_STATE_CHANGED_ ACTION、WifiManager.WIFI_STATE_CHANGED_ACTION、WifiManager.RSSI_CHANGED_ ACTION的Intent,相应的更新方法如代码清单1-5所示。
代码清单1-5 WiFi信号的更新
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) {
// 如果WiFi关闭,隐藏WiFi图标
mService.setIconVisibility("wifi", false);
}
} else if (action.equals(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION)) {
final boolean enabled = intent.getBooleanExtra(
WifiManager.EXTRA_SUPPLICANT_CONNECTED,false);
if (!enabled) {
mService.setIconVisibility("wifi", false);
}
} else if (action.equals(WifiManager.RSSI_CHANGED_ACTION)) {
int iconId;
final int newRssi = intent.getIntExtra(WifiManager.EXTRA_NEW_RSSI, -200);
int newSignalLevel = WifiManager.calculateSignalLevel(newRssi, sWifiSignalImages[0].length);
if (newSignalLevel != mLastWifiSignalLevel) {
mLastWifiSignalLevel = newSignalLevel;
if (mIsWifiConnected) {
iconId = sWifiSignalImages[mInetCondition][newSignalLevel];
} else {
iconId = sWifiTemporarilyNotConnectedImage;
}
mService.setIcon("wifi", iconId, 0);
}
}
}
另外,Android还对WiMax提供了内置支持。
5. 蓝牙信号
对于蓝牙信号,Android目前可以响应BluetoothAdapter、BluetoothHeadset、BluetoothA2dp和BluetoothPbap的状态变化,相应的更新方法如代码清单1-6所示。
代码清单1-6 蓝牙信号的更新
private final void updateBluetooth(Intent intent) {
int iconId = R.drawable.stat_sys_data_bluetooth;
String action = intent.getAction();
if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
mBluetoothEnabled = state == BluetoothAdapter.STATE_ON;
} else if (action.equals(BluetoothHeadset.ACTION_STATE_CHANGED)) {
mBluetoothHeadsetState = intent.getIntExtra(
BluetoothHeadset.EXTRA_STATE,BluetoothHeadset.STATE_ERROR);
} else if (action.equals(BluetoothA2dp.ACTION_SINK_STATE_CHANGED)) {
BluetoothA2dp a2dp = new BluetoothA2dp(mContext);
if (a2dp.getConnectedSinks().size() != 0) {
mBluetoothA2dpConnected = true;
} else {
mBluetoothA2dpConnected = false;
}
} else if (action.equals(BluetoothPbap.PBAP_STATE_CHANGED_ACTION)) {
mBluetoothPbapState = intent.getIntExtra(
BluetoothPbap.PBAP_STATE,BluetoothPbap.STATE_DISCONNECTED);
} else {
return;
}
if (mBluetoothHeadsetState == BluetoothHeadset.STATE_CONNECTED || mBluetoothA2dpConnected ||
mBluetoothPbapState == BluetoothPbap.STATE_CONNECTED) {
iconId = R.drawable.stat_sys_data_bluetooth_connected;
}
mService.setIcon("bluetooth", iconId, 0);
mService.setIconVisibility("bluetooth", mBluetoothEnabled);
}
6. 闹钟
当StatusBarPolicy收到Action为ACTION_ALARM_CHANGED的Intent时, StatusBarPolicy会通知StatusBarManager进行闹钟图标的更新,相应示例如下:
private final void updateAlarm(Intent intent) {
boolean alarmSet = intent.getBooleanExtra("alarmSet", false);
mService.setIconVisibility("alarm_clock", alarmSet);
}