AOSP Android14 Launcher3——远程窗口动画关键类SurfaceControl详解

在 Launcher3 执行涉及其他应用窗口(即“远程窗口”)的动画时,例如“点击桌面图标启动应用”或“从应用上滑回到桌面”的过渡动画,SurfaceControl 扮演着至关重要的角色。它是实现这些跨进程、高性能、精确定制动画的核心技术。

SurfaceControl在源码中的使用

Launcher3中有几处非常经典的使用SurfaceControl的地方。
在这里插入图片描述

在分屏应用进入到最近任务,或者从最近任务启动应用时,涉及到分屏应用中间的bar条,这个bar条是属于SystemUI进程的,在Launcher中显示就属于远程窗口,因此需要通过SurfaceControl来进行更新操作。
启动分屏应用时bar条由隐藏到最终显示的过程就是通过SurfaceControl控制bar条的透明度来实现的。
源码如下:

    public static ValueAnimator createSplitAuxiliarySurfacesAnimator(@Nullable RemoteAnimationTarget[] nonApps, boolean shown,@Nullable Consumer<ValueAnimator> animatorHandler) {if (nonApps == null || nonApps.length == 0) {return null;}List<SurfaceControl> auxiliarySurfaces = new ArrayList<>();for (RemoteAnimationTarget target : nonApps) {final SurfaceControl leash = target.leash;if (target.windowType == TYPE_DOCK_DIVIDER && leash != null && leash.isValid()) {auxiliarySurfaces.add(leash);}}if (auxiliarySurfaces.isEmpty()) {return null;}SurfaceControl.Transaction t = new SurfaceControl.Transaction();if (animatorHandler == null) {// Apply the visibility directly without fade animation.for (SurfaceControl leash : auxiliarySurfaces) {t.setVisibility(leash, shown);}t.apply();t.close();return null;}ValueAnimator dockFadeAnimator = ValueAnimator.ofFloat(0f, 1f);dockFadeAnimator.addUpdateListener(valueAnimator -> {float progress = valueAnimator.getAnimatedFraction();for (SurfaceControl leash : auxiliarySurfaces) {if (leash != null && leash.isValid()) {t.setAlpha(leash, shown ? progress : 1 - progress);}}t.apply();});dockFadeAnimator.addListener(new AnimatorListenerAdapter() {@Overridepublic void onAnimationStart(Animator animation) {if (shown) {for (SurfaceControl leash : auxiliarySurfaces) {t.setLayer(leash, Integer.MAX_VALUE);t.setAlpha(leash, 0);t.show(leash);}t.apply();}}@Overridepublic void onAnimationEnd(Animator animation) {if (!shown) {for (SurfaceControl leash : auxiliarySurfaces) {if (leash != null && leash.isValid()) {t.hide(leash);}}t.apply();}t.close();}});dockFadeAnimator.setDuration(SPLIT_DIVIDER_ANIM_DURATION);animatorHandler.accept(dockFadeAnimator);return dockFadeAnimator;}

下来来详解SurfaceControl在Launcher中的角色以及为什么要使用SurfaceControl

SurfaceControl 的角色:

  1. 窗口/图层的句柄: 在 Android 图形系统中,每个窗口或可视元素最终都对应一个或多个图层 (Layer),这些图层由系统的合成器 (SurfaceFlinger) 负责管理和混合。SurfaceControl 是一个轻量级的句柄 (Handle),它代表了 SurfaceFlinger 中的一个图层(Surface)。你可以把它想象成一个指向屏幕上某个“画板”的遥控器。
  2. 直接操作图层属性: 通过 SurfaceControl,一个有权限的进程(在远程动画场景下,通常是 Launcher 或 SystemUI)可以直接、高效地修改其代表的图层在 SurfaceFlinger 中的各种属性,而无需与创建这个图层的原始应用进程进行复杂的通信或等待其响应。这些属性包括:
    • 几何变换: 位置 (Position)、缩放 (Scale)、旋转 (Rotation) (通常通过设置变换矩阵 Matrix 实现)。
    • 视觉效果: 透明度 (Alpha)、层级 (Z-order)、裁剪区域 (Window Crop)、圆角半径 (Corner Radius)、阴影 (Shadow Radius)、模糊 (Blur) 等。
  3. 跨进程动画的桥梁: 在远程动画中,系统 (WindowManager) 会将参与动画的窗口(例如正在打开的应用窗口、正在关闭的 Launcher 窗口、壁纸窗口)的 SurfaceControl(通常是一个称为 “Leash” 的特殊控制层)打包在 RemoteAnimationTarget 对象中,传递给动画控制器(Launcher)。
  4. 动画执行者 (SurfaceControl.Transaction): Launcher 拿到这些 SurfaceControl 后,不会去修改对应应用的 View 属性,而是创建 SurfaceControl.Transaction 对象。在动画的每一帧:
    • Launcher 计算出每个目标窗口图层应该具有的视觉属性(比如,应用窗口从图标大小放大到全屏,透明度从 0 到 1,裁剪区域从无到有,圆角从大变小)。
    • 使用 Transaction 提供的方法(如 setMatrix(), setAlpha(), setWindowCrop(), setCornerRadius())为每个 SurfaceControl 设置这些目标属性。
    • 最后调用 transaction.apply() 原子性地将这一帧的所有属性变更提交给 SurfaceFlinger
    • SurfaceFlinger 在下一个 VSYNC 信号到来时,根据这些最新的属性来合成并显示屏幕内容,从而驱动了视觉上的动画效果。

为什么在远程动画中使用 SurfaceControl

使用 SurfaceControl 是实现现代 Android 流畅、复杂过渡动画的关键,原因如下:

  1. 高性能 (Performance): 直接在 SurfaceFlinger (系统合成器)层面操作图层属性非常高效,通常能利用硬件加速。这避免了在应用进程内部进行复杂的 View 布局、绘制或属性动画,这些操作可能更耗资源且容易引发卡顿 (Jank)。
  2. 精确同步 (Synchronization): 对于涉及多个应用窗口(跨进程)的过渡动画(如应用启动/关闭、分屏),需要精确地同步它们的动画。通过 SurfaceControl.Transaction,Launcher 可以原子性地更新所有相关图层的属性,确保它们在同一帧内发生变化,实现完美的视觉同步。如果依赖各个应用自己执行动画,几乎不可能做到如此精确的同步。
  3. 强大控制力 (Control): SurfaceControl API 提供了对图层视觉属性的底层、细粒度控制,使得 Launcher 可以实现非常复杂的动画效果,例如从图标到窗口的平滑变形、窗口内容的裁剪、圆角变化等,这些效果很难通过传统的 View 动画或窗口动画(ActivityOptions)实现得如此精细。
  4. 解耦 (Decoupling): 被动画的应用(例如正在启动的应用)不需要主动参与这个由 Launcher 控制的过渡动画。应用只需要正常地将自己的内容绘制到它的 Surface 上即可。Launcher 通过 SurfaceControl 在外部“指挥”SurfaceFlinger 如何变换和展示这个 Surface。这大大降低了应用和系统过渡动画之间的耦合度。
  5. 无缝体验 (Seamlessness): SurfaceControl 使得元素(如图标)看起来能够“无缝地”跨越进程边界变形成为另一个应用的窗口,提供了非常连贯和自然的视觉体验。

总结:

在 Launcher 对远程窗口执行动画的过程中,SurfaceControl 充当了底层图层(Surface)的直接控制器。Launcher 通过它,绕开了应用进程,直接与系统合成器 SurfaceFlinger 交互,以高性能、精确同步的方式驱动应用窗口的几何变换和视觉效果,从而实现了流畅、复杂且跨进程的过渡动画。这是现代 Android 系统动画(尤其是 Quickstep 手势动画)的核心技术基础。

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

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

相关文章

超详细实现单链表的基础增删改查——基于C语言实现

文章目录 1、链表的概念与分类1.1 链表的概念1.2 链表的分类 2、单链表的结构和定义2.1 单链表的结构2.2 单链表的定义 3、单链表的实现3.1 创建新节点3.2 头插和尾插的实现3.3 头删和尾删的实现3.4 链表的查找3.5 指定位置之前和之后插入数据3.6 删除指定位置的数据和删除指定…

17.整体代码讲解

从入门AI到手写Transformer-17.整体代码讲解 17.整体代码讲解代码 整理自视频 老袁不说话 。 17.整体代码讲解 代码 import collectionsimport math import torch from torch import nn import os import time import numpy as np from matplotlib import pyplot as plt fro…

前端性能优化:所有权转移

前端性能优化&#xff1a;所有权转移 在学习rust过程中&#xff0c;学到了所有权概念&#xff0c;于是便联想到了前端&#xff0c;前端是否有相关内容&#xff0c;于是进行了一些实验&#xff0c;并整理了这些内容。 所有权转移&#xff08;Transfer of Ownership&#xff09;…

Missashe考研日记-day23

Missashe考研日记-day23 0 写在前面 博主前几天有事回家去了&#xff0c;断更几天了不好意思&#xff0c;就当回家休息一下调整一下状态了&#xff0c;今天接着开始更新。虽然每天的博客写的内容不算多&#xff0c;但其实还是挺费时间的&#xff0c;比如这篇就花了我40多分钟…

Docker 中将文件映射到 Linux 宿主机

在 Docker 中&#xff0c;有多种方式可以将文件映射到 Linux 宿主机&#xff0c;以下是常见的几种方法&#xff1a; 使用-v参数• 基本语法&#xff1a;docker run -v [宿主机文件路径]:[容器内文件路径] 容器名称• 示例&#xff1a;docker run -it -v /home/user/myfile.txt:…

HarmonyOS-ArkUI-动画分类简介

本文的目的是,了解一下HarmonyOS动画体系中的分类。有个大致的了解即可。 动效与动画简介 动画,是客户端提升界面交互用户体验的一个重要的方式。可以使应用程序更加生动灵越,提高用户体验。 HarmonyOS对于界面的交互方面,围绕回归本源的设计理念,打造自然,流畅品质一提…

C++如何处理多线程环境下的异常?如何确保资源在异常情况下也能正确释放

多线程编程的基本概念与挑战 多线程编程的核心思想是将程序的执行划分为多个并行运行的线程&#xff0c;每个线程可以独立处理任务&#xff0c;从而充分利用多核处理器的性能优势。在C中&#xff0c;开发者可以通过std::thread创建线程&#xff0c;并使用同步原语如std::mutex、…

区间选点详解

步骤 operator< 的作用在 C 中&#xff0c; operator< 是一个运算符重载函数&#xff0c;它定义了如何比较两个对象的大小。在 std::sort 函数中&#xff0c;它会用到这个比较函数来决定排序的顺序。 在 sort 中&#xff0c;默认会使用 < 运算符来比较两个对象…

前端配置代理解决发送cookie问题

场景&#xff1a; 在开发任务管理系统时&#xff0c;我遇到了一个典型的身份认证问题&#xff1a;​​用户登录成功后&#xff0c;调获取当前用户信息接口却提示"用户未登录"​​。系统核心流程如下&#xff1a; ​​用户登录​​&#xff1a;调用 /login 接口&…

8.1 线性变换的思想

一、线性变换的概念 当一个矩阵 A A A 乘一个向量 v \boldsymbol v v 时&#xff0c;它将 v \boldsymbol v v “变换” 成另一个向量 A v A\boldsymbol v Av. 输入 v \boldsymbol v v&#xff0c;输出 T ( v ) A v T(\boldsymbol v)A\boldsymbol v T(v)Av. 变换 T T T…

【java实现+4种变体完整例子】排序算法中【冒泡排序】的详细解析,包含基础实现、常见变体的完整代码示例,以及各变体的对比表格

以下是冒泡排序的详细解析&#xff0c;包含基础实现、常见变体的完整代码示例&#xff0c;以及各变体的对比表格&#xff1a; 一、冒泡排序基础实现 原理 通过重复遍历数组&#xff0c;比较相邻元素并交换逆序对&#xff0c;逐步将最大值“冒泡”到数组末尾。 代码示例 pu…

系统架构设计(二):基于架构的软件设计方法ABSD

“基于架构的软件设计方法”&#xff08;Architecture-Based Software Design, ABSD&#xff09;是一种通过从软件架构层面出发指导详细设计的系统化方法。它旨在桥接架构设计与详细设计之间的鸿沟&#xff0c;确保系统的高层结构能够有效指导后续开发。 ABSD 的核心思想 ABS…

Office文件内容提取 | 获取Word文件内容 |Javascript提取PDF文字内容 |PPT文档文字内容提取

关于Office系列文件文字内容的提取 本文主要通过接口的方式获取Office文件和PDF、OFD文件的文字内容。适用于需要获取Word、OFD、PDF、PPT等文件内容的提取实现。例如在线文字统计以及论文文字内容的提取。 一、提取Word及WPS文档的文字内容。 支持以下文件格式&#xff1a; …

Cesium学习笔记——dem/tif地形的分块与加载

前言 在Cesium的学习中&#xff0c;学会读文档十分重要&#xff01;&#xff01;&#xff01;在这里附上Cesium中英文文档1.117。 在Cesium项目中&#xff0c;在平坦坦地球中加入三维地形不仅可以增强真实感与可视化效果&#xff0c;还可以​​提升用户体验与交互性&#xff0c…

Spring Boot 断点续传实战:大文件上传不再怕网络中断

精心整理了最新的面试资料和简历模板&#xff0c;有需要的可以自行获取 点击前往百度网盘获取 点击前往夸克网盘获取 一、痛点与挑战 在网络传输大文件&#xff08;如视频、数据集、设计稿&#xff09;时&#xff0c;常面临&#xff1a; 上传中途网络中断需重新开始服务器内…

数码管LED显示屏矩阵驱动技术详解

1. 矩阵驱动原理 矩阵驱动是LED显示屏常用的一种高效驱动方式&#xff0c;利用COM&#xff08;Common&#xff0c;公共端&#xff09;和SEG&#xff08;Segment&#xff0c;段选&#xff09;线的交叉点控制单个LED的亮灭。相比直接驱动&#xff0c;矩阵驱动可以显著减少所需I/…

【上位机——MFC】菜单类与工具栏

菜单类 CMenu&#xff0c;封装了关于菜单的各种操作成员函数&#xff0c;另外还封装了一个非常重要的成员变量m_hMenu(菜单句柄) 菜单使用 添加菜单资源加载菜单 工具栏相关类 CToolBarCtrl-》父类是CWnd&#xff0c;封装了关于工具栏控件的各种操作。 CToolBar-》父类是CC…

liunx中常用操作

查看或修改linux本地mysql端口 cat /etc/my.cnf 如果没有port可以添加&#xff0c;有可以修改 查看本地端口占用情况 bash netstat -nlt | grep 3307 HADOOP集群 hdfs启动与停止 # 一键启动hdfs集群 start-dfs.sh # 一键关闭hdfs集群 stop-dfs.sh #除了一键启停外&#x…

衡石chatbi如何通过 iframe 集成

iframe 集成方式是最简单的一种&#xff0c;您只需要在您的 HTML 文件中&#xff08;或 Vue/React 组件中&#xff09;添加一个 iframe 元素&#xff0c;并设置其 src 属性为 AI 助手的 URL。 <iframesrc"https://develop.hengshi.org/copilot"width"100%&q…

Java集合框架深度解析:HashMap、HashSet、TreeMap、TreeSet与哈希表原理详解

一、核心数据结构总览 1. 核心类继承体系 graph TDMap接口 --> HashMapMap接口 --> TreeMapSet接口 --> HashSetSet接口 --> TreeSetHashMap --> LinkedHashMapHashSet --> LinkedHashSetTreeMap --> NavigableMapTreeSet --> NavigableSet 2. 核心特…