狀態欄框架-- 深入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);
}

發佈了33 篇原創文章 · 獲贊 17 · 訪問量 24萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章