开机关机动画工作流程
一,开机画面切换过程
(1) Linux 系统启动,出现Linux小企鹅画面(由内核实现)。
(2) Android平台启动初始化,出现"A N D R I O D"文字字样画面。
(3) Android平台上层图形系统启动,出现含闪动的ANDROID字样的动画图片(start)。
二,(2)和(3)启动运行的过程
(1) Android 系统启动后,init.c中main()调用load_565rle_p_w_picpath()函数读取/initlogo.rle(一张565 rle压缩的位图),如果读取成功,则在/dev/graphics/fb0显示Logo图片;如果读取失败,则将/dev/tty0设为TEXT模式,并打开/dev/tty0,输出文本“A N D R I O D”字样。E8,E9已经将此部分会直接路过,E8直接注释此过程
相应代码如下:
- static int console_init_action(int nargs, char **args)
- {
- int fd;
- char tmp[PROP_VALUE_MAX];
- if (console[0]) {
- snprintf(tmp, sizeof(tmp), "/dev/%s", console);
- console_name = strdup(tmp);
- }
- fd = open(console_name, O_RDWR);
- if (fd >= 0)
- have_console = 1;
- close(fd);
- /*
- //查看init.h文件
- //#define INIT_IMAGE_FILE "/initlogo.rle"
- //ADB SHELL查看根目录没有此张图片
- //加载initlogo.rle文件
- if( load_rle_p_w_picpath(INIT_IMAGE_FILE) ) {
- //此时fd 是/dev/tty0对应的是输出端口
- //tty1表示输入端口,tty2貌似表示错误信息
- fd = open("/dev/tty0", O_WRONLY);//将/dev/tty0设为text模式
- if (fd >= 0) {
- const char *msg;
- msg = "\n"
- "\n"
- "\n"
- "\n"
- "\n"
- "\n"
- "\n" // console is 40 cols x 30 lines
- "\n"
- "\n"
- "\n"
- "\n"
- "\n"
- "\n"
- "\n"
- " A N D R O I D ";
- write(fd, msg, strlen(msg));
- close(fd);//关闭接口
- }
- }
- */
- return 0;
- }
相关代码:
- system/core/init/init.c
- system/core/init/init.h
- system/core/init/init.rc
- system/core/init/logo.c
*.rle文件的制作步骤:
- a. 使用GIMP或者Advanced Batch Converter软件,将图象转换为RAW格式;
- b. 使用android自带的rgb2565工具,将RAW格式文件转换为RLE格式(如:rgb2565 -rle < initlogo.raw > initlogo.rle)。
- 注:修改这几个地方的代码编译过后要重新烧写recovery,boot
(2),开机动画(闪动的ANDROID字样的动画图片)
我们最主要经常要修改的这是这部内容,这里包含两种动画类型:
1,第一种类似于Windows系统的滚动条,是由前景和背景两张PNG图片组成,对应原文件位于frameworks/base/core/res/assets/p_w_picpaths/。前景图片(android-logo-mask.png)上的Android文字部分镂空,背景图片(android-logo-shine.png)则是简单的纹理。系统登录时,前景图片在最上层显示,程序代码(BootAnimation.android())控制背景图片连续滚动,透过前景图片文字镂空部分滚动显示背景纹理,从而实现动画效果。
图片1: 前景图片 图片2: 背景图片
2,制件开机动画包,开机动画服务程序启动以后会先在系统指定目录检查此包是否存在,如果存在,系统将执行此包中的动画,如果检查系统不存在此包,此时系统才会去按第一方式播放动画,这里包中的内容是通过一张一张图片连续播放来实现动画效果的,最后要生成一个类似bootanimation.zip的包
3,执行过程,init.c解析init.rc(其中定义服务:“service bootanim /system/bin/bootanimation”),bootanim服务由SurfaceFlinger.readyToRun()(property_set("ctl.start", "bootanim");)执行开机动画、bootFinished()(property_set("ctl.stop", "bootanim");)执行停止开机动画。 BootAnimation.h和BootAnimation.cpp文件放在了/frameworks/base/cmds/bootanimation目录下了,增加了一个入口文件bootanimation_main.cpp。Android.mk文件中可以看到,将开机动画从原来的SurfaceFlinger里提取出来了,生成可执行文件:bootanimation。
Android.mk代码如下:
//=============Android.mk======================
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= /
bootanimation_main.cpp /
BootAnimation.cpp
# need "-lrt" on Linux simulator to pick up clock_gettime
ifeq ($(TARGET_SIMULATOR),true)
ifeq ($(HOST_OS),linux)
LOCAL_LDLIBS += -lrt
endif
endif
LOCAL_SHARED_LIBRARIES := /
libcutils /
libutils /
libui /
libcorecg /
libsgl /
libEGL /
libGLESv1_CM /
libmedia
LOCAL_C_INCLUDES := /
$(call include-path-for, corecg graphics)
LOCAL_MODULE:= bootanimation
include $(BUILD_EXECUTABLE)
//==========================================
开机动画第一个入口:bootanimation_main.cpp
int main(int argc, char** argv)
{
…..........
if (!noBootAnimation) {
sp proc(ProcessState::self());
ProcessState::self()->startThreadPool();
//初始化开机动画,开始播放开机动画.booted传下去的开机操作还是关机操作的参数
sp boot = new BootAnimation(booted);
//初始化开机声音,开始播放开机声音.这个类是根据开机动画自定义的,可根据需求自行修改删除
sp bootsound = new BootAnimationSound(booted);
IPCThreadState::self()->joinThreadPool();
}
}
根据bootanimation_main.cpp将会初始化 BootAnimation类.下面我们来查看 BootAnimation.cpp文件.通过BootAnimation 构造函数来初始化 sbootanimation变量.根据sbootanimation来实现开关机播放不同的动画.判断开机还是关机可通过上面传过来的参数确定
BootAnimation::BootAnimation(bool shutdownAnimation) : Thread(false)
{
mSession = new SurfaceComposerClient();
mShutdownAnimation = shutdownAnimation;
//权宜之计
if (mShutdownAnimation) {
// 关机时播放的动画包
mSession->setOrientation(0, 0, 0);
sprintf(sbootanimation, "/system/media/shutdownanimation.zip");
}else{
// 开机时播放的动画包
sprintf(sbootanimation, "/system/media/bootanimation.zip");
}
}
此处可以看到 sbootanimation定义是一个zip包路径,通过这个我们可以知道,如果要通过第二种方法实现开关机动画可将制作的zip包放在/system/media/目录下文件名一致便可以了,后面会给出制作zip包的方法。如果是用第一种方法只需修改上面提到的两个图片即可。
mSession->setOrientation(0, 0, 0);此条语句是关机强制横屏,修改可通过第二个参数修改.值分别对应(0->0度,1->90度,2->180度,3->270度,)具体可修改查看效果
根据mAndroidAnimation的值来确定是播放第一种动画效果还是第二种动画效果
BootAnimation::threadLoop()
if (mAndroidAnimation) {
r = Android(); // 执行android字体闪动的图片
} else {
r = movie(); // 执行bootanimation.zip中提供的动画图片
}
==> BootAnimation::Android()会加载"p_w_picpaths/android-logo-mask.png"和"p_w_picpaths/android-logo-shine.png"
==> BootAnimation::movie()会加载bootanimation.zip中的内容
这里是开机动画,下面是开机音乐的代码,流程跟开机动画类型
BootAnimationSound.cpp
和开机动画一样, 初始化bootsound变量,来实现开关机播放不同的音乐,判断开机还是关机可通过上面传过来的参数确定
BootAnimationSound::BootAnimationSound(bool booted) : Thread(false)
{
mShutdownAnimation = booted;
if (mShutdownAnimation) {
// 关机时播放的声音
sprintf(bootsound, "system/media/audio/ui/power_off.mp3");
}else{
// 开机时播放的声音
sprintf(bootsound, "system/media/audio/ui/power_on.mp3");
}
}
通过bootsound我们知道要将你的音频文件放在system/media/audio/ui/目录即可播放声音了,具体实现播放声音的操作看下文,比较简单, playSound类实现播放声音的。
void BootAnimationSound::playSound()
{
MediaPlayer* mp = new MediaPlayer();
if (mp->setDataSource(bootsound, NULL) == NO_ERROR) {
/*系统启动时声音从扬声器出来,而关机时如果插耳机则会从耳机出来,所以在
* 这里强制设定。但是,这个API 涉及许可,许可服务 PermissionController
* 在 ActivityManagerService 启动,而ActivityManagerService 启动时间比
* SurfaceFlinger 和 Audio 都晚,从而导致开机时动画播放一段时间才有声
* 音。所以加了此判定。
* */
if(mShutdownAnimation) {
mp->setAudioStreamType(AudioSystem::ENFORCED_AUDIBLE);
}else{
sleep(2);
}
mp->prepare();
mp->start();
/* start 之后,设置音量才有效果。 start 之前设音量没有效果的。*/
mp->setVolume(0.4, 0.4);
} else {
LOGE("Failed to load CameraService sounds: system/media/audio/ui/power_on_off.ogg");
}
}
代码比较简单,但还是一点要特别强调在设置开关机音量的时候,执行过mp->start();以后再执行mp->setVolume(0.4, 0.4);才会有效果,这是一个很神奇的一个问题,我们徐申龙徐工通过调试很久才找到这个很操蛋的问题,注意这点会给你节省不少时间,
最后别忘了在Android.mk文件还需要引入播放声音库
LOCAL_SHARED_LIBRARIES := \
libcutils \
libutils \
libbinder \
libui \
libskia \
libEGL \
libGLESv1_CM \
libgui \
libmedia
请注意,libmedia是新添加的;
bootanimation.zip包的制做
第一步,我们将png图片转换成colormap:8bit 以缩小文件占用磁盘空间 (以下是ubuntu命令,不用linux,可以用windows下的做图工具来转换图片格式):
convert -type palette boot_003.jpg boot_003.convert.png
做好了图片,就需要把图片打成bootanimation.zip包了。
这个包,除了图片目录,还有一个desc.txt的文件,这个文本文件是用来告诉系统,如何使用图片目录来实现动画的。 所以有一定的语法,不过很简单:
目标屏幕宽度(480) 目标屏幕高度(800) 每次帧间隔
p 重复次数 播放完成后停顿 图片文件夹名1
p 重复次数 播放完成后停顿 图片文件夹名2
以一个desc.txt为例:
480 800 15 图片宽度480,高度800,这是我们I9000屏幕参数,最后15是播放动画的每秒帧率。就是一秒钟播放多少张图片,动画的最原始实现。小时候大家都玩过吧
p 1 0 foldername // p 是一个分隔符,1 表示播放一遍,0表示播放完后停顿 0 帧,最后是图片所在的zip包里的目录名。比如你的zip包里最后是这么个结构
// folder0(里面包含很多图片) + desc.txt, 那么你可以在这里把foldername 替换成folder0
根据这个语法,我们也可以自定义各种动画形式,例如下面所示:
p 2 30 folder0 将folder0里的图片,播放2遍,播放完一遍后停顿30帧,因为我们之前设置了帧率是15帧每秒,那么这里就等于停顿2秒。
p 0 0 folder1 将folder1里的图片无限循环播放,每次播放不停顿。
如果你设置的宽度和高度不充满屏幕也没关系,剩余区域,系统会填充黑色。如果你设置的宽度和高度大过屏幕,系统会自动裁剪显示居中部分的图片区域。
4. 将转换好的图片集打包在不同的目录下, 然后把图片目录和一个描述动画的desc.txt 无压缩率格式打包成bootanimation.zip, 下面是ubuntu命令,你可以用winrar等工具,但是注意要选择无压缩率,无损压缩。另外保持压缩包后的目录结构。
zip -0 -r bootanimation.zip part0 part1 desc.txt
5. 最后将这个zip文件 拷贝到你的机器里 /data/local/bootanimation.zip
需要注意的是 如果你使用winrar进行压缩打包的话,需要设置参数如下:
压缩格式选zip
压缩方式选:存储(即不压缩)