前言
一般情況下我們Android裝置的開機動畫是以圖片動畫的形式顯示出來的,如果我們的動畫裡面有文字,而恰好我們的裝置必須支援多語言。腫麼辦,原生系統的開機動畫只有一個,怎麼樣才能做到支援多語言多動畫呢?
專案思路
要想支援多語言多動畫,我們肯定得知道當前設定的是什麼語言?然後,再根據語言去載入對應的開機動畫(準備對應語言的開機動畫素材包,即bootanimation。zip)。這裡沒有介紹Android的開機動畫原理,如果不懂的朋友,可以去網上搜索相關的知識,這裡就不補充了。以後有可能會寫一篇關於開機動畫流程的文章。好,大概的思路有了,就是先獲取當前系統語言,然後,載入對應的開機動畫。
專案實戰
這裡先大概說下,開機動畫的載入序列圖,如下圖:
原始碼路徑:
frameworks/base/cmds/bootanimation/bootanimation_main。cpp
frameworks/base/cmds/bootanimation/BootAnimation。cpp
frameworks/base/cmds/bootanimation/BootAnimation。h
system/core/libutils/Threads。cpp
system/core/include/utils/Thread。h
system/core/include/utils/RefBase。h
system/core/libutils/RefBase。cpp
system/core/include/utils/StrongPointer。h
從上面的序列圖中,我們可以知道,開機動畫載入繪製主要集中在readyToRun和threadLoop函式中處理。下面來看下這兩個函式分別是怎麼處理的。BootAnimation。cpp
status_t BootAnimation::readyToRun() {
mAssets。addDefaultAssets();
sp
ISurfaceComposer::eDisplayIdMain));
DisplayInfo dinfo;
status_t status = SurfaceComposerClient::getDisplayInfo(dtoken, &dinfo); if (status) return -1; // create the native surface
sp
dinfo。w, dinfo。h, PIXEL_FORMAT_RGB_565);
SurfaceComposerClient::openGlobalTransaction();
control->setLayer(0x40000000);
SurfaceComposerClient::closeGlobalTransaction();
sp
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;
mContext = context;
mSurface = surface;
mWidth = w;
mHeight = h;
mFlingerSurfaceControl = control;
mFlingerSurface = s;
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); //判斷bootanimation。zip開機動畫包是否存在,存在就繪製bootanimation。zip中的動畫,否則繪製android原生動畫
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;
}
return NO_ERROR;
}
系統在readyToRun中主要是做一些繪製初始化工作和bootanimation。zip是否存在的事情,如果bootanimation。zip不存在就是使用系統預設的動畫。接下來看下threadLoop()函式
bool BootAnimation::threadLoop()
{
bool r;
if (mAndroidAnimation) { //繪製Andriod原生動畫
r = android();
} else { //繪製bootanimation。zip中的自定義動畫
r = movie();
}
// No need to force exit anymore
property_set(EXIT_PROP_NAME, “0”);
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;
}
至於android()和movie()裡的具體內容這裡就不詳敘了。它們的目的都是繪製開機動畫。不過,一個是framwork 中assets目錄下png圖片,一個是bootanimation。zip中的圖片。現在回到我們的問題點,根據不同語言顯示對應語言的開機動畫。從上面的開機動畫載入流程中我們已經知道,我們只需要在readyToRun中獲取當前系統語言,然後讓其載入對應的bootanimation。zip即可。注:這裡我們需要給不同語言的開機動畫包設定對應的語言路徑。例如:
/system/media/bootanimation。zip
/system/media/zh/bootanimation。zip
/system/media/en/bootanimation。zip
好,現在開始我們的修改步驟吧!
第一步:修改開機動畫載入路徑
BootAnimation。cpp
#define SYSTEM_PATH “/system/media”
#define BOOTANIMAION_FILE “bootanimation。zip”
status_t BootAnimation::readyToRun() {。。。 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, “”); //————————-add by steven zhang start——————————- //zh en //獲取當前系統語言 char language[PROPERTY_VALUE_MAX]; property_get(“persist。sys。language”, language, “zh”); char systemBootAnimaPath[PROPERTY_VALUE_MAX]; //設定對應的開機動畫路徑,例如:/system/media/zh/bootanimation。zip sprintf(systemBootAnimaPath, “%s/%s/%s”, SYSTEM_PATH, language, BOOTANIMAION_FILE); ALOGD(“systemBootAnimaPath::%s——-”,systemBootAnimaPath); //————————-add by steven zhang end——————————- bool encryptedAnimation = atoi(decrypt) != 0 || !strcmp(“trigger_restart_min_framework”, decrypt); //判斷bootanimation。zip開機動畫包是否存在,存在就繪製bootanimation。zip中的動畫,否則繪製android原生動畫 if ((encryptedAnimation && (access(SYSTEM_ENCRYPTED_BOOTANIMATION_FILE, R_OK) == 0) && (mZip。open(SYSTEM_ENCRYPTED_BOOTANIMATION_FILE) == NO_ERROR)) || //————————-add by steven zhang start——————————- ((access(systemBootAnimaPath, R_OK) == 0) && (mZip。open(systemBootAnimaPath) == NO_ERROR)) || //————————-add by steven zhang end——————————- ((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; } return NO_ERROR;透過上面這一步我們已經將載入開機動畫的路徑修改成對應語言的開機動畫路徑了。接下來我們要做的就是在對應的路徑下放入開機動畫包。第二步:對應的語言路徑下放入開機動畫包在device目錄下找到對應專案的mk檔案,在其中加入如下程式碼:device/xxx/yyy。mkPRODUCT_COPY_FILES += \ device/xxx/yyy/bootMedia/bootanimation。zip:system/media/bootanimation。zip \ device/xxx/yyy/bootMedia/zh/bootanimation。zip:system/media/zh/bootanimation。zip \ device/xxx/yyy/bootMedia/en/bootanimation。zip:system/media/en/bootanimation。zip \這一步的操作就是將原始碼中的不同語言的開機動畫包複製到系統中對應的位置。第三步:編譯系統驗證效果這裡就不多說怎麼編譯系統和驗證了。感興趣的同學實現了上面兩部後,基本上是可以實現開機動畫跟著語言變化而變化的需求了。總結本來只是想寫一下開機動畫怎麼支援多語言的問題,寫著寫著發現後面部分同學可能不知道開機動畫的載入流程。所以後面準備好好講下Android系統開機動畫流程。