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张图片

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

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

相关文章

Linux网络编程:数据链路层协议

目录 前言&#xff1a; 1.以太网 1.1.以太网帧格式 1.2.MTU&#xff08;最大传输单元&#xff09; 1.2.1.IP协议和MTU 1.2.2.UDP协议和MTU 1.2.3.TCP协议和MTU 2.ARP协议&#xff08;地址解析协议&#xff09; 2.1.ARP在局域网通信的角色 2.2.ARP报文格式 2.3.ARP报文…

数据库中锁的机制和MVCC协议以及隔离级别

文章目录 数据库中的锁锁与索引的关系释放锁的时机乐观锁与悲观锁行锁与表锁共享锁与排它锁意向锁记录锁、间隙锁和临键锁记录锁间隙锁临键锁 锁优化方案 MVCC协议MySQL的隔离级别脏读和幻读快照读和当前读 版本链Read ViewRead View 与已提交读Read View 与可重复读m_up_limit…

工业无线wifi系统搭配高速路由,解决联网及数据传输

​面对日益复杂的工业应用场景,企业对无线网络的高速、可靠和安全提出了更高要求。星创易联SR600系列多网口4G路由器应运而生,为工业无线WiFi系统提供了一个性能卓越的高速路由方案。&#xff08;key-iot.com/iotlist/sr600-5.html&#xff09; SR600路由器集4G LTE、虚拟专用…

直播美颜工具解析:美颜SDK核心技术与性能优化方法

本篇文章&#xff0c;小编将深入解析直播美颜SDK的核心技术及其性能优化方法&#xff0c;以期为开发者提供有价值的参考。 一、美颜SDK核心技术 1.实时人脸检测与识别 美颜SDK的核心技术之一是实时人脸检测与识别。这项技术基于深度学习算法&#xff0c;能够快速、准确地识别…

零刻SER8 AMD 8845Hs Ryzen AI 本地部署大语言模型教程!

零刻SER8 8845HS,配备了一个内置的 NPU&#xff08;神经网络处理单元&#xff09;&#xff0c;可以通过LM Studio语言大模型来部署己的 GPT 模型 AI 聊天机器人&#xff0c;AI 助手已迅速成为提高生产力、效率&#xff0c;甚至是头脑风暴的关键资源。在本地机器上运行 AI 聊天机…

数字人私有化部署系统厂商大比拼

数字人系统私有化部署放在2022年简直是天方夜谭&#xff0c;没有投资个上百万和数百万想建立自己的一个数字人saas平台是可望不可及的事。但是到了2023年&#xff0c;数字人私有化部署系统价格从最初的数十万&#xff0c;迅速被打压到数万元就可以拥有一个自己的数字人平台。可…

ArcGIS中几个好用的空间分析工具

ArcGIS是一款经典的GIS应用&#xff0c;其空间分析能力很强&#xff0c;有着丰富的空间分析工具。今天&#xff0c;我们一起来了解几个好用的空间分析工具的功用及操作。 注&#xff1a;演示版本为ArcMap10.4.1 1.方向分布&#xff08;标准差椭圆&#xff09; 路径&#xff…

陆面生态水文模拟与多源遥感数据同化的实践技术应用

了解陆表过程的主要研究内容以及陆面模型在生态水文研究中的地位和作用&#xff1b;熟悉模型的发展历程&#xff0c;常见模型及各自特点&#xff1b;理解Noah-MP模型的原理&#xff0c;掌握Noah-MP模型在单站和区域的模拟、模拟结果的输出和后续分析及可视化等方法&#xff1b;…

(一文读懂)大模型到底是怎么生成文字的?

前言 在人工智能的领域&#xff0c;大模型在去年已经成为了一个热门的话题。 各大厂商如谷歌、微软、OpenAI等&#xff0c;都在积极研发和应用大模型技术。 这些模型在语言理解、图像识别、推荐系统等方面都表现出了惊人的能力&#xff0c;甚至在某些任务上&#xff0c;已经…

【JS红宝书学习笔记】第6章 集合引用类型

第6章 集合引用类型 对象 数组与定型数组 Map、WeakMap、Set 以及 WeakSet 类型 1. object 很适合存储和在应用程序间交换数据。 显式创建object的两种方式&#xff1a; &#xff08;1&#xff09;new操作符 let person new Object(); person.name "Nicholas";…

MySQL是怎么保证持久性的(redo log日志相关)

Mysql中 事务的很多实现&#xff0c;都是因为有日志的支撑&#xff0c;比如binlog、undo log、redo log等 MySQL是怎么保证持久性的 持久性是指&#xff0c;事务一旦提交&#xff0c;它对数据库的改变就应该是永久性的&#xff0c;接下来的其他操作或故障不能对其有影响。In…

大数据数据治理

大数据数据治理介绍 大数据数据治理是一个复杂的过程&#xff0c;涉及到数据的标准化、融通、关联、解析、聚合等一系列活动。其核心目标是在确保数据安全的基础上&#xff0c;提高大数据资源和资产的可用性、易用性和可靠性&#xff0c;从而显著提升大数据资源和资产的价值7。…

Ktor库的高级用法:代理服务器与JSON处理

在现代网络编程中&#xff0c;Ktor是一个高性能且易于使用的框架&#xff0c;它提供了对异步编程、WebSockets、HTTP客户端和服务器等特性的原生支持。Ktor是使用Kotlin语言编写的&#xff0c;充分利用了Kotlin的协程特性来简化异步编程。本文将深入探讨Ktor库的高级用法&#…

AlDente Pro for Mac(电池最大充电限制工具)v1.24激活版

AlDente Pro for Mac是一款运行在MacOS平台上专业的电池最大充电限制工具。通过 AlDente Pro 您可以设置电池的最大充电百分比设置为 20&#xff05; 至 100&#xff05;&#xff0c;然后&#xff0c;它将保持在所需的电池百分比&#xff0c;然后再次使用电源适配器进行充电。 …

安徽某高校数据挖掘作业4-5 (与一些碎碎念)

1. 编写程序求函数、、的极限。 解答&#xff1a; import sympy as sp# 定义符号变量 x x sp.symbols(x)# 定义函数 f1 sp.sin(20 * x) / x f2 (1 4 * x)**(2 / x) f3 (1 4 / x)**(2 * x)# 计算极限 limit1 sp.limit(f1, x, 0) limit2 sp.limit(f2, x, 0) limit3 sp…

跨域请求解决方法----不允许有多个 ‘Access-Control-Allow-Origin‘ CORS 头

后端配置了代码&#xff1a; spring:application:name: spzx-server-gatewaycloud:nacos:discovery:server-addr: localhost:8848gateway:discovery:locator:enabled: trueglobalcors:cors-configurations:[/**]:allowedOriginPatterns: "*"# 允许请求中携带的头信息…

连锁门面预付费电表管理系统

1.什么叫连锁门面预付费电表管理系统? 连锁门面预付费电表管理系统是一种前沿的电力管理解决方案&#xff0c;尤其适用于拥有众多分店的服务提供商。该系统容许用户使用电力以前预先支付花费&#xff0c;有效解决传统式后付模式的收支明细纠纷案件和扣费难题。 2.系统的核心…

非递归实现快排排序及归并排序(尾篇)

1.快速排序&#xff08;双指针实现&#xff09; 2.非递归实现快排 3.递归实现归并排序 4.非递归实现归并排序 5.总代码 1.快速排序&#xff08;双指针实现&#xff09; 俩有个指针一前一后的排放着&#xff0c;cur先走并且去找比kye对应值小的数组值&#xff0c;一旦找到后…

x86国产化麒麟系统上安装docker及问题解决

以前感觉安装docker没有问题&#xff0c;所以没有记录怎么安装的&#xff0c;最近在国产化系统上安装docker总是失败&#xff0c;经过仔细研究完全解决了该问题&#xff0c;特此记录。 参考链接&#xff1a; 在 OpenKylin 上安装 Docker 按照上面的链接可以知道整个docker安装…

EMC整改学习-笔记

EMC整改学习-笔记 来自赛盛技术的笔记 如果我拿到一个产品超标的一个频谱图的话&#xff0c;首先我们可以对比做一个分析。来确定你干扰源的一个分类和定义是哪些。是你这个产品类型&#xff0c;什么样的电路对应什么样的一个。从我们的一个大量的一个测试数据的经验来看&…