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

了解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);} ......
}

相关文章:

了解AsyncRotationController

概述 基于android 15.0, 以从强制横屏App上滑退回桌面流程来分析 frameworks/base/services/core/java/com/android/server/wm/AsyncRotationController.javaAsyncRotationController 是一种控制器,用于处理设备显示屏旋转时非活动窗口的异步更新。这种控制器通过…...

有必要找第三方软件测评公司吗?如何选择靠谱软件测评机构?

软件测试是确保软件质量的重要环节,而在进行软件测试时,是否有必要找第三方软件测评公司呢?第三方软件测评公司是指独立于软件开发公司和用户之间的中立机构,专门从事软件测试和测评工作。与自身开发团队或内部测试团队相比,选择…...

物联网系统中市电电量计量方案(一)

为什么要进行电量计量? 节约资源:电量计量可以帮助人们控制用电量,从而达到节约资源的目的。在当前严峻的资源供应形势下,节约能源是我们应该重视的问题。合理计费:电表可以帮助公共事业单位进行合理计费,…...

2024年热门无线领夹麦克风哪款好,麦克风品牌排行榜前十名推荐

​在音频领域,无线领夹麦克风不断推陈出新,为我们带来了更出色的声音体验。无论你是主播、自媒体创作者、教师还是商务人士,都能从中找到适合自己的那一款。为了帮助大家轻松挑选到理想的无线领夹麦克风,我特别挑选了几款具有代表…...

IEEE顶刊“放水”?稳居1区Top,发文扩张IF稳长,CCF推荐,审稿友好!

本周投稿推荐 SCI • 能源科学类,1.5-2.0(25天来稿即录) • CCF推荐,4.5-5.0(2天见刊) • 生物医学制药类(2天逢投必中) EI • 各领域沾边均可(2天录用&#xff09…...

发布:PhonePrompter_PC(手机录视频提词器_电脑版)

PhonePrompter_PC(手机录视频提词器_电脑版) 目 录 1. 概述... 2 2. 应用手册... 3 下载地址:百度网盘 请输入提取码 提取码:8wsa 1. 概述 平时工作和生活中需要用手机竖屏或横屏模式录制造工作、科技、历史、生活等方面的一些视…...

shein测试开发会问些啥?

🏆本文收录于《CSDN问答解惑-》专栏,主要记录项目实战过程中的Bug之前因后果及提供真实有效的解决方案,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&…...

mysql索引优化

1、不在索引列做任何操作: 函数表达式:select sum(id) from 计算:where id 1; 隐式转换:where id "" 2、尽量全值匹配(在联合索引中,where 后面的条件尽量和索引的所有列匹配…...

Linux文件编程(打开/创建写入读取移动光标)

目录 一、如何在Linux下做开发 1.vi编辑器 2.gcc编译工具 3.常用指令 二、文件打开及创建 三、写入文件 四、读取文件 五、文件“光标”位置 一、如何在Linux下做开发 所谓文件编程,就是对文件进行操作,Linux的文件和Windows系统的文件大差不差…...

集成测试技术栈

前端 浏览器操作:playwright、selenium 后端 testcontainercucumbervitestcypressmsw...

MongoDB - 集合和文档的增删改查操作

文章目录 1. MongoDB 运行命令2. MongoDB CRUD操作1. 新增文档1. 新增单个文档 insertOne2. 批量新增文档 insertMany 2. 查询文档1. 查询所有文档2. 指定相等条件3. 使用查询操作符指定条件4. 指定逻辑操作符 (AND / OR) 3. 更新文档1. 更新操作符语法2. 更新单个文档 updateO…...

【深度学习基础】安装包报错——MAC M3-MAX芯片安装scikit-learn库报错。

目录 一、问题描述二、解决方法 一、问题描述 首先想安装scikit-learn库在mac终端显示顺利安装完成,但是测试的时候报错如下所示: /opt/anaconda3/envs/dtc/bin/python /Users/chenfaquan/PycharmProjects/TimeSeries/data_create.py Traceback (most…...

【chatgpt消费者偏好】是什么驱动了游客持续旅游意愿?推文分享—2024-07-08

今天推文的主题是【chatgpt&消费者意愿】 第一篇:文章主要研究了什么因素驱动旅游者继续使用ChatGPT进行旅行服务,并从人类拟态的角度探讨了旅游者对ChatGPT的感知和使用意图。第二篇:本文探讨了ChatGPT-4在生成针对TripAdvisor上发布的…...

torchplus

https://gitee.com/hj_research/torchplus 一、安装 pip install tplus...

LeetCode之最长回文子串

1.题目链接 5. 最长回文子串 - 力扣(LeetCode)https://leetcode.cn/problems/longest-palindromic-substring/description/ 2.题目解析 对于这道题目我们可以使用动态规划的思路来求解,具体思路是,对于一个长度大于2的子串&…...

Gradle 介绍

Gradle 定义 Gradle 是一个现代化的构建自动化工具,用于管理软件项目的构建过程和依赖关系。它通过一种灵活且强大的 DSL(领域特定语言)语法来描述项目的构建逻辑和任务,可以用于构建几乎任何类型的软件项目,从简单的应…...

短视频矩阵:批量发布的秘密揭秘

在数字化时代,短视频已经成为一种广受欢迎的媒体形式。无论是用于品牌推广、产品营销还是个人创作,短视频都提供了一种直观、生动的方式来吸引观众的注意力。然而,有效地制作、管理和发布短视频对于许多创作者和企业来说是一个挑战。 为此&am…...

基于 Nginx + Spring Boot + Vue + JPA 的网站安全防护指南

引言 在现代互联网时代,确保网站的安全性非常重要。尤其是基于前后端分离架构,更需要特别注意安全防护。接下来,带你了解几种常见的安全攻击及其应对措施。 常见的安全攻击及应对措施 1. 跨站脚本攻击 (XSS) 攻击描述: 跨站脚…...

Perl词法切分器:文本解析的瑞士军刀

📖 Perl词法切分器:文本解析的瑞士军刀 在编程语言中,词法分析是编译过程的第一步,它涉及将输入的源代码分解成一个个的词素或标记。Perl作为一种功能强大的文本处理语言,提供了丰富的工具来进行词法切分。本文将深入…...

基于深度学习LightWeight的人体姿态之行为识别系统源码

一. LightWeight概述 light weight openpose是openpose的简化版本,使用了openpose的大体流程。 Light weight openpose和openpose的区别是: a 前者使用的是Mobilenet V1(到conv5_5),后者使用的是Vgg19(前10…...

从WWDC看苹果产品发展的规律

WWDC 是苹果公司一年一度面向全球开发者的盛会,其主题演讲展现了苹果在产品设计、技术路线、用户体验和生态系统构建上的核心理念与演进脉络。我们借助 ChatGPT Deep Research 工具,对过去十年 WWDC 主题演讲内容进行了系统化分析,形成了这份…...

PHP和Node.js哪个更爽?

先说结论,rust完胜。 php:laravel,swoole,webman,最开始在苏宁的时候写了几年php,当时觉得php真的是世界上最好的语言,因为当初活在舒适圈里,不愿意跳出来,就好比当初活在…...

MySQL 隔离级别:脏读、幻读及不可重复读的原理与示例

一、MySQL 隔离级别 MySQL 提供了四种隔离级别,用于控制事务之间的并发访问以及数据的可见性,不同隔离级别对脏读、幻读、不可重复读这几种并发数据问题有着不同的处理方式,具体如下: 隔离级别脏读不可重复读幻读性能特点及锁机制读未提交(READ UNCOMMITTED)允许出现允许…...

spring:实例工厂方法获取bean

spring处理使用静态工厂方法获取bean实例,也可以通过实例工厂方法获取bean实例。 实例工厂方法步骤如下: 定义实例工厂类(Java代码),定义实例工厂(xml),定义调用实例工厂&#xff…...

uniapp微信小程序视频实时流+pc端预览方案

方案类型技术实现是否免费优点缺点适用场景延迟范围开发复杂度​WebSocket图片帧​定时拍照Base64传输✅ 完全免费无需服务器 纯前端实现高延迟高流量 帧率极低个人demo测试 超低频监控500ms-2s⭐⭐​RTMP推流​TRTC/即构SDK推流❌ 付费方案 (部分有免费额度&#x…...

【C语言练习】080. 使用C语言实现简单的数据库操作

080. 使用C语言实现简单的数据库操作 080. 使用C语言实现简单的数据库操作使用原生APIODBC接口第三方库ORM框架文件模拟1. 安装SQLite2. 示例代码:使用SQLite创建数据库、表和插入数据3. 编译和运行4. 示例运行输出:5. 注意事项6. 总结080. 使用C语言实现简单的数据库操作 在…...

数据库分批入库

今天在工作中,遇到一个问题,就是分批查询的时候,由于批次过大导致出现了一些问题,一下是问题描述和解决方案: 示例: // 假设已有数据列表 dataList 和 PreparedStatement pstmt int batchSize 1000; // …...

【论文阅读28】-CNN-BiLSTM-Attention-(2024)

本文把滑坡位移序列拆开、筛优质因子,再用 CNN-BiLSTM-Attention 来动态预测每个子序列,最后重构出总位移,预测效果超越传统模型。 文章目录 1 引言2 方法2.1 位移时间序列加性模型2.2 变分模态分解 (VMD) 具体步骤2.3.1 样本熵(S…...

【开发技术】.Net使用FFmpeg视频特定帧上绘制内容

目录 一、目的 二、解决方案 2.1 什么是FFmpeg 2.2 FFmpeg主要功能 2.3 使用Xabe.FFmpeg调用FFmpeg功能 2.4 使用 FFmpeg 的 drawbox 滤镜来绘制 ROI 三、总结 一、目的 当前市场上有很多目标检测智能识别的相关算法,当前调用一个医疗行业的AI识别算法后返回…...

安宝特案例丨Vuzix AR智能眼镜集成专业软件,助力卢森堡医院药房转型,赢得辉瑞创新奖

在Vuzix M400 AR智能眼镜的助力下,卢森堡罗伯特舒曼医院(the Robert Schuman Hospitals, HRS)凭借在无菌制剂生产流程中引入增强现实技术(AR)创新项目,荣获了2024年6月7日由卢森堡医院药剂师协会&#xff0…...