最近在修改一些应用层的动画与Logo的框架?这里揭开android开机动画的神秘面纱。
1、制作开关机动画
1.1 开机动画的位置
system/media/bootanimation.zip,要修改开机动画就是修改bootanimation这个压缩文件。如果不存在该压缩包,使用原生自带的资源,其路径在system/framework/framework-res.apk/assets/images(Android-logo-mask.png,Android-logo-shine.png),但是比较难看,比较常见的就是“android”。所以要定制自己的开关机动画一般都是在system/media/目录下放置bootanimation.zip和shutanimation.zip.这里以开机动画为例,关机动画和开机动画其原理一样。
制作动画需要part1 ,part2 ,desc.txt 添加压缩到bootanimation.zip/shutanimation.zip 格式,并命名为bootanimation/shutanimation.zip,压缩方式为储存格式。
1.2 bootanimation.zip文件结构
bootanimation里面主要包含一个desc.txt以及N个文件夹。而文件夹里面放着的就是开机动画的图片资源。decs.txt的作用就是指导系统如何去执行开机动画。
desc.txt编写规范,例如开机动画需要用到2个文件夹,分别是part1和part2,开机的时候,先把part1里面的图片都播放一遍,然后再循环播放part2里面的文件,直到进入系统,decs.txt文档的内容如下:
320 480 12
p 1 0 part1
p 0 0 part2
320 480是代表屏幕的分辨率,12表示12帧每秒,简单地说12代表一秒钟播放12张图片;
p 1 0 part1:p就是play。1是播放一次,0是无限次。0代表阶段间隔帧数为0。part1就是说,这条指令是针对part1这个文件夹的;
p 0 0 part2:第一个0这里是代表循环播放,第二个0和上面第二条指令一样。part2就是第二个文件夹。
总结规则如下:
第一条指令:[屏幕的分辨率] [播放频率]
第二条指令:[p] [播放次数] [间隔帧数] [文件夹]
第N条指令: 同上
1.3 压缩包
把需要用到的part文件夹跟decs.txt打包成zip格式,必须是zip,不能是rar,且打包的时压缩方式选择“存储”模式。然后改名成为bootanimation.zip,最后将制作好的zip包push到/system/media目录下。
注意:bootanimation不能太大,一般最好不要超过3M。
1.4 查看动画
在终端中输入命令:
adb shell---> cd /system/bin--->bootanimation 或者bootanimation shut
这样不用重启即可查看定制的动画,方便。
1.5 硬性条件
手机必须有root权限,否则我们制作好的图片资源没办法push到/system/media目录,另外执行bootanimaiton也有可能没有权限,所以这里要定制自己的手机必须有root权限,当然了至于使用什么样的方式大家可以根据自己的爱好,各显神通。
2、播放原理
通过上面的准备开机资源已经制作好了,那android是怎么来实现播放的。首先对于开关机动画的播放,android专门使用了一个 native service来实现播放(/system/bin/bootanimation),包括开机铃声的实现也是用该service来实现的。
2.1 bootanimation的启动
Android系统在init.rc中定义了很多Service,具体定义格式可以参考《Android Platform Developer’s Guide》中的“Android Init Language”。Init.rc中定义的Service将会被Init进程创建,其中已经定义的服务就包含bootanimation。
每一项服务必须在/init.rc中定义.Android系统启动时,init守护进程将解析init.rc和启动属性服务,属性“ ctl.start ”和“ctl.stop ”是用来启动和停止服务的。一旦收到设置“ ctrl.start ”属性的请求,属性服务将使用该属性值作为服务名找到该服务,启动该服务。这项服务的启动结果将会放入“ init.svc.<服务名>“属性中 。
service bootanim /system/bin/bootanimation
user graphics
group graphics system audio qcom_oncrpc
disabled
oneshot
定义了一个bootanim的服务,对应执行/system/bin/bootanimation
disabled 表示init进程创建只是创建它,但不立刻执行;
oneshot 表示该服务只执行一次;
2.2 开机动画调用
通过上面可知,bootanimation的调用同故宫clt.start 和ctl.stop来实现的,当我们开机启动时,系统内核起来后,启动android,这时就会启动开机动画具体是在
SurfaceFlinger.cpp的readyToRun方法中调用,为什么会在这调用,请回顾一下开机流程。
status_t SurfaceFlinger::readyToRun()
{
// start boot animation service
property_set(“ctl.start”, “bootanim”);// }
当android启动完成后,关闭掉开机动画
void SurfaceFlinger::bootFinished()
{
//stop bootanim service
property_set("ctl.stop", "bootanim");
}
2.3 bootanimation 源码分析
代码所在位置:/frameworks/base/cmds/bootanimation,其主要包含以下三个文件
BootAnimation_main.cpp
BootAnimation.h
bootAnimation.cpp
2.3.1 Bootanimation_main.cpp
该文件是主入口文件;
int main(int argc, char** argv)
{
#if defined(HAVE_PTHREADS)
setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_DISPLAY);
#endif
char value[PROPERTY_VALUE_MAX];
property_get("debug.sf.nobootanimation", value, "0");
int noBootAnimation = atoi(value);
LOGI_IF(noBootAnimation, "boot animation disabled");
if (!noBootAnimation) {
sp<ProcessState> proc(ProcessState::self());
ProcessState::self()->startThreadPool();
// create the boot animation object
bool setBoot = true;
bool setRotated = false;
bool sePaly = true;
if(argc > 1){
if(!strcmp(argv[1],"shut"))
setBoot = false;
}
if(argc > 2){
if(!strcmp(argv[2],"nomp3"))
sePaly = false;
}
if(argc > 3){
if(!strcmp(argv[3],"rotate"))
setRotated = true;
}
char volume[PROPERTY_VALUE_MAX];
property_get("persist.sys.mute.state", volume, "-1");
int nVolume = -1;
nVolume = atoi(volume);
if(nVolume == 0 || nVolume == 1 ){
sePaly = false;
}
sp<BootAnimation> boot = new BootAnimation(setBoot,sePaly,setRotated);
IPCThreadState::self()->joinThreadPool();
}
return 0;
}
其主要的功能是根据传进来的参数决定是是要播放开机还是关机动画/铃音,并且启动BootAnimation;
2.3.2 BootAnimation.cpp
BootAnimation.cpp集成自Thread,在创建时会调用readyToRun()->threadLoop()。
status_tBootAnimation::readyToRun() {
……………省略………………………
mAndroidAnimation = false;
if(bBootOrShutDown){
status_t err = mZip.open("/data/local/bootanimation.zip");
if (err != NO_ERROR) {
err =mZip.open("/system/media/bootanimation.zip");
if (err != NO_ERROR) {
mAndroidAnimation = true;
}
}
}else {
if(!bShutRotate){
status_terr = mZip.open("/data/local/shutanimation.zip");
if (err != NO_ERROR) {
err =mZip.open("/system/media/shutanimation.zip");
if (err != NO_ERROR) {
mAndroidAnimation = true;
}
}
}
}
return NO_ERROR;
}
readyToRun() 方法判断/system/media/bootanimation.zip(shutanimaion.zip)是否存在,如果存在,则将 mAndroidAnimation 设置false,这个变量决定threadLoop中调用android()还是movie()来具体实现动画的播放。
boolBootAnimation::threadLoop()
{
........省略........
if(!bBootOrShutDown){
pSoundFileName="/data/local/shutaudio.mp3";
pBackupSoundFileName="/system/media/shutaudio.mp3";
} else {
pSoundFileName="/data/local/bootaudio.mp3";
pBackupSoundFileName="/system/media/bootaudio.mp3";
}
if (mAndroidAnimation)
r = android();
} else {
r = movie();
}
}
threadLoop()方法根据 mAndroidAnimation 变量调用android()/movie(). 如果system/media/shutanimation.zip/bootanimation.zip存在的话,调用movie(),该接口会解析zip文件中的desc.txt文件,根据txt文件中的配置来播放动画。否则就调用android来播放原生自带的资源。