SystemUI之快捷设置区域QSPanel及点击事件流程分析

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u012966861/article/details/81390874
快捷设置区域的布局是由StatusBar.java的makeStatusBarView()统一加载;
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

<include layout="@layout/status_bar_expanded"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:visibility="invisible" />

status_bar_expanded.xml

<FrameLayout
    android:id="@+id/qs_frame"
    android:layout="@layout/qs_panel"
    android:layout_width="@dimen/qs_panel_width"
    android:layout_height="match_parent"
    android:layout_gravity="@integer/notification_panel_layout_gravity"
    android:clipToPadding="false"
    android:clipChildren="false"
    systemui:viewType="com.android.systemui.plugins.qs.QS" />

qs_panel.xml

<com.android.systemui.qs.QSContainerImpl
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/quick_settings_container"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:elevation="0dp"
    android:clipToPadding="false"
    android:clipChildren="false">

    <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>

见名知意,这个id为quick_settings_panel即为我们所找的那个SystemUI上的快捷设置区域控件的ID;

代码控制方面

仍然是从StatusBar.java的makeStatusBarView()方法开始

protected void makeStatusBarView() {

.......

// Set up the quick settings tile panel
    View container = mStatusBarWindow.findViewById(R.id.qs_frame);//获取视图对象
if (container != null) {
    ......
    final QSTileHost qsh = SystemUIFactory.getInstance().createQSTileHost(mContext, this,
            mIconController);//创建并初始化QSTileHost对象
    mBrightnessMirrorController = new BrightnessMirrorController(mStatusBarWindow,
            mScrimController);
    fragmentHostManager.addTagListener(QS.TAG, (tag, f) -> {
        QS qs = (QS) f;
        if (qs instanceof QSFragment) {
            ((QSFragment) qs).setHost(qsh);
            mQSPanel = ((QSFragment) qs).getQsPanel();
            mQSPanel.setBrightnessMirror(mBrightnessMirrorController);
            mKeyguardStatusBar.setQSPanel(mQSPanel);
        }
    });

.......

}

一步步分析,首先先实例化一个View(qs_frame包含一个QSPanel视图)对象,然后再去创建QSTileHost对象,看一下QSTileHost的构造方法

QSTileHost.java

public QSTileHost(Context context, StatusBar statusBar,
        StatusBarIconController iconController) {
    mIconController = iconController;
    mContext = context;
    mStatusBar = statusBar;

    // M: @ {
    mQuickSettingsExt = OpSystemUICustomizationFactoryBase
            .getOpFactory(context).makeQuickSettings(context);
    // @ }

    mServices = new TileServices(this, Dependency.get(Dependency.BG_LOOPER));

    mQsFactories.add(new QSFactoryImpl(this));
    Dependency.get(PluginManager.class).addPluginListener(this, QSFactory.class, true);

    Dependency.get(TunerService.class).addTunable(this, TILES_SETTING);//使用TunerService去Settings中查询key为TILES_SETTING的值,即查询快捷设置菜单项
    // AutoTileManager can modify mTiles so make sure mTiles has already been initialized.
    mAutoTiles = new AutoTileManager(context, this);
}

关键Dependency.get(TunerService.class).addTunable(this, TILES_SETTING);使用TunerService去Settings中查询key为TILES_SETTING的值,即查询快捷设置菜单项,查询到的结果通过onTuningChanged()方法回调返回;

TunerServiceImpl.java

private void addTunable(Tunable tunable, String key) {
    if (!mTunableLookup.containsKey(key)) {
        mTunableLookup.put(key, new ArraySet<Tunable>());
    }
    mTunableLookup.get(key).add(tunable);
    if (LeakDetector.ENABLED) {
        mTunables.add(tunable);
        Dependency.get(LeakDetector.class).trackCollection(mTunables, "TunerService.mTunables");
    }
    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()方法回调返回
}
public abstract class TunerService {

.......

public interface Tunable {
    void onTuningChanged(String key, String newValue);
}

......

}

QSTileHost实现接口Tunable,实现方法onTuningChanged

@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对快捷设置选项显示更新
    }
}

 

并将其保存在成员变量的mTiles集合中,最后回调onTilesChanged()方法,通知QSPanel.java对快捷设置选项显示更新。

onTilesChanged()方法的实现是在QSPanel.java中重写的:

@Override
public void onTilesChanged() {
    setTiles(mHost.getTiles());
}

至此QSTileHost.java的构造方法分析完成,然后再回到调用处StatusBar.java的makeStatusBarView()方法继续分析:

((QSFragment) qs).setHost(qsh);

QSFragment.java

public void setHost(QSTileHost qsh) {
    mQSPanel.setHost(qsh, mQSCustomizer);//
    mHeader.setQSPanel(mQSPanel);
    mFooter.setQSPanel(mQSPanel);
    mQSDetail.setHost(qsh);
}

QSPanel.java

public void setHost(QSTileHost host, QSCustomizer customizer) {
    mHost = host;
    mHost.addCallback(this);
    setTiles(mHost.getTiles());
}

而其中的setTiles()方法会先remove掉所有的TileRecord记录并移除所有的tileView

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对象并赋值绑定相应的回调和点击事件(点击、双击、长按)接口,再将其保存到ArrayList<TileRecord> mRecords集合中,然后再去addView();

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) {
            // Both the collapsed and full QS panels get this callback, this check determines
            // which one should handle showing the detail.
            if (shouldShowDetail()) {
                QSPanel.this.showDetail(show, r);
            }
        }

        @Override
        public void onToggleStateChanged(boolean state) {
            if (mDetailRecord == r) {
                fireToggleStateChanged(state);
            }
        }

        @Override
        public void onScanStateChanged(boolean state) {
            r.scanState = state;
            if (mDetailRecord == r) {
                fireScanStateChanged(r.scanState);
            }
        }

        @Override
        public void onAnnouncementRequested(CharSequence announcement) {
            if (announcement != null) {
                mHandler.obtainMessage(H.ANNOUNCE_FOR_ACCESSIBILITY, announcement)
                        .sendToTarget();
            }
        }
    };
    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;
}
protected void setupTileLayout() {
    mTileLayout = (QSTileLayout) LayoutInflater.from(mContext).inflate(
            R.layout.qs_paged_tile_layout, this, false);
    mTileLayout.setListening(mListening);
    addView((View) mTileLayout);//把视图加入view
}

猜你喜欢

转载自blog.csdn.net/u012966861/article/details/81390874