【安卓13-Framework】SystemUI定制之屏蔽下拉状态栏部分快捷按钮

news2024/10/7 12:27:07

1、需求

屏蔽下拉状态栏谷歌录屏、省电模式、二维码扫描器等快捷按钮。

2、修改路径

普及:安卓的SystemUI包提供了状态栏、导航栏、通知中心等重要的用户界面元素。
状态栏小部件UI显示修改路径:frameworks/base/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java

3、修改思路

下拉状态栏属于系统UI的一部分,位于SystemUI包下,不同安卓版本这个包的代码有些许出入,但是万变不离其宗,掌握修改原理即可,下面来一步步分析如何修改以及为什么要这样修改:

(1)修改方法

打开这个文件:frameworks/base/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java,定位到这个方法:
在这里插入图片描述
这个方法做了两件事,第一件事是加载“存货”(Stock tiles),什么是存货呢,就是安卓原生自带的小部件,比如WiFi、蓝牙、定位等快捷按钮,第二件事是加载工程师自定义的小部件(Custom tiles),在这里我们先不研究自定义的小部件,以后有时间再研究。
既然是加载“存货”,那这些存货从哪里来呢,先不看这个,我先把修改代码放出来,若不想研究原理可不看后面,修改代码如下:

    @Nullable
    protected QSTileImpl createTileInternal(String tileSpec) {
        // Stock tiles.
        if (mTileMap.containsKey(tileSpec)
                // We should not return a Garbage Monitory Tile if the build is not Debuggable
                && (!tileSpec.equals(GarbageMonitor.MemoryTile.TILE_SPEC) || Build.IS_DEBUGGABLE)) {
            //屏蔽下拉状态栏中的几个tile,返回空对象
            Set<String> multipleStrings = new HashSet<>();
            multipleStrings.add("screenrecord"); //谷歌录屏
            multipleStrings.add("battery");  // 省电模式
            multipleStrings.add("qr_code_scanner"); // 二维码扫描器
            if (multipleStrings.contains(tileSpec)) {
                return null;
            }
            return mTileMap.get(tileSpec).get();
        }

        // Custom tiles
        if (tileSpec.startsWith(CustomTile.PREFIX)) {
            return CustomTile.create(
                    mCustomTileBuilderProvider.get(), tileSpec, mQsHostLazy.get().getUserContext());
        }

        // Broken tiles.
        Log.w(TAG, "No stock tile spec: " + tileSpec);
        return null;
    }

好了,结束!

nonono,开个玩笑,接下来讲解原理,因为有些版本不是这样改的,待会就知道了。

(2)修改原理

首先我们知道,谷歌的代码写的都是很优雅的,想完全看懂不容易,这里我们只啃一部分,那就是下拉状态栏那些快捷按钮(QS tile)是如何添加的。
首先我们观察SystemUI目录,里面有很多子目录,大部分都是每一个模块细化出来,比如WiFi相关UI放在一个目录,声音UI放一个目录,目录里面基本都是写小模块的具体实现。

而qs目录就是专门负责实现通知栏或状态栏这个面板的各种功能和交互效果,比如图标的显示、动画效果、点击事件的处理等。
这里我们主要看qs目录,该目录结构如图:
在这里插入图片描述
其中,QSContainerImpl.java 这个类作为下拉状态栏快速面板的布局承载各种View,QSTileHost.java类是个接口实现类,里面实现了对tile的增删改查操作:
在这里插入图片描述
例如,我们想移除谷歌相机,同样可以在布局初始化处调用removeTile方法:

    @Override
    public void removeTile(String spec) {
        if (spec.startsWith(CustomTile.PREFIX)) {
            // If the tile is removed (due to it not actually existing), mark it as removed. That
            // way it will be marked as newly added if it appears in the future.
            setTileAdded(CustomTile.getComponentFromSpec(spec), mCurrentUser, false);
        }
        mMainExecutor.execute(() -> changeTileSpecs(tileSpecs-> tileSpecs.remove(spec)));
    }

传入一个字符串“screenrecord”,关于怎么知道各个组件的键值,后面会讲。
注意,调用这个方法只能移除原生自带的一些组件键值,addTile(String spec) 这个方法也是只能创建自带的组件。
接下来回到上面修改的实现类QSFactoryImpl.java里面看它是如何移除谷歌相机的,首先,这个mTileMap是一个map 集合,里面加载了所有的谷歌原生tile键值
在这里插入图片描述
我们看下这个map 是从哪里传递过来的,在这里插入图片描述
看到是通过构造方法传递,继续找哪里调用这个构造方法
在这里插入图片描述
在这个类里面,我们看到tileMap在这里传递了进来,看一下tileMap的结构

        val tileMap = mutableMapOf<String, Provider<QSTileImpl<*>>>(
            "internet" to Provider { internetTile },
            "bt" to Provider { bluetoothTile },
            "dnd" to Provider { dndTile },
            "inversion" to Provider { colorInversionTile },
            "airplane" to Provider { airplaneTile },
            "work" to Provider { workTile },
            "rotation" to Provider { rotationTile },
            "flashlight" to Provider { flashlightTile },
            "location" to Provider { locationTile },
            "cast" to Provider { castTile },
            "hotspot" to Provider { hotspotTile },
            "battery" to Provider { batterySaverTile },
            "saver" to Provider { dataSaverTile },
            "night" to Provider { nightDisplayTile },
            "nfc" to Provider { nfcTile },
            "dark" to Provider { darkModeTile },
            "screenrecord" to Provider { screenRecordTile },
            "reduce_brightness" to Provider { reduceBrightColorsTile },
            "cameratoggle" to Provider { cameraToggleTile },
            "mictoggle" to Provider { microphoneToggleTile },
            "controls" to Provider { deviceControlsTile },
            "alarm" to Provider { alarmTile },
            "wallet" to Provider { quickAccessWalletTile },
            "qr_code_scanner" to Provider { qrCodeScannerTile },
            "onehanded" to Provider { oneHandedModeTile },
            "color_correction" to Provider { colorCorrectionTile },
            "dream" to Provider { dreamTile },
            "font_scaling" to Provider { fontScalingTile }
        )

这段代码是 Kotlin 语言编写的,它定义了一个名为 tileMap 的可变映射(MutableMap)。这个映射的键是字符串类型(String),而值是 Provider<QSTileImpl<*>> 类型。Provider 是 Dagger 框架中的一个接口,它代表了一个对象的延迟提供者,即当需要时才会创建该对象。以**“screenrecord” to Provider { screenRecordTile },**为例,这个screenrecord键值映射了一个provider,当请求screenrecord键时,会返回一个screenRecordTile对象,这个对象就是谷歌录屏这个按钮的实体,实现了谷歌录屏这个快捷按钮的一些行为,比如点击录制,停止录制等。
我们回到创建过程看
在这里插入图片描述
在创建过程时加入过滤集合,将不需要显示的快捷按钮的键值加到set中,如果集合包含要创建的tile,就返回一个空对象,上面对对象判空,如果为空,则不会创建tile。

明白了创建原理,改起来就很简单了,比如在安卓其他版本,这个实现类并不是这样写的
在这里插入图片描述
这里这个实现类是直接在当前类根据tile标识返回对应的实体

    @Nullable
    protected QSTileImpl createTileInternal(String tileSpec) {
        // Stock tiles.
        switch (tileSpec) {
            case "wifi":
                return mWifiTileProvider.get();
            case "internet":
                return mInternetTileProvider.get();
            case "bt":
                return mBluetoothTileProvider.get();
            /*case "cell":
                return mCellularTileProvider.get();*/
            case "dnd":
                return mDndTileProvider.get();
            case "inversion":
                return mColorInversionTileProvider.get();
            case "airplane":
                return mAirplaneModeTileProvider.get();
            /*case "work":
                return mWorkModeTileProvider.get();
            case "rotation":
                return mRotationLockTileProvider.get();
            case "flashlight":
                return mFlashlightTileProvider.get();
            case "location":
                return mLocationTileProvider.get();*/
            case "cast":
                return mCastTileProvider.get();
            case "hotspot":
                return mHotspotTileProvider.get();
            /*case "battery":
                return mBatterySaverTileProvider.get();
            case "saver":
                return mDataSaverTileProvider.get();
            case "night":
                return mNightDisplayTileProvider.get();
            case "nfc":
                return mNfcTileProvider.get();
            case "dark":
                return mUiModeNightTileProvider.get();*/
            /*case "screenrecord":
                return mScreenRecordTileProvider.get();*/
            /*case "reduce_brightness":
                return mReduceBrightColorsTileProvider.get();
            case "cameratoggle":
                return mCameraToggleTileProvider.get();
            case "mictoggle":
                return mMicrophoneToggleTileProvider.get();*/
            case "controls":
                return mDeviceControlsTileProvider.get();
            /*case "alarm":
                return mAlarmTileProvider.get();
            case "wallet":
                return mQuickAccessWalletTileProvider.get();
            case "qr_code_scanner":
                return mQRCodeScannerTileProvider.get();
            case "onehanded":
                return mOneHandedModeTileProvider.get();*/
            case "color_correction":
                return mColorCorrectionTileProvider.get();
            /*case "dream":
                return mDreamTileProvider.get();*/
        }

        // Custom tiles
        if (tileSpec.startsWith(CustomTile.PREFIX)) {
            return CustomTile.create(
                    mCustomTileBuilderProvider.get(), tileSpec, mQsHostLazy.get().getUserContext());
        }

        // Debug tiles.
        /*if (Build.IS_DEBUGGABLE) {
            if (tileSpec.equals(GarbageMonitor.MemoryTile.TILE_SPEC)) {
                return mMemoryTileProvider.get();
            }
        }*/

        // Broken tiles.
        Log.w(TAG, "No stock tile spec: " + tileSpec);
        return null;
    }

这种也很简单,直接注释掉不要的tile即可,这个版本的实现类写的稍微就没那么优雅了,但是基本原理都一样。
好了,先写到这里。

3、总结

系统下拉状态栏包含的内容还是很多的,目前只分析了如何移除快捷按钮,继续刨析还可以实现增加自定义的按钮,不过得遵循谷歌的一套做法,再深入了解还可以美化状态栏,这些就留给以后去慢慢分析了。

共勉:分享知识,共同进步!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1624803.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

政安晨:【Keras机器学习示例演绎】(十七)—— 用于图像分类的 RandAugment 可提高鲁棒性

目录 导入与设置 加载 CIFAR10 数据集 定义超参数 初始化 RandAugment 对象 创建 TensorFlow 数据集对象 可视化使用 RandAugment 增强的数据集 可视化使用 simple_aug 增强的数据集 定义模型构建实用功能 使用 RandAugment 训练模型 用 simple_aug 训练模型 加载 C…

Rime 如何通过 iCloud 实现词库多端同步,Windows、iOS、macOS

Rime 如何通过 iCloud 实现词库多端同步&#xff0c;Windows、iOS、macOS 一、设备环境 最理想的输入环境就是在多端都使用同一个词库&#xff0c;这样能保持多端的输入习惯是一致的。 以我为例&#xff0c;手头每天都要用到的操作平台和对应的输入法&#xff1a; 操作系统设…

Spring Boot | Spring Boot “自定义“ Redis缓存 “序列化机制“

目录: Spring Boot "自定义" Redis缓存 "序列化机制" &#xff1a;一、基于 "注解" 的 "Redis缓存管理" 的 "默认序列化机制" 和 "自定义序列化机制"1.1 基于 "注解" 的 "Redis缓存管理" 的 …

抽象代理模式2.0版本

前言&#xff1a; 1.0版本的核心 代理的定义 A proxy, in its most general form, is a class functioning as an interface to something else. The proxy could interface to anything: a network connection, a large object in memory, a file, or some other resource t…

金融级国产化替代中间件有哪些?

过去&#xff0c;国内中间件市场一直由IBM、Oracle等国际大型企业所主导&#xff0c;这在一定程度上限制了对国内企业多样化和个性化需求的满足&#xff0c;尤其是在实现底层硬件与上层应用软件之间高效、精准匹配方面。面对日益复杂的国际局势&#xff0c;金融安全已成为国家整…

akSmart大带宽服务器基础配置科普

在数字化时代&#xff0c;服务器的性能和网络带宽成为业务发展的关键因素。RakSmart作为知名的服务器提供商&#xff0c;其大带宽服务器备受用户青睐。那么&#xff0c;RakSmart大带宽服务器的基础配置究竟有哪些呢?本文将为您揭开这一神秘面纱。 首先&#xff0c;我们来看看R…

【基于YOLOv8的教室人脸识别 附源码 数据集】

基于YOLOv8的教室人脸识别 附源码 数据集 在当今数字化迅速发展的教育领域中&#xff0c;人脸识别技术已成为提高校园安全和教学效率的关键工具。本文将详细介绍基于最新YOLOv8算法的教室人脸识别系统&#xff0c;这一系统不仅能够实时准确地识别学生和教职工的面部特征&#…

【QT】ROS2 Humble联合使用QT教程

【QT】ROS2 Humble联合使用QT教程 文章目录 【QT】ROS2 Humble联合使用QT教程1. 安装ROSProjectManager插件2. 创建ROS项目3.一个快速体验的demoReference 环境的具体信息如下&#xff1a; ubunt 22.04ros2 humbleQt Creator 13.0.0ROS ProjectManager 13.0.0 本文建立在已经…

【A-034】基于SSH的电影订票系统(含论文)

【A-034】基于SSH的电影订票系统&#xff08;含论文&#xff09; 开发环境&#xff1a; Jdk7(8)Tomcat7(8)MySQLIntelliJ IDEA(Eclipse) 数据库&#xff1a; MySQL 技术&#xff1a; SpringStruts2HiberanteJSPJquery 适用于&#xff1a; 课程设计&#xff0c;毕业设计&…

MacOS通过命令行开启关闭向日葵远程控制的后台服务

categories: [Tips] tags: MacOS Tips 写在前面 经常有小伙伴问我电脑相关的问题, 而解决问题的一个重要途径就是远程了. 关于免费的远程工具我试过向日葵和 todesk, 并且主要使用向日葵, 虽然 MacOS 下要设置很多权限, 但是也不影响其丝滑的控制. 虽然用着舒服, 但是向日葵…

【Elasticsearch<一>✈️✈️】简单安装使用以及各种踩坑

目录 &#x1f378;前言 &#x1f37b;一、软件安装&#xff08;Windows版&#xff09; 1.1、Elasticsearch 下载 2.1 安装浏览器插件 3.1、安装可视化工具 Kibana 4.1、集成 IK 分词器 &#x1f37a;二、安装问题 &#x1f379;三、测试 IK 分词器 ​&#x1f377; 四、章…

高端制造企业生产设备文件管理,怎样保证好用不丢失文件?

高端制造业在市场经济中占据重要角色&#xff0c;在高端制造业企业内部&#xff0c;生产设备又是最关键的一环环&#xff0c;它们不仅负责完成生产任务&#xff0c;同时也会产生大量的文件。这些数据反映了设备的运行状态、生产效率、能源消耗以及产品质量等多个方面&#xff0…

Delta模拟器:iOS上的复古游戏天堂

Delta模拟器&#xff1a;iOS上的复古游戏天堂 在数字时代&#xff0c;我们有时会怀念起那些早期的电子游戏&#xff0c;它们简单、纯粹&#xff0c;带给我们无尽的乐趣。虽然现在的游戏在画质和玩法上都有了巨大的提升&#xff0c;但那种复古的感觉却始终无法替代。幸运的是&a…

科技云报道:走入商业化拐点,大模型“开箱即用”或突破行业困局

科技云报道原创。 大模型加速狂飙&#xff0c;AI商业化却陷入重重困境。 一方面&#xff0c;传统企业不知道怎么将AI融入原始业务&#xff0c;另一方面&#xff0c;AI企业难以找到合适的商业化路径。 纵观海外AI玩家&#xff0c;已经有许多企业趟出了自己的商业化道路。 微…

C#从入门到精通:一场深入浅出的编程之旅【文末送书】

文章目录 C#从入门到精通入门篇进阶篇精通篇模式探索C#从入门到精通&#xff08;第7版&#xff09;&#xff08;软件开发视频大讲堂&#xff09;【文末送书】 C#从入门到精通 在当今数字化的时代&#xff0c;编程已经成为一项至关重要的技能。而在众多编程语言中&#xff0c;C…

人工智能|深度学习——多模态条件机制 Cross Attention 原理及实现

一、引入 虽然之前写过 Attention 的文章&#xff0c;但现在回头看之前写的一些文章&#xff0c;感觉都好啰嗦&#xff0c;正好下一篇要写的 Stable Diffusion 中有 cross-attention&#xff0c;索性就再单拎出来简单说一下 Attention 吧&#xff0c;那么这篇文章的作用有两个&…

微软在汉诺威工业博览会上推出新制造业Copilot人工智能功能,强化Dynamics 365工具集

在近日于德国汉诺威举行的盛大工业博览会上&#xff0c;微软向全球展示了其最新推出的制造业人工智能功能&#xff0c;这些功能以Dynamics 365工具集为核心&#xff0c;旨在通过先进的AI技术为制造业带来前所未有的变革。 此次推出的新功能中&#xff0c;最为亮眼的是支持AI的…

python 中使用 ESP8266 实现语音识别(或热词检测)

介绍 我的大部分家庭自动化都是通过对网络中的设备执行 HTTP 请求来控制的。 (例如:开灯、打开收音机、控制加热系统...... 这可以使用ESP8266轻松完成。我有一个控制器和一个触摸传感器,当我在床上时用它来控制灯光和音乐。 像 Amazon Echo 或 Google Homepod 一样添加语…

【Qt QML】TabBar的用法

Qt Quick中的TabBar提供了一个基于选项卡的导航模型。TabBar由TabButton控件填充&#xff0c;并且可以与任何提供currentIndex属性的布局或容器控件一起使用&#xff0c;例如StackLayout或SwipeView。 import QtQuick import QtQuick.Controls import QtQuick.LayoutsWindow …

【论文阅读】Self-DC:何时检索,何时生成?

对于RAG来说&#xff0c;什么时候利用外部检索&#xff0c;什么时候使用大模型产生已知的知识&#xff0c;以回答当前的问题?这是一个非常有趣的话题。 《Self-DC: When to retrieve and When to generate? Self Divide-and-Conquer for Compositional Unknown Questions》这…