aosp13/14/15/16如何实现窗口局部区域高斯模糊毛玻璃效果及Winscope原生重大bug发现

Android 窗口模糊处理 在 Android 12 中,我们提供了一些用于实现窗口模糊处理效果(例如背景模糊处理和模糊处理后方屏幕)的公共 API。窗口模糊处理或跨窗口模糊处理用于模糊处理给定窗口后方的屏幕。有两种窗口模糊处理方式,可用于实现不同的视觉效果:背景模糊处理:可用于创建具有模糊背景的窗口,创造出磨砂玻璃效果。模糊处理后方屏幕:可用于模糊处理(对话框)窗口后方的整个屏幕,创造出景深效果。仅背景模糊处理 (a)、仅模糊处理后方屏幕 (b)、背景模糊处理和模糊处理后方屏幕 (c) 阅读详情

背景:

关于aosp高版本系统自带的高斯模糊我们之前已经分享过相关的实战文章,具体可以点击如下链接:

android13 FLAG_BLUR_BEHIND 壁纸高斯模糊,毛玻璃背景方案设计-千里马framework实战

壁纸模糊前:
在这里插入图片描述

壁纸模糊后:
在这里插入图片描述
但是上面分享模糊都是针对整个窗口进行的,就是桌面窗口设置一下后面窗口进行模糊的标志位,然后针对桌面窗口后面的壁纸窗口进行整体模糊。

但是学员们又提出新的需求,他想要的是局部模糊,需求如下:
在这里插入图片描述

简单说学员就是想实现对状态栏等区域局部进行高斯模糊,以前方案是针对窗口layer所有进行模糊,那么是否可以实现窗口的局部高斯模糊呢?
那么接下来要去探索aosp原生系统是否有接口支持局部高斯模糊呢?

SurfaceFlinger高斯接口代码探索:

以前高斯模糊原理也分析过,知道是在SurfaceFlinger触摸绘制时候进行的高斯模糊,那么再来分析一下高斯模糊相关实现时候是否有相关区域设置参数,从而反推出相关接口。
frameworks/native/libs/renderengine/skia/SkiaGLRenderEngine.cpp

void SkiaGLRenderEngine::drawLayersInternal(
        const std::shared_ptr<std::promise<RenderEngineResult>>&& resultPromise,
        const DisplaySettings& display, const std::vector<LayerSettings>& layers,
        const std::shared_ptr<ExternalTexture>& buffer, const bool /*useFramebufferCache*/,
        base::unique_fd&& bufferFence) {
  //省略
    if (mBlurFilter) {
        bool requiresCompositionLayer = false;
        for (const auto& layer : layers) {
            // if the layer doesn't have blur or it is not visible then continue
            if (!layerHasBlur(layer, ctModifiesAlpha)) {  //这里会判断layer是否有高斯模糊
                continue;
            }
            //判断1就是backgroundBlurRadius,就是之前一直用的
            if (layer.backgroundBlurRadius > 0 &&
                layer.backgroundBlurRadius < mBlurFilter->getMaxCrossFadeRadius()) {
                requiresCompositionLayer = true;
            }
             //判断2这个之前没了解过,看着明显blurRegions就是有一个模糊区域数组,这里其实就是我们突破口
            for (auto region : layer.blurRegions) {
                if (region.blurRadius < mBlurFilter->getMaxCrossFadeRadius()) {
                    requiresCompositionLayer = true;
                }
            }
            if (requiresCompositionLayer) {
                activeSurface = dstSurface->makeSurface(dstSurface->imageInfo());
                canvas = mCapture->tryOffscreenCapture(activeSurface.get(), &offscreenCaptureState);
                blurCompositionLayer = &layer;//这里赋值模糊的layer给blurCompositionLayer变量
                break;
            }
        }
    }
//省略
    for (const auto& layer : layers) {
     //省略
        sk_sp<SkImage> blurInput;
        //这里就是核心
        if (blurCompositionLayer == &layer) {
            LOG_ALWAYS_FATAL_IF(activeSurface == dstSurface);
            LOG_ALWAYS_FATAL_IF(canvas == dstCanvas);

            // save a snapshot of the activeSurface to use as input to the blur shaders
            blurInput = activeSurface->makeImageSnapshot();

            // blit the offscreen framebuffer into the destination AHB, but only
            // if there are blur regions. backgroundBlurRadius blurs the entire
            // image below, so it can skip this step.
            if (layer.blurRegions.size()) {
                SkPaint paint;
                paint.setBlendMode(SkBlendMode::kSrc);
                if (CC_UNLIKELY(mCapture->isCaptureRunning())) {
                    uint64_t id = mCapture->endOffscreenCapture(&offscreenCaptureState);
                    dstCanvas->drawAnnotation(SkRect::Make(dstCanvas->imageInfo().dimensions()),
                                              String8::format("SurfaceID|%" PRId64, id).c_str(),
                                              nullptr);
                    dstCanvas->drawImage(blurInput, 0, 0, SkSamplingOptions(), &paint);
                } else {
                    activeSurface->draw(dstCanvas, 0, 0, SkSamplingOptions(), &paint);
                }
            }

            // assign dstCanvas to canvas and ensure that the canvas state is up to date
            canvas = dstCanvas;
            surfaceAutoSaveRestore.replace(canvas);
            initCanvas(canvas, display);

            LOG_ALWAYS_FATAL_IF(activeSurface->getCanvas()->getSaveCount() !=
                                dstSurface->getCanvas()->getSaveCount());
            LOG_ALWAYS_FATAL_IF(activeSurface->getCanvas()->getTotalMatrix() !=
                                dstSurface->getCanvas()->getTotalMatrix());

            // assign dstSurface to activeSurface
            activeSurface = dstSurface;
        }

        SkAutoCanvasRestore layerAutoSaveRestore(canvas, true);
        if (CC_UNLIKELY(mCapture->isCaptureRunning())) {
            // Record the name of the layer if the capture is running.
            std::stringstream layerSettings;
            PrintTo(layer, &layerSettings);
            // Store the LayerSettings in additional information.
            canvas->drawAnnotation(SkRect::MakeEmpty(), layer.name.c_str(),
                                   SkData::MakeWithCString(layerSettings.str().c_str()));
        }
        // Layers have a local transform that should be applied to them
        canvas->concat(getSkM44(layer.geometry.positionTransform).asM33());

        const auto [bounds, roundRectClip] =
                getBoundsAndClip(layer.geometry.boundaries, layer.geometry.roundedCornersCrop,
                                 layer.geometry.roundedCornersRadius);
        if (mBlurFilter && layerHasBlur(layer, ctModifiesAlpha)) {
            std::unordered_map<uint32_t, sk_sp<SkImage>> cachedBlurs;

            // if multiple layers have blur, then we need to take a snapshot now because
            // only the lowest layer will have blurImage populated earlier
            if (!blurInput) {
                blurInput = activeSurface->makeImageSnapshot();
            }
            // rect to be blurred in the coordinate space of blurInput
            const auto blurRect = canvas->getTotalMatrix().mapRect(bounds.rect());

            // if the clip needs to be applied then apply it now and make sure
            // it is restored before we attempt to draw any shadows.
            SkAutoCanvasRestore acr(canvas, true);
            if (!roundRectClip.isEmpty()) {
                canvas->clipRRect(roundRectClip, true);
            }

            // TODO(b/182216890): Filter out empty layers earlier
            if (blurRect.width() > 0 && blurRect.height() > 0) {
                if (layer.backgroundBlurRadius > 0) {
                    ATRACE_NAME("BackgroundBlur");
                    auto blurredImage = mBlurFilter->generate(grContext, layer.backgroundBlurRadius,
                                                              blurInput, blurRect);

                    cachedBlurs[layer.backgroundBlurRadius] = blurredImage;

                    mBlurFilter->drawBlurRegion(canvas, bounds, layer.backgroundBlurRadius, 1.0f,
                                                blurRect, blurredImage, blurInput);
                }

                canvas->concat(getSkM44(layer.blurRegionTransform).asM33());
                for (auto region : layer.blurRegions) {
                    if (cachedBlurs[region.blurRadius] == nullptr) {
                        ATRACE_NAME("BlurRegion");
                        //明显看到这里会传递相关的模糊区域参数
                        cachedBlurs[region.blurRadius] =
                                mBlurFilter->generate(grContext, region.blurRadius, blurInput,
                                                      blurRect);
                    }

                    mBlurFilter->drawBlurRegion(canvas, getBlurRRect(region), region.blurRadius,
                                                region.alpha, blurRect,
                                                cachedBlurs[region.blurRadius], blurInput);
                }
            }
        }
//省略
    return;
}

从SurfaceFlinger的模糊实现来看,确实有layer.blurRegions可以控制相关图层layer的区域模糊。

最后根据这个layer.blurRegions线索一路追踪发现上层其实有现成的接口可以进行设置。
frameworks/base/core/java/android/view/SurfaceControl.java


        /**
         * Specify what regions should be blurred on the {@link SurfaceControl}.
         *
         * @param sc SurfaceControl.
         * @param regions List of regions that will have blurs.
         * @return itself.
         * @see BlurRegion#toFloatArray()
         * @hide
         */
        public Transaction setBlurRegions(SurfaceControl sc, float[][] regions) {
            checkPreconditions(sc);
            nativeSetBlurRegions(mNativeObject, sc.mNativeObject, regions, regions.length);
            return this;
        }

所以完全可以通过这个接口来进行实现

代码实现成果展示

这里以桌面作为demo,针对桌面的上部分500像素局部区域进行模糊,这样可以明显区分出来是否模糊生效。

核心代码如下:

在这里插入图片描述需要完整patch的学员可以私聊马哥
成果展示:
先看看没有模糊时候壁纸
在这里插入图片描述

代码模糊上面500像素后最后效果如下:

在这里插入图片描述

Winscope重大bug发现

上面确实调用了setBlurRegions是有效果的,本来想通过Winscope来再次验证一下,但是发现如下情况:
在这里插入图片描述
这里是啥情况?为啥Winscope显示这个BlurRegions是个空,明明我们现象看都发现成功了,这里就刚好把这个Winscope的重大bug留个学员们探索的一个作业了哈。

学员朋友们尝试看看是否可以修复android这个重大的原生bug,大家先尝试自己探索修复,实在搞不出来,更多答案及修复方案马哥到时候可能会分享群里哈。

更多framework实战开发干货,请关注下面“千里马学框架”

AOSP 13-16窗口局部模糊实战:SurfaceFlinger BlurRegion与Winscope调试陷阱 Android系统定制中,毛玻璃这类细节需求常被低估。要实现窗口局部区域的高斯模糊,应用层RenderEffect或截图方案都无法满足实时合成要求,真正可靠的路径是借助SurfaceFlinger的BlurRegion能力。作为合成器级的隐藏API,BlurRegion允许在指定矩形区域对layer背后的内容进行实时模糊,但也带来坐标基准、系统签名、跨版本兼容等工程挑战。从AOSP 13到16,其数据结构与解析逻辑持续演进,开发者需小心处理坐标转换与Transaction资源释放。此外,Winscope在解 阅读详情

相关推荐

Android窗口毛玻璃BlurRegion与SurfaceFlinger实战

模糊效果是现代UI设计中的重要视觉手段,高斯模糊作为一种基础图像算法,广泛用于背景虚化与层次营造。在Android系统中,要实现窗口局部区域的实时毛玻璃效果,仅靠View层模糊远远不够,必须深入系统合成链路。BlurRegion作为SurfaceFlinger提供的核心机制,允许开发者精确指定窗口中的矩形区域进行背景模糊,并与前景半透明层实时混合,从而实现与窗口内容同步的动态模糊效果。该机制在Android 13至16各版本间存在差异,开发者需要结合WindowManager、SurfaceControl以

weixin_26843605的博客 236

Android12窗口模糊(一)在Activity和Dialog中实现高斯模糊效果

介绍Android12如何实现高斯模糊的效果

AfinalStone的专栏 2万+

Android12窗口模糊(二)在WindowManager的addView方法添加的视图中实现高斯模糊效果

通过Android12系统源码具体分析高斯模糊API的底层实现逻辑

AfinalStone的专栏 1万+

android 窗口级模糊实现方式

请注意,窗口级模糊效果可能会对性能产生一定的影响,特别是在较低的设备上。因此,在使用时应谨慎考虑效果和性能之间的平衡,并进行适当的性能优化。无论你选择哪种方式,都需要确保在 AndroidManifest.xml 中提供。

diannao720的博客 2423

数据集分享 | IWR1642呼吸心跳数据集

雷达开源数据库 数据集

【调皮连续波】雷达技术领域知识博主 3205

一文讲透什么是ADC/DAC中的DDC、DUC、采样率以及数据率等概念

摘要:ADC/DAC中的采样率与数据率概念不同,采样率是转换器的时钟速率,而数据率是数字输出的实际速率。抽取通过滤波降低数据速率,提升信噪比但牺牲带宽;内插则通过插零和滤波提高采样率,将镜像信号移远但增加延迟和功耗。JESD204B标准的高速转换器需平衡通道数与串行速率,内插/抽取技术是关键。文章还解析了DDC、DUC的应用及优缺点,为高速数据转换设计提供参考。(150字)

weixin_49761275的博客 4268

aosp11/12/13 壁纸高斯模糊,毛玻璃SurfaceFlinger层面原理-第二节千里马framework实战

hi,粉丝朋友们!上一个blog已经详细讲解了系统中自带相关接口实现窗口的高斯模糊相关效果,具体点击这里。

liaosongmao1的专栏 857

保姆级教程:用R包ggpicrust2搞定PICRUSt2功能预测,从差异分析到热图PCA一键出图

本文提供了一份详细的ggpicrust2使用指南,帮助用户从零开始完成PICRUSt2功能预测数据的差异分析和可视化。通过安装配置、数据导入、差异分析到高级可视化(如热图和PCA)的全流程讲解,即使是初学者也能快速掌握发表级图表的生成技巧。

weixin_33712987的博客 385

平滑处理

平滑处理,(smoothing)也称模糊处理(bluring)。作用就是减少图像上的噪声或者失真。 图像滤波,即在尽量保留图像细节特征的条件下对目标图像的噪声进行抑制,是图像预处理中不可缺少的操作,其处理效果的好坏将直接影响到后续图像处理和分析的有效性和可靠性。 消除图像中的噪声成分叫作图像的平滑化或滤波操作。信号或图像的能量大部分集中在幅度谱的低频和中频段是很常见的,而在较高频段,感兴趣的信...

sinat_31608641的博客 1万+

三. zemax光学设计流程+案例

文章目录zemax 基本操作:1. 建立光学基本模型2. 像质评价3. 优化(重点)4. 公差分析简单镜头设计 zemax 基本操作: 1. 建立光学基本模型 2. 像质评价 3. 优化(重点) 对系统设定的约束条件或目标值 统称为操作数。 操作数: 光学特性参数(焦距EFFL,近轴放大率PMAG,入瞳位置EMPP) 像差参数(球差SPHA,彗差COMA,像散ASTI) 边界条件(中心厚度值CTVA,边缘厚度值ETAV) 优化的主要步骤: 设置评价函数和优化操作数 一般小像差系统采用波像差 构建

Taiiiii的博客 8054

i.MX6ULL系统移植 | 使用busybox制作根文件系统(1.29.0)

一. 下载BusyBox BusyBox是一个继承了大量Linux命令核工具的软件,像常用的ls、cp、mv、ifconfig等命令。一般下载BusyBox的源码,然后配置Busybox,选择自己想要的功能,最后编译即可。 BusyBox在官方可以直接下载:https://www.busybox.net/。目前最新是1.35.0,这里我使用1.29.0版本。 axel https://www.busybox.net/downloads/busybox-1.29.0.tar.bz2 下载之后解压: tar

Mculover666的博客(嵌入式) 1146

AOSP局部毛玻璃实战:模糊技术选型与Winscope调试陷阱

窗口级毛玻璃效果是系统UI定制中的高频需求。在AOSP环境中实现局部高斯模糊,远不止添加一个模糊滤镜那么简单,它涉及RenderEffect与SurfaceFlinger的跨窗口渲染链路。本文从Android模糊能力演进谈起,简要说明高斯核与散焦模糊的原理,再对比截图离线合成、跨窗口blurRegion、RenderEffect+RuntimeShader三种架构的适用场景与性能取舍。同时梳理AOSP 13至16的适配差异与常见坑点,并分享如何借助Winscope验证模糊区域,以及一个可能误导调试方向的原生

weixin_28718793的博客 185

语言模型推理能力与计算表达力深度解析

语言模型的推理能力本质上是一种知识迁移与泛化应用的过程,其核心在于Transformer架构中的自注意力机制和前馈网络的协同作用。计算表达力作为衡量模型能力的关键指标,涉及函数逼近、组合泛化和上下文理解等多个维度。随着模型规模的扩大,涌现能力现象揭示了参数规模与推理能力之间的非线性关系。在实际应用中,通过提示工程和微调策略可以有效激活和优化模型的推理表现。当前研究正探索模块化架构和世界模型整合等方向,以突破长程推理和因果关系建模等前沿挑战。本文深入探讨了语言模型推理泛化的技术原理与实践方法,为理解计算表达力

weixin_42521032的博客 343

Android实现高斯模糊效果(附带源码)

Android实现高斯模糊效果(附带源码)

欢迎来到我的博客!这里是一个专注于计算机技术的分享平台,涵盖编程开发、算法研究、系统架构、软件工程等多个领域。无论你是初学者还是资深开发者,都能在这里找到有价值的内容。 2722

UCIE Specification详解(十一)

Electrical Layer (2D and 2.5D)以及UCIe-3D

Crazzy_M的博客 1194

【人工智能之深度学习】21. 自动驾驶感知实战:YOLOv4复杂天气优化方案(BDD100K全代码+效果对比)

摘要:自动驾驶摄像头在雨雾天气下易受图像模糊、目标遮挡影响,导致YOLOv4检测精度骤降。本文基于BDD100K公开数据集(含多天气场景),设计三阶段优化方案:1)物理建模生成雨雾效果(雨滴线条+大气散射模型),将恶劣天气样本占比从20%提升至40%;2)在YOLOv4颈部嵌入CBAM注意力机制,强化模糊区域特征提取;3)L1剪枝(30%)+TensorRT量化实现轻量化。需特别说明:本文为教学虚拟案例,不可直接用于车载部署,实际落地需结合多传感器融合与ISO 26262认证。

专注于人工智能、软件开发、工控自动化、工厂数字化及智能化等领域,希望和大家共同进步! 1684

Android 多任务窗口中的界面高斯模糊处理问题

应用开发过程中安全问题的确需要系统考虑也要开发者自己多考虑,一个小的细节可能会让你的应用变的更安全,最近在用招商银行App的时候无意中发现了iPhone上多任务窗口,看到招商银行的应用有一个特别的地方就是当应用出现在多任务中的时候界面被高斯模糊处理了,也就是看不到界面内容了(如下图一),你看后面的今日头条还是可以看到内容的,为什么看不到这个应该都知道为了安全嘛。先说结论,就目前而言,iOS实现了系统级的可对后台任务列表中的App预览界面进行高斯模糊处理;Android目前假如我们想让应用安全点就是不要在多任

UrasakiNakajima的博客 6864

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

SurfaceFlinger简介

1. SurfaceFlinger背景知识         SurfaceFlinger 是一个独立的Service, 它接收所有Window的Surface作为输入,根据ZOrder, 透明度,大小,位置等参数,计算出每个Surface在最终合成图像中的位置,然后交由HWComposer或OpenGL生成最终的显示Buffer, 然后显示到特定的显示设备上。 下面首先介绍下相关概念:

撒哈拉的绿洲 2万+

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

高斯模糊的Java实现

1、http://jhlabs.com/ip/index.html public static byte[] blur(byte[] data) throws IOException { ByteArrayInputStream bais = new ByteArrayInputStream(data); BufferedImage img = Image...

weixin_34162228的博客 452

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

计算机桌面出现模糊窗口,显示屏模糊,教您怎么解决电脑屏幕模糊

在办公室工作时,我们总是需要长时间对着电脑,这时候电脑屏幕的清晰度对我们的眼睛来讲就很重要了。最近有用户反映,打开电脑发现电脑模糊不清晰,老感觉看的不是很清楚,看得眼睛很难受。下面,小编就来跟大家讲解解决电脑屏幕模糊的操作步骤。有用户反映,电脑在使用了一段时间之后,会出现屏幕便模糊的现象,就像是电脑的分辨率突然降低了一样,虽然说不会影响到电脑的操作,但是很多时候会觉得视觉效果降低了很多,画面感不强...

weixin_36300623的博客 3489

开源跨平台窗口 GuiLite 和 QT 下载安装记录

1、GuiLite--宣称6000行代码解决Windows+Linux+Mac+Android+vr+嵌入式 等的跨平台窗口解决方案。Github的项目地址:https://github.com/idea4good/GuiLite 下载研究了一下,其主要思想结构是,先申请一块跟显示器(或者目标窗口)相同大小的内存,然后把图像、文字、动画等内容,像素级别的绘制到内存当中,合成一张渲染后的图像(内存...

fripy的专栏 3262

Windows 10 Creaters Update 新功能——画中画模式和窗口高斯模糊

在Windows 10 Creaters Update中,可以给窗口设置高斯模糊了,只要几行代码! <Grid Loaded="Grid_Loaded"> <Grid x:Name="mg"></Grid> <Grid Background="Blue" Opacity="0.4" x:Nam...

diechun5019的博客 297

android 高斯模糊

commit c3802d22f11b4e513ba776277d18f315c5c769f7 Author: Mathias Agopian <mathias@google.com> Date: Wed Dec 8 17:13:19 2010 -0800 More clean-up. Get rid off the "blur" effect in SurfaceFlinger For multiple reason, this effect is not ma...

zyfzhangyafei的专栏 372

【Unity Bug挑战】第10期 SerializeReference 内存泄漏之谜

你翻了一下代码,项目里大量使用了 [SerializeReference] 特性来做技能系统的多态序列化——大概有 200 多个不同的技能效果类,都挂在 SkillData 这个 ScriptableObject 上,通过 Addressables 动态加载和释放。Unity 的 Native 对象是引用计数管理的,而 C# 托管对象是 GC 管理的。SerializeReference 的多态对象,它们的 Native 侧表示是什么样的?托管堆内存 | 加载后释放,回到初始水平 | 正常,符合预期。

crystal_WJT的博客 666

Jenkins + Python 全自动跑通「禅道任务/BUG 导出 → 月度开发考核表」

Jenkins结合Python实现禅道任务与BUG全自动导出及月度开发考核统计。通过复现浏览器三步导出流程(重置筛选、初始化、提交表单),精准获取全量数据;基于代码剔除父任务重复工时,修正“指派给”与“解决者”归属偏差,避免0工时导致的BUG率失真。最终生成含开发人天、有效负责BUG数、加权BUG率等字段的考核表,口径固化为可复用规则,彻底杜绝手工统计误差,实现零干预、高可信的自动化考核闭环。

一个人的博客 364
上一篇: 安卓车机车载面试福利6:一线厂商车载系统开发相关面试题
下一篇: 音量调节相关的一些问题解答之Active StreamType原理
千里马学框架
博客等级 码龄6年 1万+粉丝 650原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

千里马学框架

帮助你了,就请我喝杯咖啡

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值