1. 程式人生 > >QSTile 的一點變化 Android O 與 Android N 相比

QSTile 的一點變化 Android O 與 Android N 相比

起因

Android O 點選QSPanel 中的資料圖示沒法展開詳情檢視資料使用量,而在Android N 上可以的,所以想調檢視看O 上有什麼不同。
注:本文不涉及任何流程分析,只是單純的想找回個功能,並藉此描述一下O 和N 在tile 上的一點點不同。

現象差異

我們都知道在Android N 上QSTile 有兩種展示形式:
1. QSPanel 半展開是點選icon 即開關,執行的方法為handleSecondaryClick();
2. QSPanel 全展開時,點選icon 有些tile 有detai展示,比如下圖中的wifi tile,此時執行的方法是handleClick(),之後呼叫showDetail() 方法顯示詳細資訊;


但是到了Android O 上變的有點不一樣了:
1. 半展開時點選icon 和Android N 上效果一樣,但執行的方法是handleClick();
2. 全展開時有兩種情況,點選icon還是開關,此時執行的方法也是handleClick();
3. 全展開時點選label 會展示detail(如果有的話),有detail 的tile 在label 旁邊會有一個indicator,而且注意觀察的話,會發現點選icon 和點選label 水波紋的中心會不一樣(如果沒有detail 的話,點選label 也是上一種效果)。此時執行的方法是handleSecondaryClick()



那麼Android O 上是怎麼會有icon 和label 兩種點選事件的呢?

Tile 佈局

我們要想label 可以點選,那我們先看看這個indicator 是怎麼回事,從佈局看起。
找到幾個和tile,layout 相關的類,並沒有發現線索,直到在qs_tile_label.xml 中看到了下面的程式碼:

        <!-- tile label -->
        <TextView
            android:id="@+id/tile_label"
            ...
            android:textAppearance
="@style/TextAppearance.QS.TileLabel" android:textColor="?android:attr/textColorPrimary"/>
<!-- 下面這個暫時不知道是做什麼的 --> <ImageView android:id="@+id/restricted_padlock" ... android:visibility="gone" /> <!-- 像是旁邊的indicator,且預設不可見,懷疑是這個了 --> <ImageView android:id="@+id/expand_indicator" android:layout_marginStart="4dp" android:layout_width="18dp" android:layout_height="match_parent" android:src="@drawable/qs_dual_tile_caret" android:tint="?android:attr/textColorPrimary" android:visibility="gone" />

之後在QSTileView.java 類中找到使用的地方:

    protected void createLabel() {
        mLabelContainer = (ViewGroup) LayoutInflater.from(getContext())
                .inflate(R.layout.qs_tile_label, this, false);
        ...
        mExpandIndicator = mLabelContainer.findViewById(R.id.expand_indicator); // here
        mExpandSpace = mLabelContainer.findViewById(R.id.expand_space);

        addView(mLabelContainer);
    }

以及控制顯示的地方

    @Override
    protected void handleStateChanged(QSTile.State state) {
        super.handleStateChanged(state);
        ...
        mExpandIndicator.setVisibility(state.dualTarget ? View.VISIBLE : View.GONE); // 顯示與否依賴於 state.dualTarget
        mExpandSpace.setVisibility(state.dualTarget ? View.VISIBLE : View.GONE);
        mLabelContainer.setContentDescription(state.dualTarget ? state.dualLabelContentDescription
                : null);
        if (state.dualTarget != mLabelContainer.isClickable()) {
            mLabelContainer.setClickable(state.dualTarget); // 設定是否可以點選
            mLabelContainer.setLongClickable(state.dualTarget);
            mLabelContainer.setBackground(state.dualTarget ? newTileBackground() : null);
        }
        mLabel.setEnabled(!state.disabledByPolicy);
        mPadLock.setVisibility(state.disabledByPolicy ? View.VISIBLE : View.GONE);
    }

可以看到indicator 的顯示受state.dualTarget 的控制。
考慮到另外也有幾個可以展開detail 的tile,比如Bluetooth等,我猜想state.dualTarget 一定會在那幾個tile 裡面賦值為true。我們搜一下,果然:

那我們在CellularTile 對應的位置也給dualTarget 賦值為true 應該就能達到我們最初想要的效果了。

結論和效果

新增state.dualTarget = true; 到CellularTile.java 的handleUpdateState() 方法後,效果如下:

state.dualTarget 控制了是否顯示indicator 以及label 是否可以點選,但點選有沒有反應要看有沒有實現相應的方法了。
點選mobile date 這裡並不是憑空多出來一個功能哈,是我知道有這個功能,只是沒顯示出來。

注:文中程式碼基於mko-mr1,一個基於aosp 的android 8.1 分支。