android定制化开关机动画、铃音


系统通常默认支持开机动画,开机关机铃声服务倒是预先定义了,不过使用时需要在/sysytem/media/下添加相应的音频文件。长按Power键弹出关键选项,关机时也只是显示进度条,而不是我们期望的关机动画同时伴有关机铃声,当然在做二次开发的时候,这些都是可以定制的。下面将逐步分析如何实现这些定制化的需求。


一.    制作开机动画


开机画面是保存在/system/media的bootanimation.zip,下面分析系统开机画面的构成
文件名为bootanimation.zip 一定是这个不能修改,里面包含part1 part2文件夹 和desc.txt,part 文件夹里面放的是动画拆分的图片,格式为png, desc.txt里面是播放的设置。
格式是这样的


480 800 15
p 1 0 part0
p 0 0 part1
480 800是指显示的分辨率宽 高
15是一秒的帧数
p后面的数字是指播放次数 0为循环,N为播放N次
后面那位数字一般为0(空指令), 表示播放一遍后稍作停顿的时间
part0,part1 为文件夹名
一般我们只使用part0目录


图片准备好了,desc.txt里面的命令也准备好了,就可以把他们一起打包压缩成zip格式了。记住,是zip格式,而不是rar格式。另外压缩的时候注意一点,压缩的时候压缩方式要选择存储,否则开机时手机会不认的。当然不至于变砖,只是开机的时候会黑着没动画一直到进入桌面为止。


 


开机动画的替换也很简单,我们把做好的bootanimation.zip替换掉原来的/system/media/bootanimation.zip文件即可。关机动画其实和开机动画的制作一样,我们命名为shutdownanimation.zip,和bootanimation.zip放在同一目录下。


 


 


 


二. 开关机动画实现原理


Android系统在init.rc中定义了很多Servic,具体定义格式可以参考《Android Platform Developer’s Guide》中的“Android Init Language”。Init.rc中定义的Service将会被Init进程创建,其中已经定义的服务就包含了开机动画,但没有关机动画的定义


service bootsound /system/bin/mplayer /system/media/bootsound


    user media


    group audio


    oneshot


//开机铃声服务 /system/media/startupsound是铃声文件


service startupsound /system/bin/mplayer /system/media/startupsound


    user media


    group audio


    disabled


    oneshot


//关机铃声服务 /system/media/shutdownsound是关机铃声


service shutdownsound /system/bin/mplayer /system/media/shutdownsound


    user media


    group audio


    disabled


    oneshot


//定义了一个bootanim的服务,对应执行/system/bin/bootanimation


//disabled 表示init进程创建只是创建它,但不立刻执行


//oneshot 表示该服务只执行一次


service bootanim /system/bin/bootanimation


    user graphics


    group graphics


    disabled


oneshot


 


 


当android系统boot时,开始加载动画和开机铃声,其代码位于


//源文件SurfaceFlinger.cpp


status_t SurfaceFlinger::readyToRun() {


    


    // start boot animation service


    property_set("ctl.start", "bootanim");//注


    {


        char value[PROPERTY_VALUE_MAX];


        property_get("persist.sys.profile.silent", value, "0");


        if (atoi(value)== 0){


            LOGI("start:persist.sys.profile.silent is soundable");


            // start startupsound service


            property_set("ctl.start","startupsound");//注


         } else {


            LOGI("start:persist.sys.profile.silent is silent");


         }


    }


    return NO_ERROR;


}


 


当Android完成boot后,关闭动画和开机铃声,代码位于


//源文件SurfaceFlinger.cpp


void SurfaceFlinger::bootFinished() {


   const nsecs_t now = systemTime();


   const nsecs_t duration = now - mBootTime;


   LOGI("Boot is finished (%ld ms)", long(ns2ms(duration)) );


   mBootFinished = true;


   //stop bootanim service


   property_set("ctl.stop", "bootanim");


   char value[PROPERTY_VALUE_MAX];


   property_get("persist.sys.profile.silent", value, "0");


   if (atoi(value)== 0){


       LOGI("stop:persist.sys.profile.silent is soundable");


       //stop startupsound service


       property_set("ctl.stop","startupsound");


   } else {


       LOGI("stop:persist.sys.profile.silent is silent");


   }


}


 


如何理解ctr.start和ctr.stop系统属性?


每一项服务必须在/init.rc中定义.Android系统启动时,init守护进程将解析init.rc和启动属性服务,属性“ ctl.start ”和“ ctl.stop ”是用来启动和停止服务的。一旦收到设置“ ctrl.start ”属性的请求,属性服务将使用该属性值作为服务名找到该服务,启动该服务。这项服务的启动结果将会放入“ init.svc.<服务名>“属性中 。客户端应用程序可以轮询那个属性值,以确定结果。想更深入了解Android property系统可以参考博文《(翻译)Android属性系统》。


 


property_set("ctl.start",ServiceName);就是启动ServiceName服务(在init.rc中定义);


property_set("ctl.stop",ServiceName)相对的是关闭ServiceName服务。


 


 


 


A启动动画服务


由于开机动画和关机动画除了播放的动画文件不同,其他的完全一致,这里重复利用/system/bin/bootanimation代码, 仿照开机动画服务,我们新定义关机动画


service shutdownanim /system/bin/bootanimation -shutdown


    user graphics


    group graphics


    disabled


    oneshot


唯一要注意的是关机动画使用的/system/bin/bootanimation带了-shutdown参数,这个参数用来区分加载的动画文件为开机还是关机动画。当bootanimation服务启动时,进入/frameworks/base/cmds/bootanimation/bootanimation_main.cpp主函数main,


int main(int argc, char** argv)


{


#if defined(HAVE_PTHREADS)


    setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_DISPLAY);


#endif


 


    char value[PROPERTY_VALUE_MAX];


    property_get("debug.sf.nobootanimation", value, "0");


    int noBootAnimation = atoi(value);


    LOGI_IF(noBootAnimation,  "boot animation disabled");


    if (!noBootAnimation) {


 


        sp<ProcessState> proc(ProcessState::self());


        ProcessState::self()->startThreadPool();


 


        // create the animation object


        sp<BootAnimation> boot = new BootAnimation();


        //根据是否有参数,来设置动画对象的isShutdown属性


        if (argc > 0) {


            if (strcmp(argv[0], "-shutdown")==0) {


                boot->isShutdown(true);


            }


        }


 


        IPCThreadState::self()->joinThreadPool();


 


    }


    return 0;


}


new BootAnimation();时,如果有参数-shutdown, 则boot->isShutdown(true);方法isShutdown和isShutdown使我们新加的,所以先要在frameworks/base/cmds/bootanimation/bootanimation/BootAnimation.h头文件中申明为public,如下:


class BootAnimation : public Thread, public IBinder::DeathRecipient


{


public:


                BootAnimation();


    virtual     ~BootAnimation();


 


    sp<SurfaceComposerClient> session() const;


    bool        mShutdown;


void        isShutdown(bool shutdown);


…………………………………………….


}


 


之后修改BootAnimation.cpp


//源码位于frameworks/base/cmds/bootanimation/bootanimation/BootAnimation.cpp


首先在构造函数中初始化mShutdown = false;表示默认是开机标志


BootAnimation::BootAnimation() : Thread(false)


{


    mSession = new SurfaceComposerClient();


    mShutdown = false;


}


实现isShutdown(bool shutdown);方法


void BootAnimation::isShutdown(bool shutdown)


{


    mShutdown = shutdown;


}


修改status_t BootAnimation::readyToRun() 方法来根据mShutdown值加载动画文件,如


status_t BootAnimation::readyToRun() {


……………………………………


mAndroidAnimation = false;


if (!mShutdown) {


    status_t err = mZip.open("/data/local/bootanimation.zip");


    if (err != NO_ERROR) {


        err = mZip.open("/system/media/bootanimation.zip");


        if (err != NO_ERROR) {


            mAndroidAnimation = true;


        }


    }


} else {


    status_t err = mZip.open("/data/local/shutdownanimation.zip");


    if (err != NO_ERROR) {


        err = mZip.open("/system/media/shutdownanimation.zip");


        if (err != NO_ERROR) {


            mAndroidAnimation = true;


        }


    }


    mShutdown = false;


}


return NO_ERROR;


}


以上是动画定制化C代码部分的全部修改。


 


 


 


B启动开机铃声服务


startupsound开机铃声服务,shutdownsound关机铃声服务


init.rc定义,service startupsound /system/bin/mplayer /system/media/startupsound


相当于用/system/bin/mplayer对象播放媒体文件/system/media/startupsound,


init.rc定义,service shutdownsound /system/bin/mplayer /system/media/shutdownsound


相当于用/system/bin/mplayer对象播放媒体文件/system/media/ shutdownsound.


 


 


到这里,开机动画和开机铃声是正常的,我们还需要修改的是关机时候的执行流程,因为默认的操作时关机确认后显示进度条。


 


 


 


C定制Android关机过程


在Android系统中,长按Power键默认会弹出对话框让你选择“飞行模式”,“静音”,“关机”等功能。


     我的目标是长按Power键,将会关机,弹出“设备将要关机”选择对话框。如果可以选择“是”关机,和“否”返回系统。


 


弹出对话框的代码位于:


frameworks\policies\base\phone\com\android\internal\policy\impl\PhoneWindowManager.java


长按Power键显示对话框的代码如下:


Runnable mPowerLongPress = new Runnable() {


    public void run() {


        mShouldTurnOffOnKeyUp = false;


        performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);


        sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);


        showGlobalActionsDialog();


    }


};


调用showGlobalActionsDialog方法将会显示上面提到的显示“飞行模式”,“静音”,“关机”,选项的对话框。


      关机的代码位于:


frameworks\policies\base\phone\com\android\internal\policy\impl\GlobalActions.java


文件的createDialog方法中,有如下代码:


mItems = Lists.newArrayList(


    // silent mode


    mSilentModeToggle,


    // next: airplane mode


    mAirplaneModeOn,


    // last: power off


    new SinglePressAction(


           com.android.internal.R.drawable.ic_lock_power_off,


           R.string.global_action_power_off) {


                public void onPress() {


                    // shutdown by making sure radio and power are handled accordingly.


                    ShutdownThread.shutdown(mContext, true);


                }


 


                public boolean showDuringKeyguard() {


                    return true;


                }


 


                public boolean showBeforeProvisioning() {


                    return true


                }


            });


从代码中我们可以看出,如果选择上述对话框的“关机”选项之后,将会调用ShutdownThread的shutdown方法来关机。shutdown方法的第二个参数标识是否弹出询问对话框。


 


ShutdownThread代码位于


frameworks/base/core/java/com/android/internal/app/ShutdownThread.java


shutdown方法中有如下代码


public static void shutdown(final Context context, boolean confirm) {


    // ensure that only one thread is trying to power down.


    // any additional calls are just returned


    synchronized (sIsStartedGuard){


        if (sIsStarted) {


            Log.d(TAG, "Request to shutdown already running, returning.");


            return;


        }


    }


 


    Log.d(TAG, "Notifying thread to start radio shutdown");


 


    if (confirm) {


        final AlertDialog dialog = new AlertDialog.Builder(context)


               .setIcon(android.R.drawable.ic_dialog_alert)


               .setTitle(com.android.internal.R.string.power_off)


               .setMessage(com.android.internal.R.string.shutdown_confirm)


               .setPositiveButton(com.android.internal.R.string.yes,


new DialogInterface.OnClickListener() {


                           public void onClick(DialogInterface dialog, int which) {


                               beginShutdownSequence(context);


                           }


                    })


                .setNegativeButton(com.android.internal.R.string.no, null)


                .create();


 


dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);


        if (!context.getResources().getBoolean(


             com.android.internal.R.bool.config_sf_slowBlur)) {


dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND);


        }


        dialog.show();


    } else {


        beginShutdownSequence(context);


    }


}


 


确认关机后开始执行beginShutdownSequence(context),这里就是我们定制关机过程的关键。


 


修改beginShutdownSequence(context)方法,在方法开头打印Log之后增加如下代码:


//我们判断如果有关机动画文件,即显示关机动画,否则显示默认的进度条。


boolean showShutdownAnim = new File("/system/media/shutdownanimation.zip").exists();


    if (showShutdownAnim) {


        Log.d(TAG, "shutdownanim");


        //设置前面说的android系统属性ctr.start,即通知属性服务启动关机动画服务


        android.os.SystemProperties.set("ctl.start", "shutdownanim");


    } else {


        // throw up an indeterminate system dialog to indicate radio is


        // shutting down.


        ProgressDialog pd = new ProgressDialog(context);


        pd.setTitle(context.getText(com.android.internal.R.string.power_off));


        pd.setMessage(context.getText(com.android.internal.R.string.shutdown_progress));


        pd.setIndeterminate(true);


        pd.setCancelable(false);


        pd.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);


        if (!context.getResources().getBoolean(


            com.android.internal.R.bool.config_sf_slowBlur)) {


            pd.getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND);


        }


 


        pd.show();


    }


 


    boolean playShutdownSound = new File("/system/media/shutdownsound").exists();


    android.os.SystemProperties.getBoolean("ro.config.enable_shutdownshound", false);


    if (playShutdownSound) {


        // play shutdown sound


        Log.d(TAG, "shutdownsound");


        android.os.SystemProperties.set("ctl.start", "shutdownsound");


}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值