一、修改Android的開關機鈴聲java
待續……linux
二、修改Android開關機畫面android
開機畫面包括三個過程windows
2.一、bootloader的開機畫面session
待續……app
2.二、Android系統init時的開機畫面函數
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
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
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
2.2.二、修改方法:
2.2.2.一、找到一張符合機器分辨率的bmp圖像,把bmp圖片轉換成爲raw圖像
要注意分辨率問題,如果不符合機器分辨率,可能顯示拉伸或者花屏之類等等各類狀況。
使用到的工具imagemagick,若沒有,用apt安裝便可。
- 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目錄下執行以下命令
- ./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
修改或者添加爲
- PRODUCT_COPY_FILES += \
- 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
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
2.3.二、另一種是用戶自定義的動畫,動畫打包爲一個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.三、開機動畫的函數實現流程。
首先,BootAnimation裏面的BootAnimation類繼承thread類,開始時,由系統調用BootAnimation類的成員函數onFirstRef(),在這個函數裏面主要是調用了父類Thread的成員函數run,而後就會建立一個新的線程。
線程開始運行時,會調用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(固定文件名)文檔構成的
- 480 480 24
- p 1 0 android
- 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下面執行如下命令便可。
- zip -0 bootanimation.zip android/*png part1/*png desc.txt
zip -0表示無壓縮
也能夠在windows下面用rar軟件打包爲zip,壓縮標準選擇爲存儲就行。(不壓縮)
而後就生成了bootanimation.zip
![](http://static.javashuo.com/static/loading.gif)