Loading cmds/bootanimation/Android.mk +2 −1 Original line number Diff line number Diff line Loading @@ -17,7 +17,8 @@ LOCAL_SHARED_LIBRARIES := \ libskia \ libEGL \ libGLESv1_CM \ libgui libgui \ libmedia LOCAL_C_INCLUDES := \ $(call include-path-for, corecg graphics) Loading cmds/bootanimation/BootAnimation.cpp +196 −7 Original line number Diff line number Diff line /* * Copyright (C) 2007 The Android Open Source Project * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. Loading @@ -22,6 +23,8 @@ #include <fcntl.h> #include <utils/misc.h> #include <signal.h> #include <pthread.h> #include <sys/select.h> #include <cutils/properties.h> Loading Loading @@ -50,21 +53,66 @@ #include <GLES/glext.h> #include <EGL/eglext.h> #include <media/AudioSystem.h> #include <media/mediaplayer.h> #include "BootAnimation.h" #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" #define USER_SHUTDOWN_ANIMATION_FILE "/data/local/shutdownanimation.zip" #define SYSTEM_SHUTDOWN_ANIMATION_FILE "/system/media/shutdownanimation.zip" #define SYSTEM_ENCRYPTED_SHUTDOWN_ANIMATION_FILE "/system/media/shutdownanimation-encrypted.zip" #define USER_BOOT_MUSIC_FILE "/data/local/boot.wav" #define SYSTEM_BOOT_MUSIC_FILE "/system/media/boot.wav" #define USER_SHUTDOWN_MUSIC_FILE "/data/local/shutdown.wav" #define SYSTEM_SHUTDOWN_MUSIC_FILE "/system/media/shutdown.wav" #define EXIT_PROP_NAME "service.bootanim.exit" extern "C" int clock_nanosleep(clockid_t clock_id, int flags, const struct timespec *request, struct timespec *remain); namespace android { // --------------------------------------------------------------------------- static pthread_mutex_t mp_lock; static pthread_cond_t mp_cond; static bool isMPlayerPrepared = false; static bool isMPlayerCompleted = false; class MPlayerListener : public MediaPlayerListener { void notify(int msg, int ext1, int ext2, const Parcel *obj) { switch (msg) { case MEDIA_NOP: // interface test message break; case MEDIA_PREPARED: pthread_mutex_lock(&mp_lock); isMPlayerPrepared = true; pthread_cond_signal(&mp_cond); pthread_mutex_unlock(&mp_lock); break; case MEDIA_PLAYBACK_COMPLETE: pthread_mutex_lock(&mp_lock); isMPlayerCompleted = true; pthread_cond_signal(&mp_cond); pthread_mutex_unlock(&mp_lock); break; default: break; } } }; BootAnimation::BootAnimation() : Thread(false) { mSession = new SurfaceComposerClient(); Loading Loading @@ -287,17 +335,19 @@ status_t BootAnimation::readyToRun() { char decrypt[PROPERTY_VALUE_MAX]; property_get("vold.decrypt", decrypt, ""); // Use customized resources for boot and showdown animation // instead of system predefined boot animation files. 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(getAnimationFileName(IMG_ENC), R_OK) == 0) && (mZip.open(getAnimationFileName(IMG_ENC)) == NO_ERROR)) || ((access(USER_BOOTANIMATION_FILE, R_OK) == 0) && (mZip.open(USER_BOOTANIMATION_FILE) == NO_ERROR)) || ((access(getAnimationFileName(IMG_DATA), R_OK) == 0) && (mZip.open(getAnimationFileName(IMG_DATA)) == NO_ERROR)) || ((access(SYSTEM_BOOTANIMATION_FILE, R_OK) == 0) && (mZip.open(SYSTEM_BOOTANIMATION_FILE) == NO_ERROR))) { ((access(getAnimationFileName(IMG_SYS), R_OK) == 0) && (mZip.open(getAnimationFileName(IMG_SYS)) == NO_ERROR))) { mAndroidAnimation = false; } Loading Loading @@ -404,6 +454,7 @@ void BootAnimation::checkExit() { bool BootAnimation::movie() { char value[PROPERTY_VALUE_MAX]; ZipFileRO& zip(mZip); size_t numEntries = zip.getNumEntries(); Loading Loading @@ -506,6 +557,14 @@ bool BootAnimation::movie() Region clearReg(Rect(mWidth, mHeight)); clearReg.subtractSelf(Rect(xc, yc, xc+animation.width, yc+animation.height)); pthread_mutex_init(&mp_lock, NULL); pthread_cond_init(&mp_cond, NULL); property_get("persist.sys.silent", value, "null"); if (strncmp(value, "1", 1) != 0) { playBackgroundMusic(); } for (int i=0 ; i<pcount ; i++) { const Animation::Part& part(animation.parts[i]); const size_t fcount = part.frames.size(); Loading Loading @@ -583,9 +642,139 @@ bool BootAnimation::movie() } } ALOGD("waiting for media player to complete."); struct timespec timeout; clock_gettime(CLOCK_REALTIME, &timeout); timeout.tv_sec += 5; //timeout after 5s. pthread_mutex_lock(&mp_lock); while (!isMPlayerCompleted) { int err = pthread_cond_timedwait(&mp_cond, &mp_lock, &timeout); if (err == ETIMEDOUT) { break; } } pthread_mutex_unlock(&mp_lock); ALOGD("media player is completed."); pthread_cond_destroy(&mp_cond); pthread_mutex_destroy(&mp_lock); return false; } char *BootAnimation::getAnimationFileName(ImageID image) { char *fileName[2][3] = { { USER_BOOTANIMATION_FILE, SYSTEM_BOOTANIMATION_FILE, SYSTEM_ENCRYPTED_BOOTANIMATION_FILE }, { USER_SHUTDOWN_ANIMATION_FILE, SYSTEM_SHUTDOWN_ANIMATION_FILE, SYSTEM_ENCRYPTED_SHUTDOWN_ANIMATION_FILE} }; int state; state = checkBootState() ? 0 : 1; return fileName[state][image]; } char *BootAnimation::getBootRingtoneFileName(ImageID image) { if (image == IMG_ENC) { return NULL; } char *fileName[2][2] = { { USER_BOOT_MUSIC_FILE, SYSTEM_BOOT_MUSIC_FILE }, { USER_SHUTDOWN_MUSIC_FILE, SYSTEM_SHUTDOWN_MUSIC_FILE } }; int state; state = checkBootState() ? 0 : 1; return fileName[state][image]; } void BootAnimation::playBackgroundMusic(void) { //Shutdown music is playing in ShutdownThread.java if (!checkBootState()) { return; } /* Make sure sound cards are populated */ FILE* fp = NULL; if ((fp = fopen("/proc/asound/cards", "r")) == NULL) { ALOGW("Cannot open /proc/asound/cards file to get sound card info."); } char value[PROPERTY_VALUE_MAX]; property_get("qcom.audio.init", value, "null"); if (strncmp(value, "complete", 8) != 0) { ALOGW("Audio service is not initiated."); } fclose(fp); char *fileName; if (((fileName = getBootRingtoneFileName(IMG_DATA)) != NULL && access(fileName, R_OK) == 0) || ((fileName = getBootRingtoneFileName(IMG_SYS)) != NULL && access(fileName, R_OK) == 0)) { pthread_t tid; pthread_create(&tid, NULL, playMusic, (void *)fileName); pthread_join(tid, NULL); } } bool BootAnimation::checkBootState(void) { char value[PROPERTY_VALUE_MAX]; bool ret = true; property_get("sys.shutdown.requested", value, "null"); if (strncmp(value, "null", 4) != 0) { ret = false; } return ret; } void* playMusic(void* arg) { int index = 0; char *fileName = (char *)arg; sp<MediaPlayer> mp = new MediaPlayer(); sp<MPlayerListener> mListener = new MPlayerListener(); if (mp != NULL) { ALOGD("starting to play %s", fileName); mp->setListener(mListener); if (mp->setDataSource(fileName, NULL) == NO_ERROR) { mp->setAudioStreamType(AUDIO_STREAM_ENFORCED_AUDIBLE); mp->prepare(); } //waiting for media player is prepared. pthread_mutex_lock(&mp_lock); while (!isMPlayerPrepared) { pthread_cond_wait(&mp_cond, &mp_lock); } pthread_mutex_unlock(&mp_lock); audio_devices_t device = AudioSystem::getDevicesForStream(AUDIO_STREAM_ENFORCED_AUDIBLE); AudioSystem::initStreamVolume(AUDIO_STREAM_ENFORCED_AUDIBLE,0,7); AudioSystem::setStreamVolumeIndex(AUDIO_STREAM_ENFORCED_AUDIBLE, 7, device); AudioSystem::getStreamVolumeIndex(AUDIO_STREAM_ENFORCED_AUDIBLE, &index, device); if (index != 0) { ALOGD("playing %s", fileName); mp->seekTo(0); mp->start(); } else { ALOGW("current volume is zero."); } } return NULL; } // --------------------------------------------------------------------------- } Loading cmds/bootanimation/BootAnimation.h +8 −1 Original line number Diff line number Diff line Loading @@ -89,11 +89,17 @@ private: bool android(); bool movie(); enum ImageID { IMG_DATA = 0, IMG_SYS = 1, IMG_ENC = 2 }; char *getAnimationFileName(ImageID image); char *getBootRingtoneFileName(ImageID image); void playBackgroundMusic(); bool checkBootState(); void checkExit(); void checkShowAndroid(); sp<SurfaceComposerClient> mSession; AssetManager mAssets; Texture mAndroid[2]; Texture mAndroid[3]; int mWidth; int mHeight; EGLDisplay mDisplay; Loading @@ -105,6 +111,7 @@ private: ZipFileRO mZip; }; static void* playMusic(void* arg); // --------------------------------------------------------------------------- }; // namespace android Loading services/java/com/android/server/power/ShutdownThread.java +154 −13 Original line number Diff line number Diff line Loading @@ -33,7 +33,11 @@ import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.IntentFilter; import android.media.MediaPlayer; import android.media.MediaPlayer.OnCompletionListener; import android.media.AudioManager; import android.os.Handler; import android.os.Message; import android.os.PowerManager; import android.os.RemoteException; import android.os.ServiceManager; Loading @@ -48,11 +52,22 @@ import android.telephony.MSimTelephonyManager; import com.android.internal.telephony.ITelephony; import com.android.internal.telephony.msim.ITelephonyMSim; import com.android.server.power.PowerManagerService; import android.util.Log; import android.view.IWindowManager; import android.view.WindowManager; import java.lang.reflect.Method; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintWriter; import java.io.OutputStreamWriter; import java.lang.reflect.Method; public final class ShutdownThread extends Thread { // constants private static final String TAG = "ShutdownThread"; Loading Loading @@ -89,9 +104,20 @@ public final class ShutdownThread extends Thread { private PowerManager.WakeLock mCpuWakeLock; private PowerManager.WakeLock mScreenWakeLock; private Handler mHandler; private static MediaPlayer mMediaPlayer; private static final String USER_BOOTANIMATION_FILE = "/data/local/shutdownanimation.zip"; private static final String SYSTEM_BOOTANIMATION_FILE = "/system/media/shutdownanimation.zip"; private static final String SYSTEM_ENCRYPTED_BOOTANIMATION_FILE = "/system/media/shutdownanimation-encrypted.zip"; private static final String MUSIC_SHUTDOWN_FILE = "/system/media/shutdown.wav"; private static final String MUSIC_QRD_SHUTDOWN_FILE = "/data/qrd_theme/boot/shutdown.wav"; private boolean isShutdownMusicPlaying = false; private static AlertDialog sConfirmDialog; private static AudioManager mAudioManager; private ShutdownThread() { } Loading Loading @@ -192,6 +218,30 @@ public final class ShutdownThread extends Thread { shutdownInner(context, confirm); } private static String getShutdownMusicFilePath() { final String[] fileName = {MUSIC_QRD_SHUTDOWN_FILE, MUSIC_SHUTDOWN_FILE}; File checkFile = null; int i = 0; for( ; i < fileName.length; i ++) { checkFile = new File(fileName[i]); if (checkFile.exists()) break; } if (i >= fileName.length) return null; return fileName[i]; } private static void lockDevice() { IWindowManager wm = IWindowManager.Stub.asInterface(ServiceManager .getService(Context.WINDOW_SERVICE)); try { wm.updateRotation(false, false); } catch (RemoteException e) { Log.w(TAG, "boot animation can not lock device!"); } } /** * Request a reboot into safe mode. Must be called from a Looper thread in which its UI * is shown. Loading @@ -215,6 +265,11 @@ public final class ShutdownThread extends Thread { sIsStarted = true; } //acquire audio focus to make the other apps to stop playing muisc mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); mAudioManager.requestAudioFocus(null, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN); if (!checkAnimationFileExist()) { // throw up an indeterminate system dialog to indicate radio is // shutting down. ProgressDialog pd = new ProgressDialog(context); Loading @@ -225,6 +280,7 @@ public final class ShutdownThread extends Thread { pd.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); pd.show(); } sInstance.mContext = context; sInstance.mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE); Loading Loading @@ -333,6 +389,39 @@ public final class ShutdownThread extends Thread { } } String shutDownFile = null; //showShutdownAnimation() is called from here to sync //music and animation properly if(checkAnimationFileExist()) { lockDevice(); showShutdownAnimation(); if (!isSilentMode() && (shutDownFile = getShutdownMusicFilePath()) != null) { isShutdownMusicPlaying = true; shutdownMusicHandler.obtainMessage(0, shutDownFile).sendToTarget(); } } Log.i(TAG, "wait for shutdown music"); final long endTimeForMusic = SystemClock.elapsedRealtime() + MAX_BROADCAST_TIME; synchronized (mActionDoneSync) { while (isShutdownMusicPlaying) { long delay = endTimeForMusic - SystemClock.elapsedRealtime(); if (delay <= 0) { Log.w(TAG, "play shutdown music timeout!"); break; } try { mActionDoneSync.wait(delay); } catch (InterruptedException e) { } } if (!isShutdownMusicPlaying) { Log.i(TAG, "play shutdown music complete."); } } // Shutdown radios. shutdownRadios(MAX_RADIO_WAIT_TIME); Loading Loading @@ -464,15 +553,13 @@ public final class ShutdownThread extends Thread { } if (!radioOff) { try { boolean subRadioOff = true; if (MSimTelephonyManager.getDefault().isMultiSimEnabled()) { final ITelephonyMSim mphone = ITelephonyMSim.Stub.asInterface( ServiceManager.checkService("phone_msim")); for (int i = 0; i < MSimTelephonyManager.getDefault(). getPhoneCount(); i++) { subRadioOff = subRadioOff && !mphone.isRadioOn(i); radioOff = radioOff && !mphone.isRadioOn(i); } radioOff = subRadioOff; } else { radioOff = !phone.isRadioOn(); } Loading Loading @@ -576,4 +663,58 @@ public final class ShutdownThread extends Thread { //Unknown exception } } private static boolean checkAnimationFileExist() { if (new File(USER_BOOTANIMATION_FILE).exists() || new File(SYSTEM_BOOTANIMATION_FILE).exists() || new File(SYSTEM_ENCRYPTED_BOOTANIMATION_FILE).exists()) return true; else return false; } private static boolean isSilentMode() { boolean isSilent = mAudioManager.isSilentMode(); SystemProperties.set("persist.sys.silent", isSilent ? "1" : "0"); return isSilent; } private static void showShutdownAnimation() { /* * When boot completed, "service.bootanim.exit" property is set to 1. * Bootanimation checks this property to stop showing the boot animation. * Since we use the same code for shutdown animation, we * need to reset this property to 0. If this is not set to 0 then shutdown * will stop and exit after displaying the first frame of the animation */ SystemProperties.set("service.bootanim.exit", "0"); SystemProperties.set("ctl.start", "bootanim"); } private Handler shutdownMusicHandler = new Handler() { @Override public void handleMessage(Message msg) { String path = (String) msg.obj; mMediaPlayer = new MediaPlayer(); try { mMediaPlayer.reset(); mMediaPlayer.setDataSource(path); mMediaPlayer.prepare(); mMediaPlayer.start(); mMediaPlayer.setOnCompletionListener(new OnCompletionListener() { @Override public void onCompletion(MediaPlayer mp) { synchronized (mActionDoneSync) { isShutdownMusicPlaying = false; mActionDoneSync.notifyAll(); } } }); } catch (IOException e) { Log.d(TAG, "play shutdown music error:" + e); } } }; } Loading
cmds/bootanimation/Android.mk +2 −1 Original line number Diff line number Diff line Loading @@ -17,7 +17,8 @@ LOCAL_SHARED_LIBRARIES := \ libskia \ libEGL \ libGLESv1_CM \ libgui libgui \ libmedia LOCAL_C_INCLUDES := \ $(call include-path-for, corecg graphics) Loading
cmds/bootanimation/BootAnimation.cpp +196 −7 Original line number Diff line number Diff line /* * Copyright (C) 2007 The Android Open Source Project * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. Loading @@ -22,6 +23,8 @@ #include <fcntl.h> #include <utils/misc.h> #include <signal.h> #include <pthread.h> #include <sys/select.h> #include <cutils/properties.h> Loading Loading @@ -50,21 +53,66 @@ #include <GLES/glext.h> #include <EGL/eglext.h> #include <media/AudioSystem.h> #include <media/mediaplayer.h> #include "BootAnimation.h" #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" #define USER_SHUTDOWN_ANIMATION_FILE "/data/local/shutdownanimation.zip" #define SYSTEM_SHUTDOWN_ANIMATION_FILE "/system/media/shutdownanimation.zip" #define SYSTEM_ENCRYPTED_SHUTDOWN_ANIMATION_FILE "/system/media/shutdownanimation-encrypted.zip" #define USER_BOOT_MUSIC_FILE "/data/local/boot.wav" #define SYSTEM_BOOT_MUSIC_FILE "/system/media/boot.wav" #define USER_SHUTDOWN_MUSIC_FILE "/data/local/shutdown.wav" #define SYSTEM_SHUTDOWN_MUSIC_FILE "/system/media/shutdown.wav" #define EXIT_PROP_NAME "service.bootanim.exit" extern "C" int clock_nanosleep(clockid_t clock_id, int flags, const struct timespec *request, struct timespec *remain); namespace android { // --------------------------------------------------------------------------- static pthread_mutex_t mp_lock; static pthread_cond_t mp_cond; static bool isMPlayerPrepared = false; static bool isMPlayerCompleted = false; class MPlayerListener : public MediaPlayerListener { void notify(int msg, int ext1, int ext2, const Parcel *obj) { switch (msg) { case MEDIA_NOP: // interface test message break; case MEDIA_PREPARED: pthread_mutex_lock(&mp_lock); isMPlayerPrepared = true; pthread_cond_signal(&mp_cond); pthread_mutex_unlock(&mp_lock); break; case MEDIA_PLAYBACK_COMPLETE: pthread_mutex_lock(&mp_lock); isMPlayerCompleted = true; pthread_cond_signal(&mp_cond); pthread_mutex_unlock(&mp_lock); break; default: break; } } }; BootAnimation::BootAnimation() : Thread(false) { mSession = new SurfaceComposerClient(); Loading Loading @@ -287,17 +335,19 @@ status_t BootAnimation::readyToRun() { char decrypt[PROPERTY_VALUE_MAX]; property_get("vold.decrypt", decrypt, ""); // Use customized resources for boot and showdown animation // instead of system predefined boot animation files. 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(getAnimationFileName(IMG_ENC), R_OK) == 0) && (mZip.open(getAnimationFileName(IMG_ENC)) == NO_ERROR)) || ((access(USER_BOOTANIMATION_FILE, R_OK) == 0) && (mZip.open(USER_BOOTANIMATION_FILE) == NO_ERROR)) || ((access(getAnimationFileName(IMG_DATA), R_OK) == 0) && (mZip.open(getAnimationFileName(IMG_DATA)) == NO_ERROR)) || ((access(SYSTEM_BOOTANIMATION_FILE, R_OK) == 0) && (mZip.open(SYSTEM_BOOTANIMATION_FILE) == NO_ERROR))) { ((access(getAnimationFileName(IMG_SYS), R_OK) == 0) && (mZip.open(getAnimationFileName(IMG_SYS)) == NO_ERROR))) { mAndroidAnimation = false; } Loading Loading @@ -404,6 +454,7 @@ void BootAnimation::checkExit() { bool BootAnimation::movie() { char value[PROPERTY_VALUE_MAX]; ZipFileRO& zip(mZip); size_t numEntries = zip.getNumEntries(); Loading Loading @@ -506,6 +557,14 @@ bool BootAnimation::movie() Region clearReg(Rect(mWidth, mHeight)); clearReg.subtractSelf(Rect(xc, yc, xc+animation.width, yc+animation.height)); pthread_mutex_init(&mp_lock, NULL); pthread_cond_init(&mp_cond, NULL); property_get("persist.sys.silent", value, "null"); if (strncmp(value, "1", 1) != 0) { playBackgroundMusic(); } for (int i=0 ; i<pcount ; i++) { const Animation::Part& part(animation.parts[i]); const size_t fcount = part.frames.size(); Loading Loading @@ -583,9 +642,139 @@ bool BootAnimation::movie() } } ALOGD("waiting for media player to complete."); struct timespec timeout; clock_gettime(CLOCK_REALTIME, &timeout); timeout.tv_sec += 5; //timeout after 5s. pthread_mutex_lock(&mp_lock); while (!isMPlayerCompleted) { int err = pthread_cond_timedwait(&mp_cond, &mp_lock, &timeout); if (err == ETIMEDOUT) { break; } } pthread_mutex_unlock(&mp_lock); ALOGD("media player is completed."); pthread_cond_destroy(&mp_cond); pthread_mutex_destroy(&mp_lock); return false; } char *BootAnimation::getAnimationFileName(ImageID image) { char *fileName[2][3] = { { USER_BOOTANIMATION_FILE, SYSTEM_BOOTANIMATION_FILE, SYSTEM_ENCRYPTED_BOOTANIMATION_FILE }, { USER_SHUTDOWN_ANIMATION_FILE, SYSTEM_SHUTDOWN_ANIMATION_FILE, SYSTEM_ENCRYPTED_SHUTDOWN_ANIMATION_FILE} }; int state; state = checkBootState() ? 0 : 1; return fileName[state][image]; } char *BootAnimation::getBootRingtoneFileName(ImageID image) { if (image == IMG_ENC) { return NULL; } char *fileName[2][2] = { { USER_BOOT_MUSIC_FILE, SYSTEM_BOOT_MUSIC_FILE }, { USER_SHUTDOWN_MUSIC_FILE, SYSTEM_SHUTDOWN_MUSIC_FILE } }; int state; state = checkBootState() ? 0 : 1; return fileName[state][image]; } void BootAnimation::playBackgroundMusic(void) { //Shutdown music is playing in ShutdownThread.java if (!checkBootState()) { return; } /* Make sure sound cards are populated */ FILE* fp = NULL; if ((fp = fopen("/proc/asound/cards", "r")) == NULL) { ALOGW("Cannot open /proc/asound/cards file to get sound card info."); } char value[PROPERTY_VALUE_MAX]; property_get("qcom.audio.init", value, "null"); if (strncmp(value, "complete", 8) != 0) { ALOGW("Audio service is not initiated."); } fclose(fp); char *fileName; if (((fileName = getBootRingtoneFileName(IMG_DATA)) != NULL && access(fileName, R_OK) == 0) || ((fileName = getBootRingtoneFileName(IMG_SYS)) != NULL && access(fileName, R_OK) == 0)) { pthread_t tid; pthread_create(&tid, NULL, playMusic, (void *)fileName); pthread_join(tid, NULL); } } bool BootAnimation::checkBootState(void) { char value[PROPERTY_VALUE_MAX]; bool ret = true; property_get("sys.shutdown.requested", value, "null"); if (strncmp(value, "null", 4) != 0) { ret = false; } return ret; } void* playMusic(void* arg) { int index = 0; char *fileName = (char *)arg; sp<MediaPlayer> mp = new MediaPlayer(); sp<MPlayerListener> mListener = new MPlayerListener(); if (mp != NULL) { ALOGD("starting to play %s", fileName); mp->setListener(mListener); if (mp->setDataSource(fileName, NULL) == NO_ERROR) { mp->setAudioStreamType(AUDIO_STREAM_ENFORCED_AUDIBLE); mp->prepare(); } //waiting for media player is prepared. pthread_mutex_lock(&mp_lock); while (!isMPlayerPrepared) { pthread_cond_wait(&mp_cond, &mp_lock); } pthread_mutex_unlock(&mp_lock); audio_devices_t device = AudioSystem::getDevicesForStream(AUDIO_STREAM_ENFORCED_AUDIBLE); AudioSystem::initStreamVolume(AUDIO_STREAM_ENFORCED_AUDIBLE,0,7); AudioSystem::setStreamVolumeIndex(AUDIO_STREAM_ENFORCED_AUDIBLE, 7, device); AudioSystem::getStreamVolumeIndex(AUDIO_STREAM_ENFORCED_AUDIBLE, &index, device); if (index != 0) { ALOGD("playing %s", fileName); mp->seekTo(0); mp->start(); } else { ALOGW("current volume is zero."); } } return NULL; } // --------------------------------------------------------------------------- } Loading
cmds/bootanimation/BootAnimation.h +8 −1 Original line number Diff line number Diff line Loading @@ -89,11 +89,17 @@ private: bool android(); bool movie(); enum ImageID { IMG_DATA = 0, IMG_SYS = 1, IMG_ENC = 2 }; char *getAnimationFileName(ImageID image); char *getBootRingtoneFileName(ImageID image); void playBackgroundMusic(); bool checkBootState(); void checkExit(); void checkShowAndroid(); sp<SurfaceComposerClient> mSession; AssetManager mAssets; Texture mAndroid[2]; Texture mAndroid[3]; int mWidth; int mHeight; EGLDisplay mDisplay; Loading @@ -105,6 +111,7 @@ private: ZipFileRO mZip; }; static void* playMusic(void* arg); // --------------------------------------------------------------------------- }; // namespace android Loading
services/java/com/android/server/power/ShutdownThread.java +154 −13 Original line number Diff line number Diff line Loading @@ -33,7 +33,11 @@ import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.IntentFilter; import android.media.MediaPlayer; import android.media.MediaPlayer.OnCompletionListener; import android.media.AudioManager; import android.os.Handler; import android.os.Message; import android.os.PowerManager; import android.os.RemoteException; import android.os.ServiceManager; Loading @@ -48,11 +52,22 @@ import android.telephony.MSimTelephonyManager; import com.android.internal.telephony.ITelephony; import com.android.internal.telephony.msim.ITelephonyMSim; import com.android.server.power.PowerManagerService; import android.util.Log; import android.view.IWindowManager; import android.view.WindowManager; import java.lang.reflect.Method; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintWriter; import java.io.OutputStreamWriter; import java.lang.reflect.Method; public final class ShutdownThread extends Thread { // constants private static final String TAG = "ShutdownThread"; Loading Loading @@ -89,9 +104,20 @@ public final class ShutdownThread extends Thread { private PowerManager.WakeLock mCpuWakeLock; private PowerManager.WakeLock mScreenWakeLock; private Handler mHandler; private static MediaPlayer mMediaPlayer; private static final String USER_BOOTANIMATION_FILE = "/data/local/shutdownanimation.zip"; private static final String SYSTEM_BOOTANIMATION_FILE = "/system/media/shutdownanimation.zip"; private static final String SYSTEM_ENCRYPTED_BOOTANIMATION_FILE = "/system/media/shutdownanimation-encrypted.zip"; private static final String MUSIC_SHUTDOWN_FILE = "/system/media/shutdown.wav"; private static final String MUSIC_QRD_SHUTDOWN_FILE = "/data/qrd_theme/boot/shutdown.wav"; private boolean isShutdownMusicPlaying = false; private static AlertDialog sConfirmDialog; private static AudioManager mAudioManager; private ShutdownThread() { } Loading Loading @@ -192,6 +218,30 @@ public final class ShutdownThread extends Thread { shutdownInner(context, confirm); } private static String getShutdownMusicFilePath() { final String[] fileName = {MUSIC_QRD_SHUTDOWN_FILE, MUSIC_SHUTDOWN_FILE}; File checkFile = null; int i = 0; for( ; i < fileName.length; i ++) { checkFile = new File(fileName[i]); if (checkFile.exists()) break; } if (i >= fileName.length) return null; return fileName[i]; } private static void lockDevice() { IWindowManager wm = IWindowManager.Stub.asInterface(ServiceManager .getService(Context.WINDOW_SERVICE)); try { wm.updateRotation(false, false); } catch (RemoteException e) { Log.w(TAG, "boot animation can not lock device!"); } } /** * Request a reboot into safe mode. Must be called from a Looper thread in which its UI * is shown. Loading @@ -215,6 +265,11 @@ public final class ShutdownThread extends Thread { sIsStarted = true; } //acquire audio focus to make the other apps to stop playing muisc mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); mAudioManager.requestAudioFocus(null, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN); if (!checkAnimationFileExist()) { // throw up an indeterminate system dialog to indicate radio is // shutting down. ProgressDialog pd = new ProgressDialog(context); Loading @@ -225,6 +280,7 @@ public final class ShutdownThread extends Thread { pd.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); pd.show(); } sInstance.mContext = context; sInstance.mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE); Loading Loading @@ -333,6 +389,39 @@ public final class ShutdownThread extends Thread { } } String shutDownFile = null; //showShutdownAnimation() is called from here to sync //music and animation properly if(checkAnimationFileExist()) { lockDevice(); showShutdownAnimation(); if (!isSilentMode() && (shutDownFile = getShutdownMusicFilePath()) != null) { isShutdownMusicPlaying = true; shutdownMusicHandler.obtainMessage(0, shutDownFile).sendToTarget(); } } Log.i(TAG, "wait for shutdown music"); final long endTimeForMusic = SystemClock.elapsedRealtime() + MAX_BROADCAST_TIME; synchronized (mActionDoneSync) { while (isShutdownMusicPlaying) { long delay = endTimeForMusic - SystemClock.elapsedRealtime(); if (delay <= 0) { Log.w(TAG, "play shutdown music timeout!"); break; } try { mActionDoneSync.wait(delay); } catch (InterruptedException e) { } } if (!isShutdownMusicPlaying) { Log.i(TAG, "play shutdown music complete."); } } // Shutdown radios. shutdownRadios(MAX_RADIO_WAIT_TIME); Loading Loading @@ -464,15 +553,13 @@ public final class ShutdownThread extends Thread { } if (!radioOff) { try { boolean subRadioOff = true; if (MSimTelephonyManager.getDefault().isMultiSimEnabled()) { final ITelephonyMSim mphone = ITelephonyMSim.Stub.asInterface( ServiceManager.checkService("phone_msim")); for (int i = 0; i < MSimTelephonyManager.getDefault(). getPhoneCount(); i++) { subRadioOff = subRadioOff && !mphone.isRadioOn(i); radioOff = radioOff && !mphone.isRadioOn(i); } radioOff = subRadioOff; } else { radioOff = !phone.isRadioOn(); } Loading Loading @@ -576,4 +663,58 @@ public final class ShutdownThread extends Thread { //Unknown exception } } private static boolean checkAnimationFileExist() { if (new File(USER_BOOTANIMATION_FILE).exists() || new File(SYSTEM_BOOTANIMATION_FILE).exists() || new File(SYSTEM_ENCRYPTED_BOOTANIMATION_FILE).exists()) return true; else return false; } private static boolean isSilentMode() { boolean isSilent = mAudioManager.isSilentMode(); SystemProperties.set("persist.sys.silent", isSilent ? "1" : "0"); return isSilent; } private static void showShutdownAnimation() { /* * When boot completed, "service.bootanim.exit" property is set to 1. * Bootanimation checks this property to stop showing the boot animation. * Since we use the same code for shutdown animation, we * need to reset this property to 0. If this is not set to 0 then shutdown * will stop and exit after displaying the first frame of the animation */ SystemProperties.set("service.bootanim.exit", "0"); SystemProperties.set("ctl.start", "bootanim"); } private Handler shutdownMusicHandler = new Handler() { @Override public void handleMessage(Message msg) { String path = (String) msg.obj; mMediaPlayer = new MediaPlayer(); try { mMediaPlayer.reset(); mMediaPlayer.setDataSource(path); mMediaPlayer.prepare(); mMediaPlayer.start(); mMediaPlayer.setOnCompletionListener(new OnCompletionListener() { @Override public void onCompletion(MediaPlayer mp) { synchronized (mActionDoneSync) { isShutdownMusicPlaying = false; mActionDoneSync.notifyAll(); } } }); } catch (IOException e) { Log.d(TAG, "play shutdown music error:" + e); } } }; }