Android开机动画,framework修改Bootanimation绘制文字。
文章目录
- Android开机动画,framework修改Bootanimation动画绘制文字。
- opengl绘制源码分析
Android开机动画,framework修改Bootanimation动画绘制文字。
frameworks/base/cmds/bootanimation/bootanimation.cpp
绘制时间的一个方法

// We render 12 or 24 hour time.
void BootAnimation::drawClock(const Font& font, const int xPos, const int yPos) {static constexpr char TIME_FORMAT_12[] = "%l:%M";static constexpr char TIME_FORMAT_24[] = "%H:%M";static constexpr int TIME_LENGTH = 6;
获取系统时间time_t rawtime;time(&rawtime);struct tm* timeInfo = localtime(&rawtime);char timeBuff[TIME_LENGTH];//显示时间的字符串const char* timeFormat = mTimeFormat12Hour ? TIME_FORMAT_12 : TIME_FORMAT_24;size_t length = strftime(timeBuff, TIME_LENGTH, timeFormat, timeInfo);if (length != TIME_LENGTH - 1) {SLOGE("Couldn't format time; abandoning boot animation clock");mClockEnabled = false;return;}char* out = timeBuff[0] == ' ' ? &timeBuff[1] : &timeBuff[0];int x = xPos;int y = yPos;//绘制文本drawText(out, font, false, &x, &y);
}
绘制文本
void BootAnimation::drawText(const char* str, const Font& font, bool bold, int* x, int* y) {glEnable(GL_BLEND); // Allow us to draw on top of the animationglBindTexture(GL_TEXTURE_2D, font.texture.name);const int len = strlen(str);const int strWidth = font.char_width * len;if (*x == TEXT_CENTER_VALUE) {*x = (mWidth - strWidth) / 2;} else if (*x < 0) {*x = mWidth + *x - strWidth;}if (*y == TEXT_CENTER_VALUE) {*y = (mHeight - font.char_height) / 2;} else if (*y < 0) {*y = mHeight + *y - font.char_height;}int cropRect[4] = { 0, 0, font.char_width, -font.char_height };for (int i = 0; i < len; i++) {char c = str[i];if (c < FONT_BEGIN_CHAR || c > FONT_END_CHAR) {c = '?';}// Crop the texture to only the pixels in the current glyphconst int charPos = (c - FONT_BEGIN_CHAR); // Position in the list of valid charactersconst int row = charPos / FONT_NUM_COLS;const int col = charPos % FONT_NUM_COLS;cropRect[0] = col * font.char_width; // Left of columncropRect[1] = row * font.char_height * 2; // Top of row// Move down to bottom of regular (one char_heigh) or bold (two char_heigh) linecropRect[1] += bold ? 2 * font.char_height : font.char_height;glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, cropRect);glDrawTexiOES(*x, *y, 0, font.char_width, font.char_height);*x += font.char_width;}glDisable(GL_BLEND); // Return to the animation's default behaviourglBindTexture(GL_TEXTURE_2D, 0);
}
初始化字体

声明一个成员变量Font。

来到android()的initFont()

这是一个文件名字符串
static const char CLOCK_FONT_ASSET[] = "images/clock_font.png";
opengl只是支持图片纹理,所以文件是一张图片
然后会把这个图片加载进来,设置宽高等等。

绘制

对这个图片进行裁剪

我们新增代码在这里TEXT_CENTER_VALUE居中显示, yc + mAndroid[0].h计算绘制的y坐标系
yc是原本Android动画的一个坐标系,但是我们不能覆盖他,所以要比他高,放到原生Android动画的上边+ mAndroid[0].h
drawClock(mClockFont, TEXT_CENTER_VALUE, yc + mAndroid[0].h);

bool BootAnimation::android()
{SLOGD("%sAnimationShownTiming start time: %" PRId64 "ms", mShuttingDown ? "Shutdown" : "Boot",elapsedRealtime());initTexture(&mAndroid[0], mAssets, "images/android-logo-mask.png");initTexture(&mAndroid[1], mAssets, "images/android-logo-shine.png");mCallbacks->init({});// clear screenglShadeModel(GL_FLAT);//qfh addbool hasInitFont = false;if (initFont(&mClockFont, CLOCK_FONT_ASSET) == NO_ERROR) {hasInitFont = true;ALOGD("android init Font ok ,fontname = %u",mClockFont.texture.name);}//qfh addglDisable(GL_DITHER);glDisable(GL_SCISSOR_TEST);glClearColor(0,0,0,1);glClear(GL_COLOR_BUFFER_BIT);eglSwapBuffers(mDisplay, mSurface);glEnable(GL_TEXTURE_2D);glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);const GLint xc = (mWidth - mAndroid[0].w) / 2;const GLint yc = (mHeight - mAndroid[0].h) / 2;// const Rect updateRect(xc, yc, xc + mAndroid[0].w, yc + mAndroid[0].h);//qfh modifyconst Rect updateRect(xc, yc, xc + mAndroid[0].w, yc + mAndroid[0].h*2);glScissor(updateRect.left, mHeight - updateRect.bottom, updateRect.width(),updateRect.height() * 2);//qfh modify// Blend stateglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);const nsecs_t startTime = systemTime();do {nsecs_t now = systemTime();double time = now - startTime;float t = 4.0f * float(time / us2ns(16667)) / mAndroid[1].w;GLint offset = (1 - (t - floorf(t))) * mAndroid[1].w;GLint x = xc - offset;glDisable(GL_SCISSOR_TEST);glClear(GL_COLOR_BUFFER_BIT);glEnable(GL_SCISSOR_TEST);glDisable(GL_BLEND);glBindTexture(GL_TEXTURE_2D, mAndroid[1].name);glDrawTexiOES(x, yc, 0, mAndroid[1].w, mAndroid[1].h);glDrawTexiOES(x + mAndroid[1].w, yc, 0, mAndroid[1].w, mAndroid[1].h);glEnable(GL_BLEND);glBindTexture(GL_TEXTURE_2D, mAndroid[0].name);glDrawTexiOES(xc, yc, 0, mAndroid[0].w, mAndroid[0].h);drawClock(mClockFont, TEXT_CENTER_VALUE, yc + mAndroid[0].h);EGLBoolean res = eglSwapBuffers(mDisplay, mSurface);if (res == EGL_FALSE)break;// 12fps: don't animate too fast to preserve CPUconst nsecs_t sleepTime = 83333 - ns2us(systemTime() - now);if (sleepTime > 0)usleep(sleepTime);checkExit();} while (!exitPending());glDeleteTextures(1, &mAndroid[0].name);glDeleteTextures(1, &mAndroid[1].name);//qfh addif (hasInitFont)glDeleteTextures(1, &mClockFont.texture.name);//qfh addreturn false;
}
opengl绘制源码分析
安卓原生的开机动画是一个渐变色,由白色到灰色的渐变,直到launcher启动完成。
主要是这两个图片起作用

initTexture就是初始化纹理的意思,这就是aosp原生的动画图片,这个Android字样是镂空的,由其他图片去填充它,

下面这是第二张图片,也加载了

一白一灰,原理就是扫光动画,它在最底层,,两张图片叠加就可以动画了,把这张图片从左往右一直反复移动,就可看到一白一灰的渐变动画了。
看下这个方法做了什么

打开一个文件转换成Bitmap
Asset* asset = assets.open(name, Asset::ACCESS_BUFFER);if (asset == nullptr)return NO_INIT;SkBitmap bitmap;sk_sp<SkData> data = SkData::MakeWithoutCopy(asset->getBuffer(false),asset->getLength());sk_sp<SkImage> image = SkImage::MakeFromEncoded(data);image->asLegacyBitmap(&bitmap, SkImage::kRO_LegacyBitmapMode);asset->close();delete asset;

这两个才是opengl部分。绑定图片纹理图案,
glScissor(updateRect.left, mHeight - updateRect.bottom, updateRect.width(),updateRect.height() * 2);
裁剪区域,不完全绘制屏幕的全部区域,选择性裁剪绘制显示区域。
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
叠加融合,就是两张图片叠加在一起绘制显示,
do {nsecs_t now = systemTime();double time = now - startTime;float t = 4.0f * float(time / us2ns(16667)) / mAndroid[1].w;GLint offset = (1 - (t - floorf(t))) * mAndroid[1].w;GLint x = xc - offset;glDisable(GL_SCISSOR_TEST);glClear(GL_COLOR_BUFFER_BIT);glEnable(GL_SCISSOR_TEST);glDisable(GL_BLEND);//绑定,绘制mAndroid[1]的图片glBindTexture(GL_TEXTURE_2D, mAndroid[1].name);glDrawTexiOES(x, yc, 0, mAndroid[1].w, mAndroid[1].h);glDrawTexiOES(x + mAndroid[1].w, yc, 0, mAndroid[1].w, mAndroid[1].h);//开启融合glEnable(GL_BLEND);//绑定 mAndroid[0]的图片,glBindTexture(GL_TEXTURE_2D, mAndroid[0].name);glDrawTexiOES(xc, yc, 0, mAndroid[0].w, mAndroid[0].h);drawClock(mClockFont, TEXT_CENTER_VALUE, yc + mAndroid[0].h);//调用opengl的方法显示到屏幕上EGLBoolean res = eglSwapBuffers(mDisplay, mSurface);if (res == EGL_FALSE)break;// 12fps: don't animate too fast to preserve CPUconst nsecs_t sleepTime = 83333 - ns2us(systemTime() - now);if (sleepTime > 0)usleep(sleepTime);checkExit();} while (!exitPending());
do,while循环绘制核心,开机动画是不断变化的,所以肯定在这个循环里实现,不断绘制的过程,绘制是有帧率的,循环不会一直执行的,因为会有功耗,所以12fps为一次绘制,一秒绘制12张图片
相关文章:
Android开机动画,framework修改Bootanimation绘制文字。
文章目录 Android开机动画,framework修改Bootanimation动画绘制文字。opengl绘制源码分析 Android开机动画,framework修改Bootanimation动画绘制文字。 frameworks/base/cmds/bootanimation/bootanimation.cpp 绘制时间的一个方法 // We render 12 or …...
2024河南高考作文ChatGPT
阅读下面的材料,根据要求写作。(60分) 随着互联网的普及、人工智能的应用,越来越多的问题能很快得到答案。那么,我们的问题是否会越来越少? 以上材料引发了你怎样的联想和思考?请写一篇文章。 要…...
整理好了!2024年最常见 20 道分布式、微服务面试题(一)
一、什么是分布式系统? 分布式系统是由多个独立的计算机(通常称为节点)组成的系统,这些计算机通过网络连接在一起,协同工作以完成一个共同的任务或服务。以下是分布式系统的关键特点和概念: 网络依赖性&am…...
要想数据形成好的数据集,必须数据治理(目的之一是防止大模型产生灰色数据等),用于炼丹(训练数据私有化模型)的数据才是好数据
数据治理:必要性、实施方法及挑战 引言 在当今数字化时代,数据已经成为企业最重要的资产之一。随着数据量的爆炸性增长,如何有效地管理和利用数据成为企业面临的重大挑战。数据治理(Data Governance)作为一种系统化的…...
外部mysql导入
利用这个命令: mysql -u username -p database_name < file.sql 然后就这样。成功导入。...
Qwen-VL论文阅读
论文地址 其他同学的详细讲解 模型结构和参数大小 (1)LLM:Qwen-7B (2)Vision Encoder:ViT架构,初始化参数是 Openclip’s ViT-bigG。 在训练和推理过程中,输入的图像都被调整到…...
超详细的java Comparable,Comparator接口解析
前言 Hello大家好呀,在java中我们常常涉及到对象的比较,不同于基本数据类型,对于我们的自定义对象,需要我们自己去建立比较标准,例如我们自定义一个People类,这个类有name和age两个属性,那么问…...
Java使用GDAL来解析KMZ及KML实战
目录 前言 一、在GQIS中浏览数据 1、关于空间参考 2、属性表格 二、GDAL的相关驱动及解析实战 1、GDAL中的KMZ驱动 2、GDAL实际解析 三、数据解析成果 1、KML解析结果 2、KMZ文件入库 四、总结 前言 在前面的博客中讲过纯Java实现Google地图的KMZ和KML文件的解析&…...
【vuex小试牛刀】
了解vuex核心概念请移步 https://vuex.vuejs.org/zh/ # 一、初始vuex # 1.1 vuex是什么 就是把需要共享的变量全部存储在一个对象里面,然后将这个对象放在顶层组件中供其他组件使用 父子组件通信时,我们通常会采用 props emit 这种方式。但当通信双方不…...
React - 实现走马灯组件
一、实现效果 二、源码分析 import {useRef, useState} from "react";export const Carousel () > {const images [{id: 3, url: https://sslstage3.sephorastatic.cn/products/2/4/6/8/1/6/1_n_new03504_100x100.jpg}, {id: 1, url: https://sslstage2.sephor…...
【学习笔记】Windows GDI绘图(十三)动画播放ImageAnimator(可调速)
文章目录 前言定义方法CanAnimate 是否可动画显示Animate 动画显示多帧图像UpdateFramesStopAnimate终止动画Image.GetFrameCount 获取动画总帧数Image.GetPropertyItem(0x5100) 获取帧延迟 自定义GIF播放(可调速) 前言 在前一篇文章中用到ImageAnimator获取了GIF动画的一些属…...
fps游戏如何快速定位矩阵
fps游戏如何快速定位矩阵 矩阵特点: 1、第一行第一列值的范围在**-1 ---- 1**之间,如果开镜之后值会变大。 2、第一行第三列的值始终为 0。 3、第一行第四列 的值比较大 , >300或者**<-300**。 根据这三个特点,定位矩阵已经足够了…...
【机器学习基础】Python编程06:五个实用练习题的解析与总结
Python是一种广泛使用的高级编程语言,它在机器学习领域中的重要性主要体现在以下几个方面: 简洁易学:Python语法简洁清晰,易于学习,使得初学者能够快速上手机器学习项目。 丰富的库支持:Python拥有大量的机器学习库,如scikit-learn、TensorFlow、Keras和PyTorch等,这些…...
R可视化:生存分析森林图
在R语言中,使用forestplot包来绘制生存分析的森林图是一个专业且直观的方式来展示各种风险因素或治疗对生存结果的影响。森林图(Forest Plot)常用于展示多项研究的效应量和其可信区间,尤其在生存分析中,它可以清晰地显示不同变量或因素对生存时间的影响程度和统计显著性。…...
一个 python+tensorFlow训练1万张图片分类的简单直观例子( 回答由百度 AI 给出 )
问题:给定一个文件夹 train_images,里面有10000张30*30像素的灰度值图片,第1~第10000张图片的名称分别为 00001.png、 00002.png、... 09999.png、10000.png,train_images 下面还有一个 image_category_map.txt文件, 文件的内容…...
DBeaver无法连接Clickhouse,连接失败
DBeaver默认下载的是0.2.6版本的驱动,但是一直连接失败: 报错提示 解决办法 点击上图中的Open Driver Configuration点击库 - 重置为默认状态在弹出的窗口中修改驱动版本号为0.2.4或者其他版本(我没有试用过其他版本)࿰…...
python基础实例
下一个更大的数 定义一个Solution类,用于实现next_great方法 class Solution: def next_great(self, nums1, nums2): # 初始化一个空字典answer,用于存储答案 answer {} # 初始化一个空列表stack,用于存储待比较的数字 stack [] # 遍历nu…...
ADASIS V2 协议-1
ADAS V2协议-1 1 简介2 版本控制3 ADASIS v23.1 ADASIS v2 Horizon (地平线)3.2 ADASIS v2的构建3.3 ADASIS v2 Horizon Provider (ADAS V2地平线提供者)3.4 paths and offsets (路径和偏移量)3.5 Path Pro…...
人工智能安全风险分析及应对策略
文│中国移动通信集团有限公司信息安全管理与运行中心 张峰 江为强 邱勤 郭中元 王光涛 人工智能(AI)是引领新一轮科技革命和产业变革的关键技术。人工智能赋能网络安全的同时,也会带来前所未有的安全风险。本文在介绍人工智能技术赋能网络安…...
Python驱动下的AI革命:技术赋能与案例解析
在当今这个信息化、数据化的时代,人工智能(AI)已经成为推动社会发展的重要力量。而Python,作为一种简单易学、功能强大的编程语言,在AI领域的应用中发挥着至关重要的作用。本文将探讨Python在AI领域的应用、其背后的技…...
SkyWalking 10.2.0 SWCK 配置过程
SkyWalking 10.2.0 & SWCK 配置过程 skywalking oap-server & ui 使用Docker安装在K8S集群以外,K8S集群中的微服务使用initContainer按命名空间将skywalking-java-agent注入到业务容器中。 SWCK有整套的解决方案,全安装在K8S群集中。 具体可参…...
调用支付宝接口响应40004 SYSTEM_ERROR问题排查
在对接支付宝API的时候,遇到了一些问题,记录一下排查过程。 Body:{"datadigital_fincloud_generalsaas_face_certify_initialize_response":{"msg":"Business Failed","code":"40004","sub_msg…...
Python爬虫实战:研究feedparser库相关技术
1. 引言 1.1 研究背景与意义 在当今信息爆炸的时代,互联网上存在着海量的信息资源。RSS(Really Simple Syndication)作为一种标准化的信息聚合技术,被广泛用于网站内容的发布和订阅。通过 RSS,用户可以方便地获取网站更新的内容,而无需频繁访问各个网站。 然而,互联网…...
为什么需要建设工程项目管理?工程项目管理有哪些亮点功能?
在建筑行业,项目管理的重要性不言而喻。随着工程规模的扩大、技术复杂度的提升,传统的管理模式已经难以满足现代工程的需求。过去,许多企业依赖手工记录、口头沟通和分散的信息管理,导致效率低下、成本失控、风险频发。例如&#…...
vue3 字体颜色设置的多种方式
在Vue 3中设置字体颜色可以通过多种方式实现,这取决于你是想在组件内部直接设置,还是在CSS/SCSS/LESS等样式文件中定义。以下是几种常见的方法: 1. 内联样式 你可以直接在模板中使用style绑定来设置字体颜色。 <template><div :s…...
Java 加密常用的各种算法及其选择
在数字化时代,数据安全至关重要,Java 作为广泛应用的编程语言,提供了丰富的加密算法来保障数据的保密性、完整性和真实性。了解这些常用加密算法及其适用场景,有助于开发者在不同的业务需求中做出正确的选择。 一、对称加密算法…...
2025盘古石杯决赛【手机取证】
前言 第三届盘古石杯国际电子数据取证大赛决赛 最后一题没有解出来,实在找不到,希望有大佬教一下我。 还有就会议时间,我感觉不是图片时间,因为在电脑看到是其他时间用老会议系统开的会。 手机取证 1、分析鸿蒙手机检材&#x…...
10-Oracle 23 ai Vector Search 概述和参数
一、Oracle AI Vector Search 概述 企业和个人都在尝试各种AI,使用客户端或是内部自己搭建集成大模型的终端,加速与大型语言模型(LLM)的结合,同时使用检索增强生成(Retrieval Augmented Generation &#…...
HDFS分布式存储 zookeeper
hadoop介绍 狭义上hadoop是指apache的一款开源软件 用java语言实现开源框架,允许使用简单的变成模型跨计算机对大型集群进行分布式处理(1.海量的数据存储 2.海量数据的计算)Hadoop核心组件 hdfs(分布式文件存储系统)&a…...
JS手写代码篇----使用Promise封装AJAX请求
15、使用Promise封装AJAX请求 promise就有reject和resolve了,就不必写成功和失败的回调函数了 const BASEURL ./手写ajax/test.jsonfunction promiseAjax() {return new Promise((resolve, reject) > {const xhr new XMLHttpRequest();xhr.open("get&quo…...
