了解AsyncRotationController

概述

基于android 15.0, 以从强制横屏App上滑退回桌面流程来分析

frameworks/base/services/core/java/com/android/server/wm/AsyncRotationController.java

AsyncRotationController 是一种控制器,用于处理设备显示屏旋转时非活动窗口的异步更新。这种控制器通过异步处理来优化屏幕旋转或应用过渡动画的启动延迟,确保窗口在旋转过程中能够平滑过渡,避免闪烁或延迟问题。具体功能包括:

  • 在旋转变化时处理窗口的淡出和淡入效果。
  • 隐藏和显示目标窗口以匹配新的旋转角度。
  • 使用同步事务管理无缝旋转,确保窗口能够平滑过渡到新的旋转状态。
Async Rotation执行时机

在这里插入图片描述

// DisplayContent.java
void setFixedRotationLaunchingAppUnchecked(@Nullable ActivityRecord r, int rotation) {if (mFixedRotationLaunchingApp == null && r != null) {mWmService.mDisplayNotificationController.dispatchFixedRotationStarted(this, rotation);// 延迟隐藏动画,以避免在短时间内点击导航栏可能触发固定旋转时出现闪烁final boolean shouldDebounce = r == mFixedRotationTransitionListener.mAnimatingRecents|| mTransitionController.isTransientLaunch(r);startAsyncRotation(shouldDebounce);} else if (mFixedRotationLaunchingApp != null && r == null) {mWmService.mDisplayNotificationController.dispatchFixedRotationFinished(this);// 如果请求display的下一次transition,保持异步旋转控制器。if (!mTransitionController.hasCollectingRotationChange(this, getRotation())) {finishAsyncRotationIfPossible();}}mFixedRotationLaunchingApp = r;
}

用于启动异步旋转过程。这个过程允许应用程序或系统在不阻塞主线程的情况下处理显示屏的旋转,从而提供更平滑的用户体验.

// DisplayContent.java
private boolean startAsyncRotation(boolean shouldDebounce) {if (shouldDebounce) {mWmService.mH.postDelayed(() -> {synchronized (mWmService.mGlobalLock) {if (mFixedRotationLaunchingApp != null&& startAsyncRotation(false /* shouldDebounce */)) {// 应用该事务,使动画控制能够立即生效getPendingTransaction().apply();}}}, FIXED_ROTATION_HIDE_ANIMATION_DEBOUNCE_DELAY_MS); //250msreturn false;}if (mAsyncRotationController == null) {mAsyncRotationController = new AsyncRotationController(this);mAsyncRotationController.start();return true;}return false;
}

动画执行

  1. 收集目标窗口
// AsyncRotationController.java
AsyncRotationController(DisplayContent displayContent) {.....// 收集那些可以异步旋转而不阻塞display的窗口。displayContent.forAllWindows(this, true /* traverseTopToBottom */);......
}public void accept(WindowState w) {if (!w.mHasSurface || !canBeAsync(w.mToken)) {return;}if (mTransitionOp == OP_LEGACY && w.mForceSeamlesslyRotate) {// Legacy transition already handles seamlessly windows.return;}......// 大部分都是执行fade窗口动画final int action = mTransitionOp == OP_CHANGE_MAY_SEAMLESS || w.mForceSeamlesslyRotate? Operation.ACTION_SEAMLESS : Operation.ACTION_FADE;mTargetWindowTokens.put(w.mToken, new Operation(action));
}
  1. 目标窗口在TO_FRONT transition启动时淡出
    在这里插入图片描述
07-11 15:27:24.362  3750  3785 D AsyncRotation: Start fade-out Window{ae32994 u0 Floating XXX}
// AsyncRotationController.java
/*** 为可能稍后无缝旋转的窗口令牌准备相应的操作(例如隐藏动画)*/
void start() {.....for (int i = mTargetWindowTokens.size() - 1; i >= 0; i--) {final WindowToken windowToken = mTargetWindowTokens.keyAt(i);final Operation op = mTargetWindowTokens.valueAt(i);if (op.mAction == Operation.ACTION_FADE || op.mAction == Operation.ACTION_TOGGLE_IME) {fadeWindowToken(false /* show */, windowToken, ANIMATION_TYPE_TOKEN_TRANSFORM);op.mLeash = windowToken.getAnimationLeash();if (DEBUG) Slog.d(TAG, "Start fade-out " + windowToken.getTopChild());} else if (op.mAction == Operation.ACTION_SEAMLESS) {op.mLeash = windowToken.mSurfaceControl;if (DEBUG) Slog.d(TAG, "Start seamless " + windowToken.getTopChild());}}.....
}
  1. 目标窗口在CHANGE transition启动时以new rotation重绘
    在这里插入图片描述
3750  3785 V WindowManager: Resize reasons for w=Window{eb45fff u0 Floating XXX}:  forceReportingResized=false insetsChanged=true configChanged=true didFrameInsetsChange=true
3750  3785 I WindowManager: Resizing Window{ae32994 u0 Floating XXX} WITH DRAW PENDING
3750  3785 V WindowManager: Requested redraw for orientation change: Window{ae32994 u0 Floating XXX}
3750  7896 I WindowManager: finishDrawing of orientation change: Window{ae32994 u0 Floating XXX} 100ms
// WindowState.java
void updateResizingWindowIfNeeded() {......// display rotation改变, 所以这里的configChanged为truefinal boolean configChanged = !mInRelayout && !isLastConfigReportedToClient();......final boolean contentChanged = didFrameInsetsChange || configChanged|| dragResizingChanged || attachedFrameChanged;.....if (contentChanged || insetsChanged || shouldSendRedrawForSync()) {ProtoLog.v(WM_DEBUG_RESIZE,"Resize reasons for w=%s:  %s configChanged=%b didFrameInsetsChange=%b",this, mWindowFrames.getInsetsChangedInfo(),configChanged, didFrameInsetsChange);.....// 重置当前窗口的mDrawState为DRAW_PENDINGif ((configChanged || getOrientationChanging() || dragResizingChanged)&& isVisibleRequested()) {winAnimator.mDrawState = DRAW_PENDING;.....}if (!mWmService.mResizingWindows.contains(this)) {ProtoLog.v(WM_DEBUG_RESIZE, "Resizing window %s", this);mWmService.mResizingWindows.add(this);}} .....
}void reportResized() {......ProtoLog.v(WM_DEBUG_RESIZE, "Reporting new frame to %s: %s", this,mWindowFrames.mCompatFrame);final boolean drawPending = mWinAnimator.mDrawState == DRAW_PENDING;if (drawPending) {ProtoLog.i(WM_DEBUG_ORIENTATION, "Resizing %s WITH DRAW PENDING", this);}.....final boolean reportDraw = syncRedraw || drawPending;.....if (Flags.bundleClientTransactionFlag()) {getProcess().scheduleClientTransactionItem(WindowStateResizeItem.obtain(mClient, mClientWindowFrames, reportDraw,mLastReportedConfiguration, getCompatInsetsState(), forceRelayout,alwaysConsumeSystemBars, displayId,syncWithBuffers ? mSyncSeqId : -1, isDragResizing,mLastReportedActivityWindowInfo));onResizePostDispatched(drawPending, prevRotation, displayId);}......
}
  1. TO_FRONT动画结束时开始淡入目标窗口
07-11 15:27:25.532  3750  7896 D AsyncRotation: handleFinishDrawing Window{ae32994 u0 Floating XXX}
07-11 15:27:25.532  3750  7896 D AsyncRotation: Complete set pending Window{ae32994 u0 Floating XXX}
07-11 15:27:25.572  3750  8951 D AsyncRotation: Setup unrotate Window{ae32994 u0 Floating XXX}
07-11 15:27:25.636  3750  7166 D AsyncRotation: Complete directly Window{ae32994 u0 Floating XXX}
07-11 15:27:25.636  3750  7166 D AsyncRotation: finishOp fade-in Window{ae32994 u0 Floating XXX}

在这里插入图片描述

// AsyncRotationController.java
void completeAll() {for (int i = mTargetWindowTokens.size() - 1; i >= 0; i--) {finishOp(mTargetWindowTokens.keyAt(i));}mTargetWindowTokens.clear();onAllCompleted();
}private void finishOp(WindowToken windowToken) {final Operation op = mTargetWindowTokens.remove(windowToken);......else if (op.mAction == Operation.ACTION_FADE) {if (DEBUG) Slog.d(TAG, "finishOp fade-in " + windowToken.getTopChild());// The previous animation leash will be dropped when preparing fade-in animation, so// simply apply new animation without restoring the transformation.fadeWindowToken(true /* show */, windowToken, ANIMATION_TYPE_TOKEN_TRANSFORM);} ......
}

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

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

相关文章

设计模式——适配器设计模式

设计模式——适配器设计模式 适配器设计模式1.1 基本介绍1.2 工作原理1.3 类适配器模式1.3.1 基本介绍1.3.2 示例1.3.3 代码实现1.3.4 注意事项 1.4 对象适配器模式1.4.1 基本介绍1.4.2 示例1.4.3 代码实现1.4.4 注意事项 1.5 接口适配器模式1.5.1 基本介绍1.5.2 示例1.5.3 代码…

如何处理Java中数据结构(如HashMap)导致的性能瓶颈

在Java开发过程中,HashMap 是一种常用的数据结构,它提供了高效的键值对存储和快速的查找、插入和删除操作。然而,在某些情况下,HashMap 可能会导致性能瓶颈。本文将探讨这些性能瓶颈的成因,并提供一些优化策略。 一、…

Webkit简介以及工作流程

Webkit简介 WebKit是一个开源的浏览器引擎,最初由苹果公司基于KHTML(K Desktop Environment的HTML渲染引擎)开发,并广泛应用于Safari浏览器。随着时间的推移,WebKit也被其他多款浏览器和应用所采用,成为We…

pudb: Python的图形化调试器

文章目录 pudb原理基础使用安装pudb启动pudb界面介绍常用操作 高级使用条件断点表达式求值自定义布局搜索和过滤插件和扩展 结论 pudb原理 pudb是一个基于文本的图形化Python调试器,它结合了pdb的强大调试功能与图形用户界面的易用性。pudb通过提供一个可视化的界面…

【操作系统】阻塞队列以及生产者消费者模型

目录 阻塞队列一. 概念二. 标准库中的阻塞队列三. 生产者消费者模型四. 阻塞队列实现 总结 阻塞队列 一. 概念 阻塞队列是⼀种特殊的队列.也遵守"先进先出"的原则. 阻塞队列能是⼀种线程安全的数据结构,并且具有以下特性: 当队列满的时候,继续⼊队列就会阻塞,直到…

Splashtop 在医疗与制药领域的业务增长近五倍

2024年7月10日 加利福尼亚州库比蒂诺 Splashtop 是安全远程访问和 IT 支持解决方案领域的领先企业,该公司今天宣布,在医疗与制药领域业务同比增长492%,取得了里程碑式的成就。快速发展的数字实验室环境和持续的网络安全威胁需要实施无缝、安…

Unity之VS脚本自动添加头部注释Package包开发

内容将会持续更新,有错误的地方欢迎指正,谢谢! Unity之VS脚本自动添加头部注释Package包开发 TechX 坚持将创新的科技带给世界! 拥有更好的学习体验 —— 不断努力,不断进步,不断探索 TechX —— 心探索、心进取&…

模板语法指令语法——02

//指令语法: 1.什么是指定,有什么作用? 指令的职责是,当表达式的值改变时,将其产生的连带影响,响应式的作用语DOM 2.vue框架中的所有指令的名字都以v-开始的 3.插值是写在标签当中用的,指令…

WSGI 服务器教程:`execute` 方法解析

Python WSGI 服务器教程:execute 方法解析 在本文中,我们将详细解析一个用于 WSGI 服务器的 execute 方法。这个方法负责执行 WSGI 应用程序,处理其响应数据,并确保在应用程序执行过程中处理所有必要的清理工作。我们将逐行解释该…

uniapp启动图延时效果,启动图的配置

今天阐述uniapp开发中给启动图做延迟效果,不然启动图太快了,一闪就过去了; 一:修改配置文件:manifest.json "app-plus" : {"splashscreen" : {"alwaysShowBeforeRender" : false,"…

编程语言前途:探索未来的无限可能

编程语言前途:探索未来的无限可能 在科技日新月异的今天,编程语言作为连接人类与计算机世界的桥梁,其前途无疑是充满无限可能与挑战的。本文将从四个方面、五个方面、六个方面和七个方面,深入剖析编程语言的前途,带您…

vivado EDIF_EXTRA_SEARCH_PATHS、EQUALIZATION

EDIF_EXTRA_SEARCH_PATHS 此属性定义了Vivado Design Suite在当前文件集上的搜索路径,以 查找设计引用的EDIF文件。 提示:当Vivado设计套件无法执行以下操作时,在实现过程中会出现以下错误 定位与黑盒关联的EDIF网表。这可以通过定义 EDIF_EX…

法律咨询援助网站

1 项目介绍 1.1 摘要 随着互联网技术的飞速发展,公众对于便捷、高效的法律咨询服务需求日益增长。传统的法律咨询方式已难以满足人们即时性、多样化的咨询需求,促使法律咨询援助网站应运而生。这些平台旨在通过数字化手段,为用户提供法律知…

【TS】Typescript 的泛型

TypeScript 的泛型(Generics)是 TypeScript 的一个非常强大的特性,它允许你在编译时定义组件,这些组件可以工作于多种类型的数据上。泛型可以创建可重用的组件,这些组件是独立于任何特定类型的。这意味着你可以编写灵活…

apache:the requested operation has failed使用httpd -t

Apache24\bin cmd 回车 httpd -t 因为我重新压缩了,记住,重新压缩要使用原路径, 因为你安装的 时候使用的是原路径 还是不行就改个端口,切记修改配置文件httpd.conf先把Tomcat停了 Define SRVROOT "F:\Apache\Apache24&q…

C++类和对象学习笔记

1.类的定义 1.1类定义的格式 class是定义类的关键字,Date为类的名字,{ }中为类的主体,注意定义类结束时后面的分号不能省略。类中的内容称为类的成员;类中的变量称为类的属性或成员变量;类中的函数称为类的方法或者成…

自定义枚举对象序列化规则: 在Json中以枚举的code值表示枚举;枚举序列化时,新增枚举描述字段;String到IEnum的转换

文章目录 引言I 案例分析1.1 接口签名计算1.2 请求对象1.3 枚举对象序列化1.4 创建JavaTimeModule以支持Java 8的时间日期类型序列化和反序列化1.5 请求对象默认值处理II 在JSON中以枚举的code值来表示枚举的实现方式2.1 自定义toString方法返回code2.2 使用@JsonValue注解,只…

adminPage-vue3依赖FormPage说明文档,表单页快速开发,使用思路及范例(Ⅱ)formConfig基础配置项

adminPage-vue3依赖FormPage说明文档,表单页快速开发,使用思路及范例(Ⅱ)formConfig配置项 属性: formConfig(表单项设置)keylabelnoLabeldefaultValuebindchildSlottypeString类型数据(除 time…

IntelliJ IDEA 2024.1.4最新教程!!直接2099!!爽到飞起!!

IntelliJ IDEA 2024.1.4最新破解教程!!直接2099!!爽到飞起!!【资源在末尾】安装馆长为各位看官准备了多个版本,看官可根据自己的需求进行下载和选择安装。https://mp.weixin.qq.com/s/Tic1iR_Xc…

C语言:高级并发操作(线程)

一、线程的概念 线程:进程中的一个实体,是CPU调度和分派的基本单位。线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器、一组寄存器和栈),但它可以与同属一个进程的其他线程共…