Android QS面板源码(下)

简介: Android QS面板源码(下)

二 QS面板内部实现梳理


2.1 QS面板开关集合构建流程


QsPanel 中除了创建各个开关View,还创建了亮度条,Footer等元素,本文重心放在开关的构建上,故不会分析其他元素的创建流程. 另外QsFragment / QSHost 等元素是在 SystemUI 启动流程中通过注入或反射构建的,其前期构建流程跳过分析


先看看整体的流程图


image.png


流程比较简单,对照源码阅读即可.简单说就是QSTileHost对象在构建初期就借助QSFactoryImpl工具对象提前创建好了各个开关的后端对象QSTile,而后QSPanel在初始化的过程中,再次利用QSTileHost去构建各个开关的视图对象QSTileView,至此一个完整的开关就构建完成,最后add到开关容器PagedTileLayout中去.若对上述各个类的作用不清楚的话可回头看看前面对各个类簇的介绍

2.2 Tile后端 是如何与 Tile视图层 产生联系的

前面QSTile的类簇中我们可以看到其有多个内部类,与此相关的内部类包括 Callback 和 State,

[图片上传失败...(image-be33f9-1669866239444)]

Tile 视图与后端的联系就是借助这两个内部类以及QSPanel这个中介产生联系的,我们来看看代码.

前面 2.1小节我们在梳理QS面板开关集合构建流程时可以看到步骤10通过addTile函数来构建Tile开关对象,其代码细节如下

[packages/SystemUI/src/com/android/systemui/qs/QSPanel.java]
    public static final class TileRecord extends Record {
        public QSTile tile;
        public com.android.systemui.plugins.qs.QSTileView tileView;
        public boolean scanState;
        public QSTile.Callback callback;
    }
    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);
            }
            ......
        };
        r.tile.addCallback(callback); // 向开关后端注册回调
        r.callback = callback;
        r.tileView.init(r.tile); // 初始化点击事件
        r.tile.refreshState(); // 首次刷新
        mRecords.add(r);
        mCachedSpecs = getTilesSpecs();
        if (mTileLayout != null) {
            mTileLayout.addTile(r); // add到开关容器
        }
        return r;
    }
    protected void drawTile(TileRecord r, QSTile.State state) {
        r.tileView.onStateChanged(state); // 将变化交给开关视图层
    }

可以看到QSPanelr.tile即后端注册了一个回调器,并在回调发生时将开关状态State传递给r.tileView即开关视图层去做视图刷新.

至于这个State是在哪里刷新的这个我们2.3 小节再分析.

2.3 Tile的一次点击事件背后的流程是怎么样的

前面 2.2 小结介绍addTile函数时我们可以看到这么一句r.tileView.init(r.tile);,这里完成了将视图层的点击事件转交给后端的操作

[packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java]
    @Override
    public void init(QSTile tile) {
        init(v -> tile.click(), v -> tile.secondaryClick(), view -> {
            tile.longClick();
            return true;
        });
    }
    public void init(OnClickListener click, OnClickListener secondaryClick,
            OnLongClickListener longClick) {
        setOnClickListener(click);
        setOnLongClickListener(longClick);
    }

即将QSTileView收到的点击事件分别交给QSTile对应的点击函数处理

[packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java]
    public void click() {
        mHandler.sendEmptyMessage(H.CLICK);
    }
public void handleMessage(Message msg) {
    if (msg.what == CLICK) {
                    if (mState.disabledByPolicy) {
                        ......
                    } else {
                        handleClick();
                    }
                }
}
abstract protected void handleClick();

QSTileImplhandleClick()函数是个抽象方法,分别由对应的开关子类去实现,例如Wifi开关

[packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java]
    @Override
    protected void handleClick() {
        ......
        refreshState(wifiEnabled ? null : ARG_SHOW_TRANSIENT_ENABLING);
        ......
    }

又回到QSTileImpl

[packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java]
    protected final void refreshState(Object arg) {
        mHandler.obtainMessage(H.REFRESH_STATE, arg).sendToTarget();
    }
public void handleMessage(Message msg) {
  if (msg.what == REFRESH_STATE) {
                    handleRefreshState(msg.obj);
                }
}
    protected void handleRefreshState(Object arg) {
        handleUpdateState(mTmpState, arg);
        final boolean changed = mTmpState.copyTo(mState);
        if (changed) {
            handleStateChanged();
        }
        ...
    }
    abstract protected void handleUpdateState(TState state, Object arg);

可以看到QSTileImpl用一个State类型的临时变量去handleUpdateState函数中收集当前开关的最新状态,而这个函数是个抽象方法,实现依旧是在各个开关子类中,我们看下Wifi开关

[packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java]
    protected final void refreshState(Object arg) {
        mHandler.obtainMessage(H.REFRESH_STATE, arg).sendToTarget();
    }
public void handleMessage(Message msg) {
  if (msg.what == REFRESH_STATE) {
                    handleRefreshState(msg.obj);
                }
}
    protected void handleRefreshState(Object arg) {
        handleUpdateState(mTmpState, arg);
        final boolean changed = mTmpState.copyTo(mState);
        if (changed) {
            handleStateChanged();
        }
        ...
    }
    abstract protected void handleUpdateState(TState state, Object arg);

这里抽取了一些代码片段,可以看到开关后端会根据当前开关状态对 state 进行赋值,这些赋值会在后续开关视图刷新时产生作用

handleUpdateState函数收集完开关状态后,我们回到前面

[packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java]
    protected void handleRefreshState(Object arg) {
        handleUpdateState(mTmpState, arg);
        final boolean changed = mTmpState.copyTo(mState);
        if (changed) {
            handleStateChanged();
        }
        ...
    }

可以看到假如开关状态发生了改变则会导致handleStateChanged()被调用

[packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java]
    private void handleStateChanged() {
        if (mCallbacks.size() != 0) {
            for (int i = 0; i < mCallbacks.size(); i++) {
                mCallbacks.get(i).onStateChanged(mState);
            }
        }
    }

这里就和前面 2.2 小节关联起来了,即 state 会被传递到视图层

[packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java]
    public void onStateChanged(QSTile.State state) {
        mHandler.obtainMessage(H.STATE_CHANGED, state).sendToTarget();
    }
    private class H extends Handler {
        private static final int STATE_CHANGED = 1;
        public H() {
            super(Looper.getMainLooper());
        }
        @Override
        public void handleMessage(Message msg) {
            if (msg.what == STATE_CHANGED) {
                handleStateChanged((QSTile.State) msg.obj);
            }
        }
    }

handleStateChanged函数不展开讲,该函数是真正做开关视图显示刷新的地方,细节看源码.


至此,我们就将开关点击背后的流程梳理清楚了,相信阅读完这三条主线的代码流程后,对整个QS面板的整体实现就很清晰了


设计思考


阅读前面 2.3小节的代码我们可以看到,不管是在Tile的逻辑层还是视图层,其内部均通过Handler来组织开关的状态刷新,因为整个QS面板有各种各样的开关,各个开关的刷新时机是不确定的,而通过消息机制则可以有条不紊得将所有开关的刷新有序组织起来,这里体现了Android中很重要的一个特性有序性,这是我们值得借鉴和参考的.

相关文章
|
2月前
|
Ubuntu 开发工具 Android开发
Repo下载AOSP源码:基于ubuntu22.04 环境配置,android-12.0.0_r32
本文介绍了在基于Ubuntu 22.04的环境下配置Python 3.9、安装repo工具、下载和同步AOSP源码包以及处理repo同步错误的详细步骤。
117 0
Repo下载AOSP源码:基于ubuntu22.04 环境配置,android-12.0.0_r32
|
2月前
|
开发工具 git 索引
repo sync 更新源码 android-12.0.0_r34, fatal: 不能重置索引文件至版本 ‘v2.27^0‘。
本文描述了在更新AOSP 12源码时遇到的repo同步错误,并提供了通过手动git pull更新repo工具来解决这一问题的方法。
57 1
|
2月前
|
Android开发 Docker 容器
docker中编译android aosp源码,出现Build sandboxing disabled due to nsjail error
在使用Docker编译Android AOSP源码时,如果遇到"Build sandboxing disabled due to nsjail error"的错误,可以通过在docker run命令中添加`--privileged`参数来解决权限不足的问题。
181 1
|
2月前
|
开发工具 uml git
AOSP源码下载方法,解决repo sync错误:android-13.0.0_r82
本文分享了下载AOSP源码的方法,包括如何使用repo工具和处理常见的repo sync错误,以及配置Python环境以确保顺利同步特定版本的AOSP代码。
169 0
AOSP源码下载方法,解决repo sync错误:android-13.0.0_r82
|
2月前
|
Java Android开发 芯片
使用Android Studio导入Android源码:基于全志H713 AOSP,方便解决编译、编码问题
本文介绍了如何将基于全志H713芯片的AOSP Android源码导入Android Studio以解决编译和编码问题,通过操作步骤的详细说明,展示了在Android Studio中利用代码提示和补全功能快速定位并修复编译错误的方法。
48 0
使用Android Studio导入Android源码:基于全志H713 AOSP,方便解决编译、编码问题
|
2月前
|
Android开发
我的Android 进阶修炼(1): AOSP源码根目录结构
本文介绍了AOSP源码的根目录结构,提供了基于MTK9269 Android 9.0源码的目录说明,帮助读者了解AOSP源码的组织方式和各目录的功能。
64 0
我的Android 进阶修炼(1): AOSP源码根目录结构
|
2月前
|
API 开发工具 Android开发
Android源码下载
Android源码下载
155 0
|
2月前
|
开发工具 Android开发 git
全志H713 Android 11 :给AOSP源码,新增一个Product
本文介绍了在全志H713 Android 11平台上新增名为myboard的产品的步骤,包括创建新的device目录、编辑配置文件、新增内核配置、记录差异列表以及编译kernel和Android系统的详细过程。
37 0
|
2月前
|
Ubuntu 开发工具 Android开发
Repo下载、编译AOSP源码:基于Ubuntu 21.04,android-12.1.0_r27
文章记录了作者在Ubuntu 21.04服务器上配置环境、下载并编译基于Android 12.1.0_r27版本的AOSP源码的过程,包括解决编译过程中遇到的问题和错误处理方法。
56 0
|
3月前
|
JavaScript Java 测试技术
基于springboot+vue.js+uniapp的高校后勤网上报修系统安卓app附带文章源码部署视频讲解等
基于springboot+vue.js+uniapp的高校后勤网上报修系统安卓app附带文章源码部署视频讲解等
40 0
下一篇
无影云桌面