当前位置: 首页 > news >正文

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

背景:

关于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 continueif (!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 shadersblurInput = 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 datecanvas = 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 activeSurfaceactiveSurface = 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 themcanvas->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 earlierif (!blurInput) {blurInput = activeSurface->makeImageSnapshot();}// rect to be blurred in the coordinate space of blurInputconst 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 earlierif (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实战开发干货,请关注下面“千里马学框架”

http://www.dtcms.com/a/390757.html

相关文章:

  • Java微服务架构设计模式精解
  • 设计模式面试之单例模式常问知识点
  • 深入解析 MySQL 元数据锁 (MDL) 与 SHOW PROCESSLIST 实战
  • 能不能写一个可以在linux使用的类nano编辑器
  • Rocky10 使用kubeadm部署K8s v1.34 一主两从
  • 深入理解Buffer:数据世界的“蓄水池“
  • 通义万相开源 Wan2.2-S2V-14B,实现图片+音频生成电影级数字人视频
  • windows c++环境 使用VScdoe配置opencv
  • JVM(四)-- 对象的实例化内存布局和直接内存
  • G1垃圾回收器的优势
  • 内存分配策略
  • Python采集Tik Tok视频详情,Tik TokAPI接口(json数据返回)
  • 实时通信技术大比拼:长轮询、短轮询、WebSocket 与 SSE 深度解析及实战指南
  • ICML 2025|图像如何与激光雷达对齐并互补?迈向协调的多模态3D全景分割
  • 基于Web的3D工程应用图形引擎——HOOPS Communicator技术解析
  • 【每日一问】运放的失调电压是什么?对于电路有何影响?
  • 【轨物方案】轨物科技新型储能管理系统:以AIoT技术驱动储能资产全生命周期价值最大化
  • 线性回归 vs 逻辑回归:从原理到实战的全面对比
  • HashMap的底层原理
  • 股指期货超短线如何操作?
  • 【洛谷】算法竞赛中的树结构:形式、存储与遍历全解析
  • 育苗盘补苗路径规划研究
  • API Gateway :API网关组件
  • conda激活虚拟环境
  • 重构大qmt通达信板块预警自动交易系统--读取通达信成分股
  • 25.9.19 Spring AOP
  • d38: PostgreSQL 简单入门与 Vue3 动态路由实现
  • No006:订阅化时间管理——迈向个性化、生态化的AI服务模式
  • 微服务-sentinel的理论与集成springcloud
  • C++学习:哈希表unordered_set/unordered_map的封装