1. 程式人生 > >SystemUI 建立 Tile 流程, 新增Tile

SystemUI 建立 Tile 流程, 新增Tile

system UI預置的(QSTile),第三方應用新增的(CustiomTile  7.0 才有的)

一、 建立自定義的Tile

 


二、Tile載入流程

Tile中方法
handleClick() 短按
getLongClickIntent() 長按
handleUpdateState() 更新狀態
handleSecondaryClick() 點選開關label顯示詳情頁
getToggleState() 若返回null詳情頁不顯示switch開關。
getSettingsIntent() 跟長按的intent一樣進入設定對應的介面。若返回null詳情頁不顯示詳細資訊。

(1)    動作的監聽響應:
       在handleClick() 方法裡處理點選事件;開啟/關閉的動畫也在這裡呼叫;
     部分開關需要重寫handleSecondaryClick() 方法,例如Wi-Fi和藍芽開關,在handleSecondaryClick() 方法裡開啟詳情頁面;
     還有開關需要重寫handleLongClick() ,例如反色和熱點開關,在這裡開啟詢問是否要隱藏的對話方塊;
     在setListening() 方法裡添加回調監聽,接受action和註冊廣播等。

(2)    狀態的管理:
      狀態管理通過一個由Host提供的looper來進行。
          每個快捷開關在handleUpdateState()中更新狀態。回撥影響狀態要通過快捷開關的工作looper呼叫refreshState() 來觸發另一個狀態更新。
     
          狀態類有三種,State類以及繼承自State類的BooleanState類和SignalState類。需要判斷開關與否的狀態的快捷開關繼承QSTile<QSTile.BooleanState>,
      包括飛航模式、反色、手電筒、熱點、定位、自動旋轉、藍芽和螢幕投射開關等;還需要判斷連線等狀態的快捷開關繼承QSTile<QSTile.SignalState>,例如Wi-Fi和移動資料網路開關;其他直接繼承QSTile<QSTile.State>。
    (3)    另外,Wi-Fi和藍芽開關需要重寫supportsDualTargets() 方法和getDetailAdapter() 方法。因為這兩個開關是繪製在一排兩個開關的佈局上而且需要顯示詳情頁面。


QSTile:快速設定Tile的基類,快速設定都繼承自這個類。
Tile通過過載handleUpdateState方法來更新狀態。如果監聽到狀態變化,或者點選事件需要更新狀態,使用refreshState來更新State。 
QSTileHost: Host的實現,管理Tile 狀態的變化。它包含各種Tile的Control類,用來設定和監聽Tile。 
State: Tile的狀態,包含圖示,名稱等資訊。 
H:繼承自Handler, 通過looper跑在QSTileHost的執行緒裡。用來處理Tile的各種事件。 
Tunable: 介面,配置變化的回撥。QSTileHost實現這個介面。 
TunerSercice:用來監聽各種配置變化。

 

介面的分析          
               QuickStatusBarHeader  -- QuickQSPanel(其中載入 HeaderTileLayout) (NUM_QUICK_TILES = "sysui_qqs_count" 第一次下拉顯示時,顯示的tile數量)                      
QSContainer -- 
           QSPanel  全部的位置

之前在   statusbar 的載入中已經寫到了
createQSTileHost() --> SystenUIFactory.QSTileHost() --> QSTileHost.addTunable() 
TunerService.addTunable的方法,會監聽ContentProvider中的Tile的變化
private void addTunable(Tunable tunable, String key) {
        if (!mTunableLookup.containsKey(key)) {
            mTunableLookup.put(key, new ArraySet<Tunable>());
        }
        mTunableLookup.get(key).add(tunable);
        Uri uri = Settings.Secure.getUriFor(key);
        if (!mListeningUris.containsKey(uri)) {
            mListeningUris.put(uri, key);
            //listening for the tile change
            mContentResolver.registerContentObserver(uri, false, mObserver, mCurrentUser);
        }
        // Send the first state.
        String value = Settings.Secure.getStringForUser(mContentResolver, key, mCurrentUser);
    //回撥 onTuningChanged, 當tile 建立,變化時
        tunable.onTuningChanged(key, value);
    }

在QSPanel的addTile中, TileRecord就是一個普通的類(當成javabean就好)包含tile view data callback

QSPanel
HeaderTileLayout的add Tile方法,
protected void addTile(final QSTile<?> tile, boolean collapsedView) {
        final TileRecord r = new TileRecord();
        r.tile = tile;
        r.tileView = createTileView(tile, collapsedView);
    //callback
        final QSTile.Callback callback = new QSTile.Callback() {
        ...
    ...
        r.tile.addCallback(callback);
        r.callback = callback;
    //onclick
        final View.OnClickListener click = new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                onTileClick(r.tile);
            }
        };
    //onlongclick
        final View.OnLongClickListener longClick = new View.OnLongClickListener() {
            @Override
            public boolean onLongClick(View v) {
                r.tile.longClick();
                return true;
            }
        };
        r.tileView.init(click, longClick);
        r.tile.refreshState();
        //全部都給mRecords塞進去
    mRecords.add(r);
        if (mTileLayout != null) {
            mTileLayout.addTile(r);
        }
}

QSTile 的觸控點選
QSTileView  extends QSTileBaseView extends QSTileView extends LinearLayout
點選事件的塞入,實際是在  QSTileBaseView.init()  和 QSTileView.init() 方法中
setOnClickListener();
setOnLongClickListener();


QSTileImpl extends QSTile 
QSTileImpl.click()/QSTileImpl.secondaryClick() --> handler senMessage H.CLICK/REDERSH/SHOW_DETAIL  -->  handMessage/handleShowDetail/ 抽象方法 --> 實現類的


每個QSTile的子類都可以過載handleSecondaryClick方法,來區別未展開和展開的Tile點選事件。
所以,點選QuickQSPanel的Tile介面,執行的是 --> handleSecondaryClick。 

QSPanel的點選事件流程。觸發點選事件後,執行QSTile的handleClick方法,refreshState或0showDetail。 
    
    refreshState的流程,QSTile的子類,要在這裡更新Tile的State 
  QSTile.Callback的onShowDetail

  
2.longClick事件
  長按事件也是在QSPanl的addTile方法裡建立的,
    最後會執行到handleLongClick的方法在這裡會從getLongClickIntent裡面,獲取一個Intent, 啟動該Intent的activity。
    getLongClickIntent 在每個tile具體類中實現