状态栏框架-- 深入Android应用开发:核心技术解析与最佳实践


和传统终端的状态栏一样,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);
}

展开阅读全文

没有更多推荐了,返回首页