1. 程式人生 > >SystemUI之快捷設定區域載入過程分析

SystemUI之快捷設定區域載入過程分析

佈局構成

在這裡插入圖片描述

  • 詳細說明,快捷設定區域的佈局是由 StatusBar.java的 makeStatusBarView ()統一載入,通過方法 inflateStatusBarWindow 方法載入佈局 super_status_bar.xml 。
protected void makeStatusBarView() {
    ......
    inflateStatusBarWindow(context);//載入佈局的方法
    ......
}

protected void inflateStatusBarWindow(Context context) {
    mStatusBarWindow = (StatusBarWindowView) View.inflate(context,
            R.layout.super_status_bar, null);
}
  • super_status_bar.xml 中包含 status_bar_expanded.xml
<include layout="@layout/status_bar_expanded"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:visibility="invisible" />
  • status_bar_expanded.xml 中包含 qs_panel.xml
<FrameLayout
    android:id="@+id/qs_frame"
    android:layout="@layout/qs_panel"
    ...... />
  • qs_panel.xml 中 id 為 quick_settings_panel 即為我們所找的那個 SystemUI 上的快捷設定區域控制元件的 id
<com.android.systemui.qs.QSContainerImpl
    ......
    <com.android.systemui.qs.QSPanel
        android:id="@+id/quick_settings_panel"
        android:layout_marginTop="@dimen/qs_panel_margin_top"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="0dp" />
    ......
</com.android.systemui.qs.QSContainerImpl>

類說明

在這裡插入圖片描述

  • QSTileHost : Host的實現,管理 Tile 狀態的變化。用來建立和監聽 Tile 。
  • Tunable : 介面,配置變化的回撥。QSTileHost 實現這個介面。
  • TunerService :用來監聽各種配置變化。

程式碼控制流程

  • 仍然是從 StatusBar.java的makeStatusBarView() 方法開始
protected void makeStatusBarView() {
......
// Set up the quick settings tile panel
    View container = mStatusBarWindow.findViewById(R.id.qs_frame);//獲取檢視物件
    ......
    final QSTileHost qsh = SystemUIFactory.getInstance().createQSTileHost(mContext, this,
            mIconController);//建立並初始化QSTileHost物件
    ......
        if (qs instanceof QSFragment) {
            ((QSFragment) qs).setHost(qsh);//給QSFragment(QSPanel)設定QSTileHost物件
            mQSPanel = ((QSFragment) qs).getQsPanel();
        }
......
}

  • 一步步分析,首先先例項化一個 View ( qs_frame 包含一個 QSPanel 檢視)物件,然後再去建立 QSTileHost 物件,然後將 QSTileHost 物件與 QSPanel 檢視物件進行繫結,看一下 QSTileHost 的構造方法。

QSTileHost.java

public QSTileHost(Context context, StatusBar statusBar,
        StatusBarIconController iconController) {
    mIconController = iconController;
    mContext = context;
    mStatusBar = statusBar;
    ......
    Dependency.get(TunerService.class).addTunable(this, TILES_SETTING);//使用TunerService去Settings中查詢key為TILES_SETTING的值,即查詢快捷設定選單項
    ......
}

  • 關鍵 Dependency.get(TunerService.class).addTunable(this, TILES_SETTING) ,使用 TunerService 去 Settings 中查詢 key 為 TILES_SETTING 的值,即查詢快捷設定選單項,查詢到的結果通過 onTuningChanged ()方法回撥返回,TunerService 的實現類是 TunerServiceImpl 。

TunerServiceImpl.java

private void addTunable(Tunable tunable, String key) {
    ......
    Uri uri = Settings.Secure.getUriFor(key);
    if (!mListeningUris.containsKey(uri)) {
        mListeningUris.put(uri, key);
        mContentResolver.registerContentObserver(uri, false, mObserver, mCurrentUser);
    }
    // Send the first state.
    String value = Settings.Secure.getStringForUser(mContentResolver, key, mCurrentUser);
    tunable.onTuningChanged(key, value);//查詢到的結果通過onTuningChanged()方法回撥返回
}

  • onTuningChanged 方法的實現在 QSTileHost 中,通過方法 loadTileSpecs 方法將 config.xml 中定義的標籤內容 load 進來,通過 createTile 方法依次根據 xml中 的 String 生成對應的 Tile ,並將 Tile 儲存在成員變數的 mTiles 集合中,最後回撥 onTilesChanged ()方法,通知 QSPanel.java 對快捷設定選項顯示更新。
@Override
public void onTuningChanged(String key, String newValue) {
......
final List<String> tileSpecs = loadTileSpecs(mContext, newValue);//呼叫loadTileSpecs方法將config.xml的內容load進來
......
tile = createTile(tileSpec);//在這裡根據String生成Tile
......
newTiles.put(tileSpec,tile);
......
mTiles.putAll(newTiles);
......

for (int i = 0; i < mCallbacks.size(); i++) {
    mCallbacks.get(i).onTilesChanged();//這裡回撥onTilesChanged()方法,通知StatusBar.java對快捷設定選項顯示更新
}
}

  • onTilesChanged ()方法的實現是在 QSPanel.java 中重寫的, setTiles 方法是對 Tile 進行設定和重新整理的重要方法,下面會詳細說明。
@Override
public void onTilesChanged() {
setTiles(mHost.getTiles());//該方法的作用下面會詳細說明
}

  • 至此 QSTileHost.java 的構造方法分析完成,然後再回到呼叫處 StatusBar.java 的 makeStatusBarView ()方法繼續分析,其中有一個檢視繫結內容(QSTileHost)的語句(( QSFragment ) qs ). setHost ( qsh ),分析完其中的 qsh ,我們繼續分析檢視 qs 。

QSFragment.java

public void setHost(QSTileHost qsh) {
mQSPanel.setHost(qsh, mQSCustomizer);//實質是將QSPanel和qsh繫結
}

QSPanel.java

public void setHost(QSTileHost host, QSCustomizer customizer) {
mHost = host;
mHost.addCallback(this);
setTiles(mHost.getTiles());
}
  • 而其中的 setTiles ()方法是不是很熟悉?它就是之前說到的對 Tile 進行設定和重新整理的重要方法,該方法會先 remove 掉所有的 TileRecord 記錄並移除所有的 tileView ,然後再重新呼叫 addTile ()建立 TileRecord 物件並賦值繫結相應的回撥和點選事件(點選、雙擊、長按)介面,再將其儲存到 ArrayList mRecords 集合中,然後再去 addView ()。
public void setTiles(Collection<QSTile> tiles, boolean collapsedView) {
for (TileRecord record : mRecords) {
mTileLayout.removeTile(record);
record.tile.removeCallback(record.callback);
}
mRecords.clear();
for (QSTile tile : tiles) {
addTile(tile, collapsedView);
}
}
  • 重新呼叫 addTile ()建立 TileRecord 物件並賦值繫結相應的回撥和點選事件(點選、雙擊、長按)介面
protected TileRecord addTile(final QSTile tile, boolean collapsedView) {
final TileRecord r = new TileRecord();
r.tile = tile;
r.tileView = createTileView(tile, collapsedView);
final QSTile.Callback callback = new QSTile.Callback() {
@Override
public void onStateChanged(QSTile.State state) {
drawTile(r, state);
}

@Override
public void onShowDetail(boolean show) {
}

@Override
public void onToggleStateChanged(boolean state) {
}

@Override
public void onScanStateChanged(boolean state) {
}

@Override
public void onAnnouncementRequested(CharSequence announcement) {
}
};
r.tile.addCallback(callback);
r.callback = callback;
r.tileView.init(r.tile);
r.tile.refreshState();
mRecords.add(r);

if (mTileLayout != null) {
mTileLayout.addTile(r);//mTileLayout是layout檢視物件
}

return r;
}

  • 將添加了Tile的檢視物件新增到總檢視中
protected void setupTileLayout() {
mTileLayout = (QSTileLayout) LayoutInflater.from(mContext).inflate(
R.layout.qs_paged_tile_layout, this, false);
mTileLayout.setListening(mListening);
addView((View) mTileLayout);//把檢視加入view
}
  • 至此就完成快捷區域載入顯示的大致流程分析。