/********************************************************************************************
* author:[email protected]大钟
* E-mail:[email protected]

*site:http://www.idealpwr.com/

*深圳市动力思维科技发展有限公司
* http://blog.csdn.net/conowen
* 注:本文为原创,仅作为学习交流使用,转载请标明作者及出处。

********************************************************************************************/


1、修改Android的开关机铃声


待续……


2、修改Android开关机画面


开机画面包括三个过程

2.1、bootloader的开机画面

待续……


2.2、Android系统init时的开机画面

修改Android的开关机铃声、Android开关机画面与动画(附代码流程)_第1张图片


修改Android的开关机铃声、Android开关机画面与动画(附代码流程)_第2张图片


修改Android的开关机铃声、Android开关机画面与动画(附代码流程)_第3张图片



2.2.1、Android系统init时,装载initlogo.rle的简单流程。

Androidinit时,会读取 /initlogo.rle文件,如果读取成功,就会在/dev/graphics/fb0显示initlogo.rle;如果读取失败,打开/dev/tty0,输出文本“A N D R I O D”字样。

相关代码:

/system/core/init/init.c
/system/core/init/init.h
/system/core/init/init.rc
/system/core/init/logo.c


@/system/core/init/init.c

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);    if( load_565rle_image(INIT_IMAGE_FILE) ) {//在init.h文件定义           //#define INIT_IMAGE_FILE    "/initlogo.rle"        fd = open("/dev/tty0", O_WRONLY);                 if (fd >= 0) {//如果找不到initlog.rle图片,则打开TEXT模式,            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 ";//打印ANDROID字样的问题。            write(fd, msg, strlen(msg));            close(fd);        }    }    return 0;}


@/system/core/init/logo.c

static int fb_open(struct FB *fb){    fb->fd = open("/dev/graphics/fb0", O_RDWR);//会在/dev/graphics/fb0显示initlogo.rle    if (fb->fd < 0)        return -1;    if (ioctl(fb->fd, FBIOGET_FSCREENINFO, &fb->fi) < 0)        goto fail;    if (ioctl(fb->fd, FBIOGET_VSCREENINFO, &fb->vi) < 0)        goto fail;    fb->bits = mmap(0, fb_size(fb), PROT_READ | PROT_WRITE,                     MAP_SHARED, fb->fd, 0);    if (fb->bits == MAP_FAILED)        goto fail;    return 0;fail:    close(fb->fd);    return -1;}/************部分省略****************//* 565RLE image format: [count(2 bytes), rle(2 bytes)] */int load_565rle_image(char *fn){    struct FB fb;    struct stat s;    unsigned short *data, *bits, *ptr;    unsigned count, max;    int fd;    if (vt_set_mode(1))         return -1;    fd = open(fn, O_RDONLY);    if (fd < 0) {        ERROR("cannot open '%s'\n", fn);        goto fail_restore_text;    }    if (fstat(fd, &s) < 0) {        goto fail_close_file;    }    data = mmap(0, s.st_size, PROT_READ, MAP_SHARED, fd, 0);    if (data == MAP_FAILED)        goto fail_close_file;    if (fb_open(&fb))        goto fail_unmap_data;    max = fb_width(&fb) * fb_height(&fb);    ptr = data;    count = s.st_size;    bits = fb.bits;    while (count > 3) {        unsigned n = ptr[0];        if (n > max)            break;        android_memset16(bits, ptr[1], n << 1);        bits += n;        max -= n;        ptr += 2;        count -= 4;    }    munmap(data, s.st_size);    fb_update(&fb);    fb_close(&fb);    close(fd);    unlink(fn);    return 0;fail_unmap_data:    munmap(data, s.st_size);    fail_close_file:    close(fd);fail_restore_text:    vt_set_mode(0);    return -1;}


2.2.2、修改方法:

2.2.2.1、找到一张符合机器分辨率的bmp图像,把bmp图片转换成为raw图像

要注意分辨率问题,若是不符合机器分辨率,可能显示拉伸或者花屏之类等等各种情况。

使用到的工具imagemagick,若没有,用apt安装即可。

convert -depth 8 initlogo.bmp rgb:initlogo.raw

2.2.2.2、把raw图像转换为rle图像即可。


使用的工具rgb2565,编译Android系统源代码成功时,最红再编译SDK(执行make PRODUCT-sdk-sdk),编译SDK成功之后,在\out\host\linux-x86\bin生成rgb2565。然后在rgb2565目录下执行如下命令

./rgb2565 -rle < initlogo.raw > initlogo.rle


2.2.2.3、替换文件

若是想在虚拟机上面测试,当系统编译完成之后,把initlogo.rle文件copy到\out\target\product\generic\root目录下,然后把\out\target\product\generic的ramdisk.img删除掉,再执行以下make命令,就可以生成新的ramdisk.img了,把ramdisk.img替代虚拟机镜像的ramdisk.img目录即可。因为root目录是ramdisk.img解包之后的文件夹,这一步只是把rle文件打包到ramdisk.img里面。


若是在一些机器的SDK修改开机画面,则可以到devices目录下的相应芯片厂商那里找找mk文件,然后编辑

如tcc892X是如下路径

\device\telechips\tcc8920st\device_base.mk

修改或者添加为

PRODUCT_COPY_FILES += \ device/telechips/common/initlogo_conowen.rle:root/initlogo.rle

事实上,这就是一个copy的过程,和之前的添加第三方apk没啥区别。



2.3、Android系统最后的开机动画(类似windows的进度条)


相关代码:

frameworks\base\cmds\bootanimation\BootAnimation.cpp

frameworks\base\cmds\bootanimation\BootAnimation.h


2.3.1、Android开机动画有两种方式,一种是系统的默认开机动画,由两张png图片构成,由代码控制背景图片的移动,造成动画效果;

相关资源

frameworks\base\core\res\assets\images\android-logo-mask.png
Android默认开机动画的前景图片,文字部分镂空,尺寸256×64

\frameworks\base\core\res\assets\images\android-logo-shine.png

Android默认开机动画的背景图片,尺寸512×64


修改Android的开关机铃声、Android开关机画面与动画(附代码流程)_第4张图片

修改Android的开关机铃声、Android开关机画面与动画(附代码流程)_第5张图片




2.3.2、另外一种是用户自定义的动画,动画打包为一个bootanimation.zip文件,存储在以下地方。

//来自Bootanimation.cpp的宏定义#define USER_BOOTANIMATION_FILE "/data/local/bootanimation.zip"#define SYSTEM_BOOTANIMATION_FILE "/system/media/bootanimation.zip"#define SYSTEM_ENCRYPTED_BOOTANIMATION_FILE "/system/media/bootanimation-encrypted.zip"


系统会先读取上述路径,查询是否存在bootanimation.zip文件,并且可以成功加载。若是都成立,系统的开机动画则是用户自定义的bootanimation.zip开机方式。否则采用系统默认的开机动画。


2.3.3、开机动画的函数实现流程。


首先,BootAnimation里面的BootAnimation类继承thread类,开始时,由系统调用BootAnimation类的成员函数onFirstRef(),在这个函数里面主要是调用了父类Thread的成员函数run,然后就会创建一个新的线程。

void BootAnimation::onFirstRef() {    status_t err = mSession->linkToComposerDeath(this);    LOGE_IF(err, "linkToComposerDeath failed (%s) ", strerror(-err));    if (err == NO_ERROR) {        run("BootAnimation", PRIORITY_DISPLAY);//开始新的线程    }}

线程开始运行时,会调用BootAnimation类的成员函数readyToRun()来作一些初始化工作,如读取给定路径的bootanimation.zip。


status_t BootAnimation::readyToRun() {    mAssets.addDefaultAssets();    DisplayInfo dinfo;    status_t status = session()->getDisplayInfo(0, &dinfo);    if (status)        return -1;    // create the native surface    sp<SurfaceControl> control = session()->createSurface(            0, dinfo.w, dinfo.h, PIXEL_FORMAT_RGB_565);    SurfaceComposerClient::openGlobalTransaction();    control->setLayer(0x40000000);    SurfaceComposerClient::closeGlobalTransaction();    sp<Surface> s = control->getSurface();    // initialize opengl and egl    const EGLint attribs[] = {            EGL_RED_SIZE,   8,            EGL_GREEN_SIZE, 8,            EGL_BLUE_SIZE,  8,            EGL_DEPTH_SIZE, 0,            EGL_NONE    };    EGLint w, h, dummy;    EGLint numConfigs;    EGLConfig config;    EGLSurface surface;    EGLContext context;    EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);    eglInitialize(display, 0, 0);    eglChooseConfig(display, attribs, &config, 1, &numConfigs);    surface = eglCreateWindowSurface(display, config, s.get(), NULL);    context = eglCreateContext(display, config, NULL, NULL);    eglQuerySurface(display, surface, EGL_WIDTH, &w);    eglQuerySurface(display, surface, EGL_HEIGHT, &h);    if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE)        return NO_INIT;    mDisplay = display;    mContext = context;    mSurface = surface;    mWidth = w;    mHeight = h;    mFlingerSurfaceControl = control;    mFlingerSurface = s;    mAndroidAnimation = true;//默认是采用系统的默认开机动画,所以mAndroidAnimation默认为true    // If the device has encryption turned on or is in process     // of being encrypted we show the encrypted boot animation.    char decrypt[PROPERTY_VALUE_MAX];    property_get("vold.decrypt", decrypt, "");    bool encryptedAnimation = atoi(decrypt) != 0 || !strcmp("trigger_restart_min_framework", decrypt);    if ((encryptedAnimation &&            (access(SYSTEM_ENCRYPTED_BOOTANIMATION_FILE, R_OK) == 0) &&            (mZip.open(SYSTEM_ENCRYPTED_BOOTANIMATION_FILE) == NO_ERROR)) ||            ((access(USER_BOOTANIMATION_FILE, R_OK) == 0) &&            (mZip.open(USER_BOOTANIMATION_FILE) == NO_ERROR)) ||            ((access(SYSTEM_BOOTANIMATION_FILE, R_OK) == 0) &&            (mZip.open(SYSTEM_BOOTANIMATION_FILE) == NO_ERROR))) {        mAndroidAnimation = false;//若成功读取到bootanimation.zip文件,标志位为false,也就是采用用户自定义的动画方案    }    return NO_ERROR;}

之后再调用BootAnimation类的成员函数threadLoop()来显示Android系统的开机动画。


bool BootAnimation::threadLoop(){    bool r;    if (mAndroidAnimation) {//由mAndroidAnimation这个标志位来决定到底播放哪一种        r = android();//播放系统默认的动画    } else {        r = movie();//播放用户自定义的动画    }    eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);    eglDestroyContext(mDisplay, mContext);    eglDestroySurface(mDisplay, mSurface);    mFlingerSurface.clear();    mFlingerSurfaceControl.clear();    eglTerminate(mDisplay);    IPCThreadState::self()->stopProcess();    return r;}bool BootAnimation::android(){    initTexture(&mAndroid[0], mAssets, "images/android-logo-mask.png");    initTexture(&mAndroid[1], mAssets, "images/android-logo-shine.png");//读取默认开机动画的两张png图片    // clear screen    glShadeModel(GL_FLAT);    glDisable(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);    glScissor(updateRect.left, mHeight - updateRect.bottom, updateRect.width(),            updateRect.height());    // Blend state    glBlendFunc(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);        EGLBoolean res = eglSwapBuffers(mDisplay, mSurface);        if (res == EGL_FALSE)            break;        // 12fps: don't animate too fast to preserve CPU        const nsecs_t sleepTime = 83333 - ns2us(systemTime() - now);        if (sleepTime > 0)            usleep(sleepTime);    } while (!exitPending());    glDeleteTextures(1, &mAndroid[0].name);    glDeleteTextures(1, &mAndroid[1].name);    return false;}bool BootAnimation::movie(){    ZipFileRO& zip(mZip);    size_t numEntries = zip.getNumEntries();    ZipEntryRO desc = zip.findEntryByName("desc.txt");    FileMap* descMap = zip.createEntryFileMap(desc);    LOGE_IF(!descMap, "descMap is null");    if (!descMap) {        return false;    }    String8 desString((char const*)descMap->getDataPtr(),            descMap->getDataLength());    char const* s = desString.string();    Animation animation;    // Parse the description file    for (;;) {        const char* endl = strstr(s, "\n");        if (!endl) break;        String8 line(s, endl - s);        const char* l = line.string();        int fps, width, height, count, pause;        char path[256];        if (sscanf(l, "%d %d %d", &width, &height, &fps) == 3) {            //LOGD("> w=%d, h=%d, fps=%d", fps, width, height);            animation.width = width;            animation.height = height;            animation.fps = fps;        }        if (sscanf(l, "p %d %d %s", &count, &pause, path) == 3) {            //LOGD("> count=%d, pause=%d, path=%s", count, pause, path);            Animation::Part part;            part.count = count;            part.pause = pause;            part.path = path;            animation.parts.add(part);        }        s = ++endl;    }    // read all the data structures    const size_t pcount = animation.parts.size();    for (size_t i=0 ; i<numEntries ; i++) {        char name[256];        ZipEntryRO entry = zip.findEntryByIndex(i);        if (zip.getEntryFileName(entry, name, 256) == 0) {            const String8 entryName(name);            const String8 path(entryName.getPathDir());            const String8 leaf(entryName.getPathLeaf());            if (leaf.size() > 0) {                for (int j=0 ; j<pcount ; j++) {                    if (path == animation.parts[j].path) {                        int method;                        // supports only stored png files                        if (zip.getEntryInfo(entry, &method, 0, 0, 0, 0, 0)) {                            if (method == ZipFileRO::kCompressStored) {                                FileMap* map = zip.createEntryFileMap(entry);                                if (map) {                                    Animation::Frame frame;                                    frame.name = leaf;                                    frame.map = map;                                    Animation::Part& part(animation.parts.editItemAt(j));                                    part.frames.add(frame);                                }                            }                        }                    }                }            }        }    }    // clear screen    glShadeModel(GL_FLAT);    glDisable(GL_DITHER);    glDisable(GL_SCISSOR_TEST);    glDisable(GL_BLEND);    glClearColor(0,0,0,1);    glClear(GL_COLOR_BUFFER_BIT);    eglSwapBuffers(mDisplay, mSurface);    glBindTexture(GL_TEXTURE_2D, 0);    glEnable(GL_TEXTURE_2D);    glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);    const int xc = (mWidth - animation.width) / 2;    const int yc = ((mHeight - animation.height) / 2);    nsecs_t lastFrame = systemTime();    nsecs_t frameDuration = s2ns(1) / animation.fps;    Region clearReg(Rect(mWidth, mHeight));    clearReg.subtractSelf(Rect(xc, yc, xc+animation.width, yc+animation.height));    for (int i=0 ; i<pcount && !exitPending() ; i++) {        const Animation::Part& part(animation.parts[i]);        const size_t fcount = part.frames.size();        glBindTexture(GL_TEXTURE_2D, 0);        for (int r=0 ; !part.count || r<part.count ; r++) {            for (int j=0 ; j<fcount && !exitPending(); j++) {                const Animation::Frame& frame(part.frames[j]);                if (r > 0) {                    glBindTexture(GL_TEXTURE_2D, frame.tid);                } else {                    if (part.count != 1) {                        glGenTextures(1, &frame.tid);                        glBindTexture(GL_TEXTURE_2D, frame.tid);                        glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);                        glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);                    }                    initTexture(                            frame.map->getDataPtr(),                            frame.map->getDataLength());                }                if (!clearReg.isEmpty()) {                    Region::const_iterator head(clearReg.begin());                    Region::const_iterator tail(clearReg.end());                    glEnable(GL_SCISSOR_TEST);                    while (head != tail) {                        const Rect& r(*head++);                        glScissor(r.left, mHeight - r.bottom,                                r.width(), r.height());                        glClear(GL_COLOR_BUFFER_BIT);                    }                    glDisable(GL_SCISSOR_TEST);                }                glDrawTexiOES(xc, yc, 0, animation.width, animation.height);                eglSwapBuffers(mDisplay, mSurface);                nsecs_t now = systemTime();                nsecs_t delay = frameDuration - (now - lastFrame);                lastFrame = now;                long wait = ns2us(frameDuration);                if (wait > 0)                    usleep(wait);            }            usleep(part.pause * ns2us(frameDuration));        }        // free the textures for this part        if (part.count != 1) {            for (int j=0 ; j<fcount ; j++) {                const Animation::Frame& frame(part.frames[j]);                glDeleteTextures(1, &frame.tid);            }        }    }    return false;}


2.3.4、制作bootanimation.zip

拿CM7的bootanimation.zip的做个例子,首先解压做个zip文件。


2.3.4.1、

可以发现里面由两个文件夹和一个desc.txt(固定文件名)文档构成的


480 480 24p 1 0 androidp 0 0 part1

第一行的三个数字分别表示开机动画在屏幕中的显示宽度、高度以及帧速(fps)(每秒钟传输的图片的数量,若是24,表示一秒钟有24张图片刷新,每一帧图片的停留时间为1/24秒)。

接下来的行定义是一样的,后面的有多少个文件夹,就接来下就写多少行来定义文件夹里面的图片就行。


第1个参数:标志符:
必须是: p


第2个参数:文件夹的图片完全播放完的循环次数:
0 : 表示本文件夹里面的图片无限循环


第3个参数:每一个循环的间隔时间:
单位是一个帧的持续时间,比如帧数是24,那么帧的持续时间就是1秒/24 。
若第3个参数为10表示————以帧数24fps播放完了android文件夹的文件,然后等待10个帧的持续时间【也就是10*(1/24)】,然后在以24fps来重复播放这个文件夹的下面的图片。以此类推。

若第3个参数为0表示————每次循环的间隔时间为0


第4个参数:文件夹名称
文件夹中的图片文件的加载刷新按文件名的名称排序。



2.3.4.2、制作


建立文件夹bootanimation,然后在里面按照规范建立desc.txt文件,把图片文件夹拖进去bootanimation文件夹里面。注意图片的文件名的顺序。

在linux下面执行以下命令即可。

zip -0 bootanimation.zip android/*png part1/*png desc.txt

zip -0表示无压缩

也可以在windows下面用rar软件打包为zip,压缩标准选择为存储就行。(不压缩)

然后就生成了bootanimation.zip

修改Android的开关机铃声、Android开关机画面与动画(附代码流程)_第6张图片


更多相关文章

  1. Android根据不同语言切换图片
  2. Android 图片处理工具类汇总
  3. android里图片下载工具类AsyncImageLoader分析
  4. android 自由缩放图片
  5. android中实现图片的上下移动
  6. android图片压缩并转为base64字符串
  7. android > 图片旋转
  8. android 滚动的缓冲图片
  9. android:设计一个能在图片上涂鸦的程序。

随机推荐

  1. Android(安卓)-- AppWidget 进阶篇
  2. android 代码混淆proguard
  3. Tinker
  4. android HorizontalScrollView的简单使用
  5. ROOT android 原理。 基于(zergRush)
  6. Android-6.0之PMS安装APK上篇
  7. Android(安卓)使用自定义Dialog打造Actio
  8. Layout_weight
  9. 深入学习百度地图Android(安卓)SDK v4.0.
  10. 内存3