(轉)修改Android的開關機鈴聲、Android開關機畫面與動畫(附代碼流程)

一、修改Android的開關機鈴聲java


待續……linux


二、修改Android開關機畫面android

開機畫面包括三個過程windows

2.一、bootloader的開機畫面session

待續……app

2.二、Android系統init時的開機畫面函數





2.2.一、Android系統init時,裝載initlogo.rle的簡單流程。工具

Androidinit時,會讀取 /initlogo.rle文件,若是讀取成功,就會在/dev/graphics/fb0顯示initlogo.rle;若是讀取失敗,打開/dev/tty0,輸出文本「A N D R I O D」字樣。oop

相關代碼:測試

/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


  1. 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.一、找到一張符合機器分辨率的bmp圖像,把bmp圖片轉換成爲raw圖像

要注意分辨率問題,如果不符合機器分辨率,可能顯示拉伸或者花屏之類等等各類狀況。

使用到的工具imagemagick,若沒有,用apt安裝便可。


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

2.2.2.二、把raw圖像轉換爲rle圖像便可。


      使用的工具rgb2565,編譯Android系統源代碼成功時,最紅再編譯SDK(執行make PRODUCT-sdk-sdk),編譯SDK成功以後,在\out\host\linux-x86\bin生成rgb2565。而後在rgb2565目錄下執行以下命令


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

2.2.2.三、替換文件

        如果想在虛擬機上面測試,當系統編譯完成以後,把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

修改或者添加爲


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

事實上,這就是一個copy的過程,和以前的添加第三方apk沒啥區別。

2.三、Android系統最後的開機動畫(相似windows的進度條)

相關代碼:

frameworks\base\cmds\bootanimation\BootAnimation.cpp

frameworks\base\cmds\bootanimation\BootAnimation.h

2.3.一、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

2.3.二、另一種是用戶自定義的動畫,動畫打包爲一個bootanimation.zip文件,存儲在如下地方。

[cpp]  view plain copy
  1. //來自Bootanimation.cpp的宏定義  
  2. #define USER_BOOTANIMATION_FILE "/data/local/bootanimation.zip"  
  3. #define SYSTEM_BOOTANIMATION_FILE "/system/media/bootanimation.zip"  
  4. #define SYSTEM_ENCRYPTED_BOOTANIMATION_FILE "/system/media/bootanimation-encrypted.zip"  

系統會先讀取上述路徑,查詢是否存在bootanimation.zip文件,而且能夠成功加載。如果都成立,系統的開機動畫則是用戶自定義的bootanimation.zip開機方式。不然採用系統默認的開機動畫。

2.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.四、製做bootanimation.zip

拿CM7的bootanimation.zip的作個例子,首先解壓作個zip文件。

2.3.4.一、

能夠發現裏面由兩個文件夾和一個desc.txt(固定文件名)文檔構成的


  1. 480 480 24  
  2. p 1 0 android  
  3. p 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.二、製做


創建文件夾bootanimation,而後在裏面按照規範創建desc.txt文件,把圖片文件夾拖進去bootanimation文件夾裏面。注意圖片的文件名的順序。

在linux下面執行如下命令便可。


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

zip -0表示無壓縮

也能夠在windows下面用rar軟件打包爲zip,壓縮標準選擇爲存儲就行。(不壓縮)

而後就生成了bootanimation.zip

相關文章
相關標籤/搜索