• Android 7 修改启动动画和开机声音


    背景

    在修改开机音量的时候,发现找不到对应的声音功能调用。

    因此了解了一下安卓的开机声音是如何实现的。

    安卓4~安卓7 都可以这么做。

    参考:

    前言

    关于安卓的开机效果(动画、logo、声音),有下面几个阶段:

    • 老的方案1:Linux 系统启动,出现Linux小企鹅画面(reboot)(Android 1.5及以上版本已经取消加载图片);
    • 沿用至今的方案2:Lndroid平台图形系统启动,出现含闪动的ANDROID字样的动画图片(start)并加载Android系统。

    我们这里说的是沿用至今的方案2。

    源码分析

    android开机动画叫源码位于frameworks/base/cmds/bootanimation/BootAnimation.cpp中,会将/data/local/bootanimation.zip/system/media/bootanimation.zip里面的图片(支持png、jpeg、bmp)以动画的形式播放出来:

    在源码树中搜索bootanimation.zip即可找到可供修改的开机动画。

    static const char OEM_BOOTANIMATION_FILE[] = "/oem/media/bootanimation.zip";
    static const char SYSTEM_BOOTANIMATION_FILE[] = "/system/media/bootanimation.zip";
    static const char SYSTEM_ENCRYPTED_BOOTANIMATION_FILE[] = "/system/media/bootanimation-encrypted.zip";
    
    status_t BootAnimation::readyToRun() {
        mAssets.addDefaultAssets();
    
        sp<IBinder> dtoken(SurfaceComposerClient::getBuiltInDisplay(
                ISurfaceComposer::eDisplayIdMain));
        DisplayInfo dinfo;
        status_t status = SurfaceComposerClient::getDisplayInfo(dtoken, &dinfo);
        if (status)
            return -1;
    
        // create the native surface andrew.hu modify
        sp<SurfaceControl> control = session()->createSurface(String8("BootAnimation"),
                dinfo.orientation == 1 ? dinfo.h : dinfo.w,
                dinfo.orientation == 1 ? 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;
        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;
    
        // 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(getAnimationFileName(IMG_ENC), R_OK) == 0)) {
            mZipFileName = getAnimationFileName(IMG_ENC);
        }
        else if (access(getAnimationFileName(IMG_OEM), R_OK) == 0) {
            mZipFileName = getAnimationFileName(IMG_OEM);
        }
        else if (access(getAnimationFileName(IMG_SYS), R_OK) == 0) {
            mZipFileName = getAnimationFileName(IMG_SYS);
        }
        return NO_ERROR;
    }
    

    循环:

    bool BootAnimation::threadLoop()
    {
        bool r;
        // We have no bootanimation file, so we use the stock android logo
        // animation.
        if (mZipFileName.isEmpty()) {
            r = android(); //   执行android字体闪动的图片 会加载"images/android-logo-mask.png"和"images/android-logo-shine.png"
        } else {
            r = movie();   //   执行bootanimation.zip中提供的动画图片 
        }
    
        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;
    }
    

    所以如果你想修改动画,那么把你做好的动画拷贝到编译好对应的目录下即可,然后编译刷入整合进system镜像包就可以看到效果了

    如果你想修改android闪动的那两张图片的话,最简单的方法是直接替换图片,如果你懂openGL的话也可以自己做酷炫的动画

    另外如果需要修改开机logo动画,可以这么做(参考BootAnimation.cpp中的android函数):

    1、将图片文件xx.png放置到 frameworks/base/core/res/assets/images中。

    2、再在函数中完成对应的调用:

    • 声明对应的类型:Texture mTexture
    • 加载initTexture(&mTexture, mAssets, "images/xx.png");
    • 使用openGL来绘制界面(略)

    添加开机声音

    既然我们已经知道了关于开机效果显示的大致流程。

    那么添加开机声音也很简单,我们可以使用MediaPlayer这个类来完成我们的需求。

    声明与实现

    首先在BootAnimation.h添加方法的声明和头文件的引用

    #include <media/AudioSystem.h>
    #include <media/mediaplayer.h>
    

    添加: void bootMusic();的声明以及对应的实现

    // frameworks/base/cmds/bootanimation/BootAnimation.h
    class BootAnimation : public Thread, public IBinder::DeathRecipient
    {
        //...
    private:
        void bootMusic();
    }
    
    
    // frameworks/base/cmds/bootanimation/BootAnimation.cpp
    void BootAnimation::bootMusic()
    {
        int index;
        const char *fileName = "/system/media/boot.wav";
        MediaPlayer* mp = new MediaPlayer();
        audio_devices_t device = AudioSystem::getDevicesForStream(AUDIO_STREAM_ENFORCED_AUDIBLE);
        if (mp->setDataSource(NULL, fileName, NULL) == NO_ERROR)
        {
            mp->setAudioStreamType(AUDIO_STREAM_ENFORCED_AUDIBLE/*AudioSystem: :ENFORCED_AUDIBLE*/);
            mp->prepare();
        }
        LOGE ("bootMusic
    ");
        AudioSystem::initStreamVolume(AUDIO_STREAM_ENFORCED_AUDIBLE, 0,7);
        AudioSystem::setStreamVolumeIndex(AUDIO_STREAM_ENFORCED_AUDIBLE, 7, device);
        AudioSystem::getStreamVolumeIndex(AUDIO_STREAM_ENFORCED_AUDIBLE/*AudioSystem::ENFORCED_AUDIBLE*/, &index, device);
        LOGE ("index %d",index);
        if (index != 0)
        {
            LOGD("playing %s", fileName);
            mp->setVolume(0.4f, 0.4f);
            mp->seekTo(0);
            mp->start();
        }
    }
    

    只要fileName对应的声音文件存在而且有权限访问到,那么无所谓放在哪里。

    此后,在合适的地方(android ()或者movie ())调用即可,例如:

    bool BootAnimation::movie()
    {
        Animation* animation = loadAnimation(mZipFileName);
        // ...
        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);
    	// ...
        
        bootMusic(); // 播放声音 (只要在播放动画之前播放即可)
        
        playAnimation(*animation); // 播放动画
    
        // ...
    
        return false;
    }
    

    Android.mk

    光有头文件还不够,播放声音还需要引入对应的库:

    # frameworks/base/cmds/bootanimation/Android.mk
    
    # ...
    
    LOCAL_SHARED_LIBRARIES := 
        libcutils 
        liblog 
        libandroidfw 
        libutils 
        libbinder 
        libui 
        libskia 
        libEGL 
        libGLESv1_CM 
        libgui 
        libOpenSLES 
        libtinyalsa 
        libregionalization 
        libmedia # 注意,libmedia是新添加的;
        
    # ...
    

    大功告成,这样就成功的添加了开机音乐。

    修改铃声

    也许有人会问,那android系统自带的那些音乐和铃声在什么地方呢?

    系统默认了很多的声音,如果有需要,可以修改frameworks/base/data/sounds下面文档及文档夹中的声音文档。

    至于编译完成后放到什么分区那是由AllAudio.mk决定的。

    AllAudio.mk的作用:是将这些音乐文档全部打包到系统system/media/audio下面各个模块的文档,然后在系统开机的时候,扫描这些文档,将其加入到数据库中,之后在设置中更换声音时,则直接从数据库中查询这些音乐文档,然后供用户选择。

    如果需要添加某个铃声,可以这么做:

    1、在AllAudio.mk添加一列类似这样的内容:$(LOCAL_PATH)/aaa.ogg:system/media/audio/bbb/xxx.ogg

    2、再将aaa.ogg拷贝到frameworks/base/data/sounds

    修改也是类似的原理。

    当然,也可以通过修改mk文件中指定的音乐文档名来实现静音等目的。

    例如,ro.config.notification_sound(通知默认的音乐文档文档名)在build/target/product/full_base.mk 中定义,如果我们不想有声音那么我们可以将默认值改为不存在的文档,则不会播放通知声音了。当然我们也可以在客户定义的mk中使用PRODUCT_PROPERTY_OVERRIDES 去复写此属性,将其指定为不存在文档或者为空,这样就不会有通知声音响了。

    修改开机动画

    这里介绍bootanimation.zip如何制作。

    开机动画包内容

    先看看bootanimation.zip的内容:解压.zip文件后,会有n个存放图片的文件夹(partn)+1个desc.txt文件。

    开机动画压缩包不能包含bootanimation文件夹,必现是如下格式

    ├── desc.txt
    ├── part0
    │   ├── 00013.png
    │   ├── 00014.png
    │   ├── 00052.png
    └── part1
        ├── 00013.png
        ├── 00015.png
        ├── 00019.png
        └── 00069.png
    

    上图中的文件夹名字可随便命名(对应desc.txt即可),里面存放的就是开机要显示的图片。

    desc.txt解析

    打开以后可以看到是类似这样的内容。

    240 320 1
    p 2 0 part0
    p 0 0 part1
    
    

    第一行代表帧率以及动画大小:

    240 320 1
    每秒1帧

    此后的每一行代表每一段动画具体的效果:

    p 2 0 part0
    代表一段动画 代表文件夹播放的次数,0代表永远循环 表示这部分播完后下部分开始的间隔 代表从哪个文件夹中寻找动画

    一般来说,将最后的那段动画设置成循环播放,就可以在进入系统界面之前一直有画面,不会出现黑屏的情况(所有动画都做完了,但是还没进入到系统界面就会出现黑屏)。

    最后一行是空行,代表文件结束;很多人在改动时候会把这一行删掉,如果制作以后失败了,那么可以将这一行加上去试试。

    图片替换

    图片需要统一格式为png,且各图片的大小需要相同。

    图片的命名可以随意,但是最后的数字要有顺序。

    zip制作

    开机动画压缩格式必须为存储方式。

    在Windows中可以在压缩时,指定压缩级别为不压缩/存档。由于Windows下压缩软件良莠不齐,因此建议在Linux中 制作。

    Linux下可以使用下列命令:

    cd bootanimation
    zip -0 -r ../bootanimation.zip ./*
    
    如果说我的文章对你有用,只不过是我站在巨人的肩膀上再继续努力罢了。
    若在页首无特别声明,本篇文章由 Schips 经过整理后发布。
    博客地址:https://www.cnblogs.com/schips/
  • 相关阅读:
    noi 2011 noi嘉年华 动态规划
    最小乘积生成树
    noi 2009 二叉查找树 动态规划
    noi 2010 超级钢琴 划分树
    noi 2011 阿狸的打字机 AC自动机
    noi 2009 变换序列 贪心
    poj 3659 Cell Phone Network 动态规划
    noi 2010 航空管制 贪心
    IDEA14下配置SVN
    在SpringMVC框架下建立Web项目时web.xml到底该写些什么呢?
  • 原文地址:https://www.cnblogs.com/schips/p/change_bootanimation_and_add_boot_music_support_in_android.html
Copyright © 2020-2023  润新知