SystemUI下拉框新增音量控制条

news2024/11/15 17:57:57

Android产品下拉框一直只有亮度条没有音量控制条。 为了方便控制音量,普遍都是底部导航栏添加音量加减按钮,在Android10以后,大家普遍用上了手势导航,去掉底部导航栏。 目前需要再下拉框中可以直接控制音量。

文章目录

  • 前言
  • 需求及效果
  • 基础必备
    • 修改文件:
  • 修改说明
    • 去掉长按亮度条不隐藏QSPanel
    • 新增音量进度条到QS面板,放到亮度进度条下方
      • 几个相关类引入
      • 简要对部分类的简单分析
        • BrightnessSlider
        • BrightnessSlider
        • QSPanelController
          • 创建mBrightnessSlider 变量的创建:
          • setBrightnessView
  • 实现方案
    • 布局
    • 构造控制器并绑定View
    • 业务
      • StatusBar
      • StatusBarPhoneModule
      • QSPanel QSPanelController
      • 其它相关类
  • 资源


前言

在Android12平台,QS 面板上,亮度控制条下面添加音量条,方便控制音量。

需求及效果

Android12 版本

  1. RK和MTK平台在下拉框QS面板中,亮度条的下方新增音量条控制器 亮度条长按不隐藏QS面板
  2. 亮度条长按不隐藏QS面板

在这里插入图片描述

在这里插入图片描述

基础必备

SystemUI 相关知识,务必做到基本流程了解、概念、架构、布局,方便实现基础功能和理解业务修改。
参考资料:截屏功能添加中的SystemUI基础描述

#修改说明
详细说明如下,参考修改文件和新增文件即可完成功能,实现需求

修改文件:

vendor/mediatek/proprietary/packages/apps/SystemUI/AndroidManifest.xml
vendor/mediatek/proprietary/packages/apps/SystemUI/src/com/android/systemui/classifier/Classifier.java
vendor/mediatek/proprietary/packages/apps/SystemUI/src/com/android/systemui/qs/QSAnimator.java
vendor/mediatek/proprietary/packages/apps/SystemUI/src/com/android/systemui/qs/QSPanel.java
vendor/mediatek/proprietary/packages/apps/SystemUI/src/com/android/systemui/qs/QSPanelController.java
vendor/mediatek/proprietary/packages/apps/SystemUI/src/com/android/systemui/settings/brightness/BrightnessController.java
vendor/mediatek/proprietary/packages/apps/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSlider.java
vendor/mediatek/proprietary/packages/apps/SystemUI/src/com/android/systemui/settings/brightness/ToggleSlider.java
vendor/mediatek/proprietary/packages/apps/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
vendor/mediatek/proprietary/packages/apps/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java

`

## 新增文件:

```java
vendor/mediatek/proprietary/packages/apps/SystemUI/res/drawable-hdpi/icon_volume_test.png
vendor/mediatek/proprietary/packages/apps/SystemUI/res/drawable-mdpi/icon_volume_test.png
vendor/mediatek/proprietary/packages/apps/SystemUI/res/drawable-xhdpi/icon_volume_test.png
vendor/mediatek/proprietary/packages/apps/SystemUI/res/drawable-xxhdpi/icon_volume_test.png
vendor/mediatek/proprietary/packages/apps/SystemUI/res/drawable-xxxhdpi/icon_volume_test.png
vendor/mediatek/proprietary/packages/apps/SystemUI/res/drawable/ic_volume.xml
vendor/mediatek/proprietary/packages/apps/SystemUI/res/drawable/volume_progress_drawable.xml
vendor/mediatek/proprietary/packages/apps/SystemUI/res/drawable/volume_progress_full_drawable.xml
vendor/mediatek/proprietary/packages/apps/SystemUI/res/layout/quick_settings_volume_dialog.xml
vendor/mediatek/proprietary/packages/apps/SystemUI/src/com/android/systemui/settings/volume/
vendor/mediatek/proprietary/packages/apps/SystemUI/src/com/android/systemui/util/ApplicationContextProvider.kt
vendor/mediatek/proprietary/packages/apps/SystemUI/src/com/android/systemui/util/ContextProvider.java
vendor/mediatek/proprietary/packages/apps/SystemUI/src/com/android/systemui/util/SoundUtils.kt

修改说明

修改说明详细文档,方便理解

去掉长按亮度条不隐藏QSPanel

  com.android.systemui.statusbar.policy.BrightnessMirrorController  亮度条镜控制器
	com.android.systemui.settings.brightness.BrightnessSliderSeekBar.OnSeekBarChangeListener回调方法中
	屏蔽mirrorController 的相关回调控制
	具体代码如下:
	 private final SeekBar.OnSeekBarChangeListener mSeekListener =
            new SeekBar.OnSeekBarChangeListener() {
        @Override
        public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
            if (mListener != null) {
                mListener.onChanged(mTracking, progress, false);
            }
        }

        @Override
        public void onStartTrackingTouch(SeekBar seekBar) {
            mTracking = true;

            if (mListener != null) {
                mListener.onChanged(mTracking, getValue(), false);
            }
            /*if (mMirrorController != null) {
                mMirrorController.showMirror();
                mMirrorController.setLocationAndSize(mView);
            }*/
        }

        @Override
        public void onStopTrackingTouch(SeekBar seekBar) {
            mTracking = false;
            if (mListener != null) {
                mListener.onChanged(mTracking, getValue(), true);
            }
            /*if (mMirrorController != null) {
                mMirrorController.hideMirror();
            }*/
        }
    };

新增音量进度条到QS面板,放到亮度进度条下方

实现方案,参考源码中亮度条实现的方式实现

几个相关类引入

com.android.systemui.settings.brightness 包下

     BrightnessController.java   :对外的控制器 BrightnessController implements ToggleSlider.Listener   
	 BrightnessSlider.java       : 本质上也是一个View,带了ViewController控制器,extends    ViewController<BrightnessSliderView> implements ToggleSlider
	 ToggleSlider.java           : 定义进度条控制器的接口,如:进度条变化回调 onChanged、setMax、getMax、getValue、setValue
     BrightnessDialog.java       :显示音量的Activity,里面加载的是Dialog,源码暂未使用  
	 BrightnessSliderView.java   :SeekBar的根布局文件,包裹ToggleSeekBarView,本质是一个FrameLayout 布局
	 ToggleSeekBar.java          :SeekBar 

简要对部分类的简单分析

BrightnessSlider

中的Factory类,来构造BrightnessSlider, 这里面加载了布局 quick_settings_brightness_dialog,
在上面已经描述 这个BrightnessSlider 本质就是一个带控制器ViewController的view

 public static class Factory {

        private final FalsingManager mFalsingManager;

        @Inject
        public Factory(FalsingManager falsingManager) {
            mFalsingManager = falsingManager;
        }

        /**
         * Creates the view hierarchy and controller
         *
         * @param context a {@link Context} to inflate the hierarchy
         * @param viewRoot the {@link ViewGroup} that will contain the hierarchy. The inflated
         *                 hierarchy will not be attached
         */
        public BrightnessSlider create(Context context, @Nullable ViewGroup viewRoot) {
            int layout = getLayout();
            BrightnessSliderView root = (BrightnessSliderView) LayoutInflater.from(context)
                    .inflate(layout, viewRoot, false);
            return new BrightnessSlider(root, mFalsingManager);
        }

        /** Get the layout to inflate based on what slider to use */
        private int getLayout() {
            return R.layout.quick_settings_brightness_dialog;
        }
    }
BrightnessSlider
 类的Factory类,来构造BrightnessController

     /** Factory for creating a {@link BrightnessController}. */
    public static class Factory {
        private final Context mContext;
        private final BroadcastDispatcher mBroadcastDispatcher;

        @Inject
        public Factory(Context context, BroadcastDispatcher broadcastDispatcher) {
            mContext = context;
            mBroadcastDispatcher = broadcastDispatcher;
        }

        /** Create a {@link BrightnessController} */
        public BrightnessController create(ToggleSlider toggleSlider) {
            return new BrightnessController(mContext, toggleSlider, mBroadcastDispatcher);
        }
    }

重点关注构造方法中传递了一个ToggleSlider参数,如果传递ToggleSlider 实现类,那么就实现了控制器和view 的绑定。
控制器中可以通过传递过来的view 来控制view 的各种状态和设置内容。 追踪一下这块创建和添加view 地方:
BrightnessController-> createcreate(ToggleSlider toggleSlider)

QSPanelController

调用地方:QSPanelController 构造方法中:*

        mBrightnessSliderFactory = brightnessSliderFactory;
        //通过factory里的create方法生成
        mBrightnessSlider = mBrightnessSliderFactory.create(getContext(), mView);
        //mView就是上边的QSPanel,可以看到,亮度条是动态添加到容器里的
        mView.setBrightnessView(mBrightnessSlider.getRootView());
        //通过factory里的create方法生成
        mBrightnessController = brightnessControllerFactory.create(mBrightnessSlider);
创建mBrightnessSlider 变量的创建:
mBrightnessSlider = mBrightnessSliderFactory.create(getContext(), mView);
	-> BrightnessSlider 的create 方法
	 /**
         * Creates the view hierarchy and controller
         *
         * @param context a {@link Context} to inflate the hierarchy
         * @param viewRoot the {@link ViewGroup} that will contain the hierarchy. The inflated
         *                 hierarchy will not be attached
         */
        public BrightnessSlider create(Context context, @Nullable ViewGroup viewRoot) {
            int layout = getLayout();
            BrightnessSliderView root = (BrightnessSliderView) LayoutInflater.from(context)
                    .inflate(layout, viewRoot, false);
            return new BrightnessSlider(root, mFalsingManager);
        }

return 返回的不就是创建的它的视线的子类吗?BrightnessSliderView
这样就间接实现了 对外Brightness 控制器BrightnessController 和 view 对应BrightnessSliderView 的绑定。

setBrightnessView
关注另外一个点:
	mView.setBrightnessView(mBrightnessSlider.getRootView());
	QSPanelController 里面的mView 肯定是QSPanel, setBrightnessView 又是做什么的呢? 且看代码
	
	 /**
     * Add brightness view above the tile layout.
     *
     * Used to add the brightness slider after construction.
     */
    public void setBrightnessView(@NonNull View view) {
        if (mBrightnessView != null) {
            removeView(mBrightnessView);
            mMovableContentStartIndex--;
        }
        addView(view, 0);
        mBrightnessView = view;
        setBrightnessViewMargin();
        mMovableContentStartIndex++;
    }

就是在QS面板里面添加View,这个地方就是QS 、QQS 相关的核心思想,根布局下面的子布局,都是通过add 添加进去的。

实现方案

实现方案和思想,完全参考亮度进度条的实现方案,故必须对SystemUI有所了解,且对亮度条控制亮度流程、思想比较熟悉,照抄照搬!
几个类的定义,实现volume 控制条,创建几个volume 调节相关的类,

    com/android/systemui/settings/volume/	  
	VolumeController.java 
	VolumeSlider.java
	VolumeSliderView.java
	和对应的布局文件quick_settings_volume_dialog

布局

quick_settings_volume_dialog 完整版本如下:其中SeekBar 完全延用brightness中的ToggleSeekBar
 <com.android.systemui.settings.volume.VolumeSliderView
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/brightness_slider"
        android:layout_width="match_parent"
        android:layout_height="@dimen/brightness_mirror_height"
        android:layout_gravity="center"
        android:contentDescription="@string/accessibility_brightness"
        android:importantForAccessibility="no" >

        <com.android.systemui.settings.brightness.ToggleSeekBar
            android:id="@+id/slider"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:minHeight="48dp"
            android:thumb="@null"
            android:background="@null"
            android:paddingStart="0dp"
            android:paddingEnd="0dp"
            android:progressDrawable="@drawable/volume_progress_drawable"
            android:splitTrack="false"
        />
    </com.android.systemui.settings.volume.VolumeSliderView>

构造控制器并绑定View

        QSPanelController 类中,构建View并构建管理view控制器 Control,同时绑定View

        mVolumeSliderFactory = volumeSliderFactory;
        mVolumeSlider = mVolumeSliderFactory.create(getContext(), mView);
        mView.setVolumeView(mVolumeSlider.getRootView());
        mVolumeController = volumeControllerFactory.create(mVolumeSlider);

业务

StatusBar

构造方法中,构建 VolumeSlider.Factory mVolumeSliderFactory,通过注解构造方法实现,其实就是加载View,布局就加载出来了

StatusBarPhoneModule

StatusBarPhoneModule.java 中,生成的StatusBar的, 也是在这里,加载传递VolumeSlider 给StatusBar 的,具体实现方式完全通过Dragger注解来实现。

  /**
     * Provides our instance of StatusBar which is considered optional.
     */
    @Provides
    @SysUISingleton
    static StatusBar provideStatusBar(
	....
	VolumeSlider.Factory volumeSliderFactory,
	....
	){
	  return new StatusBar(
	    ...
		volumeSliderFactory,
		...
	  );
	};

QSPanel QSPanelController

QSPanel QSPanelController 去掉相关的BrightnessMirrorController[镜像控制条,需求一种已经去掉这个类 或者 暂时无用就屏蔽掉]
同时分析,亮度条和进度条是怎么添加到了QSPanel 中去的

  • QSPanel 中添加brightnessSeekView 和 volumSeekView 并设置margin
 public void setVolumeView(@NonNull View view) {
		Log.d(TAG,"setVolumeView");
        if (mVolumeView != null) {
            removeView(mVolumeView);
            mMovableContentStartIndex--;
        }
        addView(view, 1);
        mVolumeView = view;
        setVolumeViewMargin();
        mMovableContentStartIndex++;
		//view.setVisibility(TunerService.parseIntegerSwitch(newValue, true) ? VISIBLE : GONE);
		
    }
    private void setVolumeViewMargin() {
        if (mVolumeView != null) {
            MarginLayoutParams lp = (MarginLayoutParams) mVolumeView.getLayoutParams();
            lp.topMargin = mContext.getResources()
                    .getDimensionPixelSize(R.dimen.qs_brightness_margin_top);
            lp.bottomMargin = mContext.getResources()
                    .getDimensionPixelSize(R.dimen.qs_brightness_margin_bottom);
            mVolumeView.setLayoutParams(lp);
        }
    }
  • QSPanelController
    QSPanelController 类中,构建View并构建管理view控制器 Control
        mVolumeSliderFactory = volumeSliderFactory;
        mVolumeSlider = mVolumeSliderFactory.create(getContext(), mView);
        mView.setVolumeView(mVolumeSlider.getRootView());
        mVolumeController = volumeControllerFactory.create(mVolumeSlider);  

其它相关类

    com.android.systemui.util  目录下几个类:
 	SoundUtils.kt                   :自定义音量控制工具,将15级别音量调整为100级别,方便展示更加细腻化 
    ContextProvider.java  ApplicationContextProvider.kt           :和ApplicationContextProvider 一起,提供全局的Context支持,在AndroidManifest.xml中配置    
 <!-- Add a Provider to get Application in Project. -->
        <provider
            android:name="com.android.systemui.util.ApplicationContextProvider"
            android:authorities="com.android.systemui.contextprovider"
            android:exported="false"
            android:grantUriPermissions="true">
   </provider>	

资源

RK Android12 SystemUI SystemUI源码方便调试
资源实现源码待RK平台集成后,晚些释放。

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

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

相关文章

Git使用方法(三)---简洁版上传git代码

1 默认已经装了sshWindows下安装SSH详细介绍-CSDN博客 2 配置链接github的SSH秘钥 1 我的.ssh路径 2 进入路径cd .ssh 文件 3 生成密钥对 ssh-keygen -t rsa -b 4096 (-t 秘钥类型 -b 生成大小) 输入完会出现 Enter file in which to save the key (/c/Users/Administrator/…

webrtc学习笔记3

Nodejs实战 对于我们WebRTC项目而言&#xff0c;nodejs主要是实现信令服务器的功能&#xff0c;客户端和服务器端的交互我们选择websocket作为通信协议&#xff0c;所以以websocket的使用为主。 web客户端 websocket WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行…

IIS发布打包后文件

1.打开IIS软件 2 添加网站&#xff0c; 自定义网站名称-选择要放置的资源路径-选择IP地址 3.打开放置的资源目录放置打包后文件 4.选择浏览 搜索不到IIS可进行一下操作 控制面板-程序和功能-启用或关闭windows功能-勾选IIS

Axios请求使用params参数导致后端获取数据嵌套

问题重述&#xff1a; 首先看前端的axios请求这里我使用params参数将data数据传给后端 let data JSON.stringify(this.posts);axios.post("/blog_war_exploded/insertPost", {params: {data: data}}).then((res) > {if (res.data "success") {alert(…

在Windows11强制开启copilot

在 Windows 11 上启用自带的基于 GPT-4 的 Copilot 功能。以下是具体步骤&#xff1a; 更新系统&#xff1a; 确保你的 Windows 11 系统已经更新到最新版本&#xff08;23H2 或更高版本&#xff09;。你可以在“设置” > “Windows 更新”中检查并安装最新更新。 更改区域和…

盒子模型

1. 盒子模型&#xff08;Box Model&#xff09;组成 2.边框&#xff08;border&#xff09; 表格的细线边框 边框会影响盒子实际大小 3.内边距&#xff08;padding&#xff09; 内边距会影响盒子实际大小 应用场景---导航栏&#xff08;不设宽高度&#xff09; 4.外边距&#x…

并发系统的 CSP+PAT 形式化建模与验证方法(以Kafka系统为例)

消息队列中间件是分布式系统的重要组成部分。它允许应用程序仅关注数据本身&#xff0c;而无需关心数据传输的具体细节。这一特性有效解决了消息异步传输、应用程序解耦以及流量削峰等问题。Kafka是一个开源的分布式消息系统&#xff0c;它基于发布-订阅模型构建。Kafka具有低延…

软考高级:数据库- 候选键、主键、外键

在数据库设计中&#xff0c;候选键、主键和外键是三个非常重要的概念。为了更好地理解它们&#xff0c;我们可以用通俗的例子来帮助说明。 通俗示例 假设我们在一个学校里管理学生的信息。每个学生都有一个独一无二的学号、名字、身份证号和手机号。这些信息都可以用来唯一标…

Cat1智能电表:技术优势与应用注意事项

Cat.1(Category1)智能电表&#xff0c;作为新一代智能计量解决方案&#xff0c;其核心优势在于低功耗广域网络(LPWAN)技术的应用&#xff0c;特别是4GLTECat.1蜂窝网络标准的集成。这不仅提升了数据传输的稳定性和安全性&#xff0c;还优化了远程管理能力&#xff0c;为电力行业…

WPF打印控件内容

当我们想打印控件内容时&#xff0c;如一个Grid中的内容&#xff0c;可以用WPF中PrintDialog类的PrintVisual()方法来实现 界面如下&#xff1a; XAML代码如下 <Grid><Grid.ColumnDefinitions><ColumnDefinition/><ColumnDefinition Width"300"…

haproxy实验-2

haproxy中的算法 静态算法&#xff1a;按照事先定义好的规则轮询公平调度&#xff0c;不关心后端服务器的当前负载、连接数和响应速度 等&#xff0c;且无法实时修改权重(只能为0和1,不支持其它值)&#xff0c;只能靠重启HAProxy生效。 static-rr&#xff1a;基于权重的轮询…

如何将本地组件库上传到npm上

如何把本地开发的组件发布到npm上面&#xff0c;我们需要去了解vue封装组件的原理&#xff0c;利用vue.use(plugin)这个api, 我们需要把封装好的组件打包成vue库&#xff0c;并提供install方法发布到npm上去&#xff0c;Vue.use(plugin)自动执行插件中的install方法。 我们在这…

建立一个能高效记录、整理编程心得,又易检索、回顾的编程笔记系统

构建一个既高效记录编程心得又便于快速回顾的编程笔记系统至关重要。此系统不仅是知识管理的基石&#xff0c;还能显著提升学习效率&#xff0c;确保在关键时刻迅速获取所需信息。 基于我超过十年的软件编程、项目管理及项目运维的深厚经验&#xff0c;我深刻体会到&#xff0c…

[000-01-030].第3节 :搭建Zookeeper集群环境

1.搭建Zookeeper集群环境 1.1.集群安装&#xff1a; a.集群规划&#xff1a; 在 hadoop103(192.168.2.3)、hadoop104(192.168.2.4) 和 hadoop105&#xff08;(192.168.2.5&#xff09; 三个节点上都部署 Zookeeper b.解压安装&#xff1a; 1.下载zookeeper压缩版本&#x…

文件批量上传,oss使用时间戳解决同名问题 以及一些sql bug

1.文件批量上传 ApiOperation(value "文件批量上传")PostMapping("/multipleImageUpload")Transactional(rollbackFor Exception.class)public Result multipleImageUpload(ApiParam(name "files",value "文件",required true) R…

2024新型数字政府综合解决方案(六)

新型数字政府综合解决方案通过融合人工智能、大数据、区块链和云计算技术&#xff0c;构建了一个全方位智能化的政务平台&#xff0c;旨在提升政府服务的效率、透明度和公众参与度。该方案实现了跨部门的数据互联互通与实时更新&#xff0c;利用先进的数据分析和自动化处理技术…

38-PCB布局实战实战及优化

1.先对布局好的器件进行锁定 1.根据模块化布局 2.电容尽量靠近ic附近&#xff0c;可以起到很好的滤波效果 3.复位按键尽量摆在容易按键的地方&#xff0c;比如周围 。。。。 最后进行对齐

KubeSphere 社区双周报| 2024.08.02-08.15

KubeSphere 社区双周报主要整理展示新增的贡献者名单和证书、新增的讲师证书以及两周内提交过 commit 的贡献者&#xff0c;并对近期重要的 PR 进行解析&#xff0c;同时还包含了线上/线下活动和布道推广等一系列社区动态。 本次双周报涵盖时间为&#xff1a;2024.08.02-08.15…

机器学习(2)-- KNN算法之手写数字识别

KNN算法 KNN&#xff08;K-Nearest Neighbor&#xff0c;K最近邻&#xff09;算法是一种用于分类和回归的非参数统计方法&#xff0c;尤其在分类问题中表现出色。在手写数字识别领域&#xff0c;KNN算法通过比较测试样本与训练样本之间的距离&#xff0c;找到最近的K个邻居&am…

智能监控,无忧仓储:EasyCVR视频汇聚+AI智能分享技术为药品仓库安全保驾护航

随着科技的飞速发展&#xff0c;药品仓库的安全管理正迎来前所未有的变革。药品作为直接关系到公众健康的重要物资&#xff0c;其安全存储和监管显得尤为重要。在这个背景下&#xff0c;视频汇聚平台EasyCVR视频智能管理系统的应用&#xff0c;为药品仓库的安全监管提供了强有力…