diff options
author | Bill Yi <byi@google.com> | 2014-10-22 09:00:49 -0700 |
---|---|---|
committer | Bill Yi <byi@google.com> | 2014-10-22 09:00:49 -0700 |
commit | 5a71f83227f0340a265f34b226d8fe01d4dd9773 (patch) | |
tree | 9e74435ad8e21fe6ace6a1c49ca2f596c60ced34 /cmds/bootanimation | |
parent | 52656916e35b08013bf776b3603d6cecba287a1e (diff) | |
parent | a0d07d49b8b0aae71beb48ec31b43f6923530d00 (diff) | |
download | frameworks_base-5a71f83227f0340a265f34b226d8fe01d4dd9773.zip frameworks_base-5a71f83227f0340a265f34b226d8fe01d4dd9773.tar.gz frameworks_base-5a71f83227f0340a265f34b226d8fe01d4dd9773.tar.bz2 |
Merge lmp-dev-plus-aosp-without-vendor into stage-aosp-master
Change-Id: I7063b7b52e9c09a57eb6bf3b4ffa3716d58ebf43
Diffstat (limited to 'cmds/bootanimation')
-rw-r--r-- | cmds/bootanimation/Android.mk | 9 | ||||
-rw-r--r-- | cmds/bootanimation/AudioPlayer.cpp | 314 | ||||
-rw-r--r-- | cmds/bootanimation/AudioPlayer.h | 47 | ||||
-rw-r--r-- | cmds/bootanimation/BootAnimation.cpp | 145 | ||||
-rw-r--r-- | cmds/bootanimation/BootAnimation.h | 7 |
5 files changed, 484 insertions, 38 deletions
diff --git a/cmds/bootanimation/Android.mk b/cmds/bootanimation/Android.mk index dd987e0..d6ecbe3 100644 --- a/cmds/bootanimation/Android.mk +++ b/cmds/bootanimation/Android.mk @@ -3,10 +3,13 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ bootanimation_main.cpp \ + AudioPlayer.cpp \ BootAnimation.cpp LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES +LOCAL_C_INCLUDES += external/tinyalsa/include + LOCAL_SHARED_LIBRARIES := \ libcutils \ liblog \ @@ -17,10 +20,8 @@ LOCAL_SHARED_LIBRARIES := \ libskia \ libEGL \ libGLESv1_CM \ - libgui - -LOCAL_C_INCLUDES := \ - $(call include-path-for, corecg graphics) + libgui \ + libtinyalsa LOCAL_MODULE:= bootanimation diff --git a/cmds/bootanimation/AudioPlayer.cpp b/cmds/bootanimation/AudioPlayer.cpp new file mode 100644 index 0000000..471b77f --- /dev/null +++ b/cmds/bootanimation/AudioPlayer.cpp @@ -0,0 +1,314 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_NDEBUG 0 +#define LOG_TAG "BootAnim_AudioPlayer" + +#include "AudioPlayer.h" + +#include <androidfw/ZipFileRO.h> +#include <tinyalsa/asoundlib.h> +#include <utils/Log.h> +#include <utils/String8.h> + +#define ID_RIFF 0x46464952 +#define ID_WAVE 0x45564157 +#define ID_FMT 0x20746d66 +#define ID_DATA 0x61746164 + +// Maximum line length for audio_conf.txt +// We only accept lines less than this length to avoid overflows using sscanf() +#define MAX_LINE_LENGTH 1024 + +struct riff_wave_header { + uint32_t riff_id; + uint32_t riff_sz; + uint32_t wave_id; +}; + +struct chunk_header { + uint32_t id; + uint32_t sz; +}; + +struct chunk_fmt { + uint16_t audio_format; + uint16_t num_channels; + uint32_t sample_rate; + uint32_t byte_rate; + uint16_t block_align; + uint16_t bits_per_sample; +}; + + +namespace android { + +AudioPlayer::AudioPlayer() + : mCard(-1), + mDevice(-1), + mPeriodSize(0), + mPeriodCount(0), + mCurrentFile(NULL) +{ +} + +AudioPlayer::~AudioPlayer() { +} + +static bool setMixerValue(struct mixer* mixer, const char* name, const char* values) +{ + if (!mixer) { + ALOGE("no mixer in setMixerValue"); + return false; + } + struct mixer_ctl *ctl = mixer_get_ctl_by_name(mixer, name); + if (!ctl) { + ALOGE("mixer_get_ctl_by_name failed for %s", name); + return false; + } + + enum mixer_ctl_type type = mixer_ctl_get_type(ctl); + int numValues = mixer_ctl_get_num_values(ctl); + int intValue; + char stringValue[MAX_LINE_LENGTH]; + + for (int i = 0; i < numValues && values; i++) { + // strip leading space + while (*values == ' ') values++; + if (*values == 0) break; + + switch (type) { + case MIXER_CTL_TYPE_BOOL: + case MIXER_CTL_TYPE_INT: + if (sscanf(values, "%d", &intValue) == 1) { + if (mixer_ctl_set_value(ctl, i, intValue) != 0) { + ALOGE("mixer_ctl_set_value failed for %s %d", name, intValue); + } + } else { + ALOGE("Could not parse %s as int for %d", intValue, name); + } + break; + case MIXER_CTL_TYPE_ENUM: + if (sscanf(values, "%s", stringValue) == 1) { + if (mixer_ctl_set_enum_by_string(ctl, stringValue) != 0) { + ALOGE("mixer_ctl_set_enum_by_string failed for %s %%s", name, stringValue); + } + } else { + ALOGE("Could not parse %s as enum for %d", stringValue, name); + } + break; + default: + ALOGE("unsupported mixer type %d for %s", type, name); + break; + } + + values = strchr(values, ' '); + } + + return true; +} + + +/* + * Parse the audio configuration file. + * The file is named audio_conf.txt and must begin with the following header: + * + * card=<ALSA card number> + * device=<ALSA device number> + * period_size=<period size> + * period_count=<period count> + * + * This header is followed by zero or more mixer settings, each with the format: + * mixer "<name>" = <value list> + * Since mixer names can contain spaces, the name must be enclosed in double quotes. + * The values in the value list can be integers, booleans (represented by 0 or 1) + * or strings for enum values. + */ +bool AudioPlayer::init(const char* config) +{ + int tempInt; + struct mixer* mixer = NULL; + char name[MAX_LINE_LENGTH]; + + for (;;) { + const char* endl = strstr(config, "\n"); + if (!endl) break; + String8 line(config, endl - config); + if (line.length() >= MAX_LINE_LENGTH) { + ALOGE("Line too long in audio_conf.txt"); + return false; + } + const char* l = line.string(); + + if (sscanf(l, "card=%d", &tempInt) == 1) { + ALOGD("card=%d", tempInt); + mCard = tempInt; + + mixer = mixer_open(mCard); + if (!mixer) { + ALOGE("could not open mixer for card %d", mCard); + return false; + } + } else if (sscanf(l, "device=%d", &tempInt) == 1) { + ALOGD("device=%d", tempInt); + mDevice = tempInt; + } else if (sscanf(l, "period_size=%d", &tempInt) == 1) { + ALOGD("period_size=%d", tempInt); + mPeriodSize = tempInt; + } else if (sscanf(l, "period_count=%d", &tempInt) == 1) { + ALOGD("period_count=%d", tempInt); + mPeriodCount = tempInt; + } else if (sscanf(l, "mixer \"%[0-9a-zA-Z _]s\"", name) == 1) { + const char* values = strchr(l, '='); + if (values) { + values++; // skip '=' + ALOGD("name: \"%s\" = %s", name, values); + setMixerValue(mixer, name, values); + } else { + ALOGE("values missing for name: \"%s\"", name); + } + } + config = ++endl; + } + + mixer_close(mixer); + + if (mCard >= 0 && mDevice >= 0) { + return true; + } + + return false; +} + +void AudioPlayer::playFile(struct FileMap* fileMap) { + // stop any currently playing sound + requestExitAndWait(); + + mCurrentFile = fileMap; + run("bootanim audio", PRIORITY_URGENT_AUDIO); +} + +bool AudioPlayer::threadLoop() +{ + struct pcm_config config; + struct pcm *pcm = NULL; + bool moreChunks = true; + const struct chunk_fmt* chunkFmt = NULL; + void* buffer = NULL; + int bufferSize; + const uint8_t* wavData; + size_t wavLength; + const struct riff_wave_header* wavHeader; + + if (mCurrentFile == NULL) { + ALOGE("mCurrentFile is NULL"); + return false; + } + + wavData = (const uint8_t *)mCurrentFile->getDataPtr(); + if (!wavData) { + ALOGE("Could not access WAV file data"); + goto exit; + } + wavLength = mCurrentFile->getDataLength(); + + wavHeader = (const struct riff_wave_header *)wavData; + if (wavLength < sizeof(*wavHeader) || (wavHeader->riff_id != ID_RIFF) || + (wavHeader->wave_id != ID_WAVE)) { + ALOGE("Error: audio file is not a riff/wave file\n"); + goto exit; + } + wavData += sizeof(*wavHeader); + wavLength -= sizeof(*wavHeader); + + do { + const struct chunk_header* chunkHeader = (const struct chunk_header*)wavData; + if (wavLength < sizeof(*chunkHeader)) { + ALOGE("EOF reading chunk headers"); + goto exit; + } + + wavData += sizeof(*chunkHeader); + wavLength -= sizeof(*chunkHeader); + + switch (chunkHeader->id) { + case ID_FMT: + chunkFmt = (const struct chunk_fmt *)wavData; + wavData += chunkHeader->sz; + wavLength -= chunkHeader->sz; + break; + case ID_DATA: + /* Stop looking for chunks */ + moreChunks = 0; + break; + default: + /* Unknown chunk, skip bytes */ + wavData += chunkHeader->sz; + wavLength -= chunkHeader->sz; + } + } while (moreChunks); + + if (!chunkFmt) { + ALOGE("format not found in WAV file"); + goto exit; + } + + + memset(&config, 0, sizeof(config)); + config.channels = chunkFmt->num_channels; + config.rate = chunkFmt->sample_rate; + config.period_size = mPeriodSize; + config.period_count = mPeriodCount; + config.start_threshold = mPeriodSize / 4; + config.stop_threshold = INT_MAX; + config.avail_min = config.start_threshold; + if (chunkFmt->bits_per_sample != 16) { + ALOGE("only 16 bit WAV files are supported"); + goto exit; + } + config.format = PCM_FORMAT_S16_LE; + + pcm = pcm_open(mCard, mDevice, PCM_OUT, &config); + if (!pcm || !pcm_is_ready(pcm)) { + ALOGE("Unable to open PCM device (%s)\n", pcm_get_error(pcm)); + goto exit; + } + + bufferSize = pcm_frames_to_bytes(pcm, pcm_get_buffer_size(pcm)); + + while (wavLength > 0) { + if (exitPending()) goto exit; + size_t count = bufferSize; + if (count > wavLength) + count = wavLength; + + if (pcm_write(pcm, wavData, count)) { + ALOGE("pcm_write failed (%s)", pcm_get_error(pcm)); + goto exit; + } + wavData += count; + wavLength -= count; + } + +exit: + if (pcm) + pcm_close(pcm); + mCurrentFile->release(); + mCurrentFile = NULL; + return false; +} + +} // namespace android diff --git a/cmds/bootanimation/AudioPlayer.h b/cmds/bootanimation/AudioPlayer.h new file mode 100644 index 0000000..7e82a07 --- /dev/null +++ b/cmds/bootanimation/AudioPlayer.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _BOOTANIMATION_AUDIOPLAYER_H +#define _BOOTANIMATION_AUDIOPLAYER_H + +#include <utils/Thread.h> + +namespace android { + +class AudioPlayer : public Thread +{ +public: + AudioPlayer(); + virtual ~AudioPlayer(); + bool init(const char* config); + + void playFile(struct FileMap* fileMap); + +private: + virtual bool threadLoop(); + +private: + int mCard; // ALSA card to use + int mDevice; // ALSA device to use + int mPeriodSize; + int mPeriodCount; + + struct FileMap* mCurrentFile; +}; + +} // namespace android + +#endif // _BOOTANIMATION_AUDIOPLAYER_H diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp index f3e3aff..167014e 100644 --- a/cmds/bootanimation/BootAnimation.cpp +++ b/cmds/bootanimation/BootAnimation.cpp @@ -14,6 +14,7 @@ * limitations under the License. */ +#define LOG_NDEBUG 0 #define LOG_TAG "BootAnimation" #include <stdint.h> @@ -31,28 +32,28 @@ #include <utils/Atomic.h> #include <utils/Errors.h> #include <utils/Log.h> -#include <utils/threads.h> #include <ui/PixelFormat.h> #include <ui/Rect.h> #include <ui/Region.h> #include <ui/DisplayInfo.h> -#include <ui/FramebufferNativeWindow.h> #include <gui/ISurfaceComposer.h> #include <gui/Surface.h> #include <gui/SurfaceComposerClient.h> -#include <core/SkBitmap.h> -#include <core/SkStream.h> -#include <core/SkImageDecoder.h> +#include <SkBitmap.h> +#include <SkStream.h> +#include <SkImageDecoder.h> #include <GLES/gl.h> #include <GLES/glext.h> #include <EGL/eglext.h> #include "BootAnimation.h" +#include "AudioPlayer.h" +#define OEM_BOOTANIMATION_FILE "/oem/media/bootanimation.zip" #define SYSTEM_BOOTANIMATION_FILE "/system/media/bootanimation.zip" #define SYSTEM_ENCRYPTED_BOOTANIMATION_FILE "/system/media/bootanimation-encrypted.zip" #define EXIT_PROP_NAME "service.bootanim.exit" @@ -96,6 +97,9 @@ void BootAnimation::binderDied(const wp<IBinder>&) // might be blocked on a condition variable that will never be updated. kill( getpid(), SIGKILL ); requestExit(); + if (mAudioPlayer != NULL) { + mAudioPlayer->requestExit(); + } } status_t BootAnimation::initTexture(Texture* texture, AssetManager& assets, @@ -105,7 +109,7 @@ status_t BootAnimation::initTexture(Texture* texture, AssetManager& assets, return NO_INIT; SkBitmap bitmap; SkImageDecoder::DecodeMemory(asset->getBuffer(false), asset->getLength(), - &bitmap, SkBitmap::kNo_Config, SkImageDecoder::kDecodePixels_Mode); + &bitmap, kUnknown_SkColorType, SkImageDecoder::kDecodePixels_Mode); asset->close(); delete asset; @@ -124,20 +128,20 @@ status_t BootAnimation::initTexture(Texture* texture, AssetManager& assets, glGenTextures(1, &texture->name); glBindTexture(GL_TEXTURE_2D, texture->name); - switch (bitmap.getConfig()) { - case SkBitmap::kA8_Config: + switch (bitmap.colorType()) { + case kAlpha_8_SkColorType: glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, w, h, 0, GL_ALPHA, GL_UNSIGNED_BYTE, p); break; - case SkBitmap::kARGB_4444_Config: + case kARGB_4444_SkColorType: glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, p); break; - case SkBitmap::kARGB_8888_Config: + case kN32_SkColorType: glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, p); break; - case SkBitmap::kRGB_565_Config: + case kRGB_565_SkColorType: glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, p); break; @@ -163,7 +167,7 @@ status_t BootAnimation::initTexture(const Animation::Frame& frame) if (codec) { codec->setDitherImage(false); codec->decode(&stream, &bitmap, - SkBitmap::kARGB_8888_Config, + kN32_SkColorType, SkImageDecoder::kDecodePixels_Mode); delete codec; } @@ -187,8 +191,8 @@ status_t BootAnimation::initTexture(const Animation::Frame& frame) if (tw < w) tw <<= 1; if (th < h) th <<= 1; - switch (bitmap.getConfig()) { - case SkBitmap::kARGB_8888_Config: + switch (bitmap.colorType()) { + case kN32_SkColorType: if (tw != w || th != h) { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tw, th, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); @@ -200,7 +204,7 @@ status_t BootAnimation::initTexture(const Animation::Frame& frame) } break; - case SkBitmap::kRGB_565_Config: + case kRGB_565_SkColorType: if (tw != w || th != h) { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tw, th, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 0); @@ -286,6 +290,9 @@ status_t BootAnimation::readyToRun() { (access(SYSTEM_ENCRYPTED_BOOTANIMATION_FILE, R_OK) == 0) && ((zipFile = ZipFileRO::open(SYSTEM_ENCRYPTED_BOOTANIMATION_FILE)) != NULL)) || + ((access(OEM_BOOTANIMATION_FILE, R_OK) == 0) && + ((zipFile = ZipFileRO::open(OEM_BOOTANIMATION_FILE)) != NULL)) || + ((access(SYSTEM_BOOTANIMATION_FILE, R_OK) == 0) && ((zipFile = ZipFileRO::open(SYSTEM_BOOTANIMATION_FILE)) != NULL))) { mZip = zipFile; @@ -388,29 +395,76 @@ void BootAnimation::checkExit() { int exitnow = atoi(value); if (exitnow) { requestExit(); + if (mAudioPlayer != NULL) { + mAudioPlayer->requestExit(); + } } } -bool BootAnimation::movie() +// Parse a color represented as an HTML-style 'RRGGBB' string: each pair of +// characters in str is a hex number in [0, 255], which are converted to +// floating point values in the range [0.0, 1.0] and placed in the +// corresponding elements of color. +// +// If the input string isn't valid, parseColor returns false and color is +// left unchanged. +static bool parseColor(const char str[7], float color[3]) { + float tmpColor[3]; + for (int i = 0; i < 3; i++) { + int val = 0; + for (int j = 0; j < 2; j++) { + val *= 16; + char c = str[2*i + j]; + if (c >= '0' && c <= '9') val += c - '0'; + else if (c >= 'A' && c <= 'F') val += (c - 'A') + 10; + else if (c >= 'a' && c <= 'f') val += (c - 'a') + 10; + else return false; + } + tmpColor[i] = static_cast<float>(val) / 255.0f; + } + memcpy(color, tmpColor, sizeof(tmpColor)); + return true; +} + +bool BootAnimation::readFile(const char* name, String8& outString) { - ZipEntryRO desc = mZip->findEntryByName("desc.txt"); - ALOGE_IF(!desc, "couldn't find desc.txt"); - if (!desc) { + ZipEntryRO entry = mZip->findEntryByName(name); + ALOGE_IF(!entry, "couldn't find %s", name); + if (!entry) { return false; } - FileMap* descMap = mZip->createEntryFileMap(desc); - mZip->releaseEntry(desc); - ALOGE_IF(!descMap, "descMap is null"); - if (!descMap) { + FileMap* entryMap = mZip->createEntryFileMap(entry); + mZip->releaseEntry(entry); + ALOGE_IF(!entryMap, "entryMap is null"); + if (!entryMap) { return false; } - String8 desString((char const*)descMap->getDataPtr(), - descMap->getDataLength()); - descMap->release(); + outString.setTo((char const*)entryMap->getDataPtr(), entryMap->getDataLength()); + entryMap->release(); + return true; +} + +bool BootAnimation::movie() +{ + String8 desString; + + if (!readFile("desc.txt", desString)) { + return false; + } char const* s = desString.string(); + // Create and initialize an AudioPlayer if we have an audio_conf.txt file + String8 audioConf; + if (readFile("audio_conf.txt", audioConf)) { + mAudioPlayer = new AudioPlayer; + if (!mAudioPlayer->init(audioConf.string())) { + ALOGE("mAudioPlayer.init failed"); + mAudioPlayer = NULL; + } + } + Animation animation; // Parse the description file @@ -421,20 +475,29 @@ bool BootAnimation::movie() const char* l = line.string(); int fps, width, height, count, pause; char path[ANIM_ENTRY_NAME_MAX]; + char color[7] = "000000"; // default to black if unspecified + char pathType; if (sscanf(l, "%d %d %d", &width, &height, &fps) == 3) { - //LOGD("> w=%d, h=%d, fps=%d", width, height, fps); + // ALOGD("> w=%d, h=%d, fps=%d", width, height, fps); animation.width = width; animation.height = height; animation.fps = fps; } - else if (sscanf(l, " %c %d %d %s", &pathType, &count, &pause, path) == 4) { - //LOGD("> type=%c, count=%d, pause=%d, path=%s", pathType, count, pause, path); + else if (sscanf(l, " %c %d %d %s #%6s", &pathType, &count, &pause, path, color) >= 4) { + // ALOGD("> type=%c, count=%d, pause=%d, path=%s, color=%s", pathType, count, pause, path, color); Animation::Part part; part.playUntilComplete = pathType == 'c'; part.count = count; part.pause = pause; part.path = path; + part.audioFile = NULL; + if (!parseColor(color, part.backgroundColor)) { + ALOGE("> invalid color '#%s'", color); + part.backgroundColor[0] = 0.0f; + part.backgroundColor[1] = 0.0f; + part.backgroundColor[2] = 0.0f; + } animation.parts.add(part); } @@ -469,11 +532,16 @@ bool BootAnimation::movie() if (method == ZipFileRO::kCompressStored) { FileMap* map = mZip->createEntryFileMap(entry); if (map) { - Animation::Frame frame; - frame.name = leaf; - frame.map = map; Animation::Part& part(animation.parts.editItemAt(j)); - part.frames.add(frame); + if (leaf == "audio.wav") { + // a part may have at most one audio file + part.audioFile = map; + } else { + Animation::Frame frame; + frame.name = leaf; + frame.map = map; + part.frames.add(frame); + } } } } @@ -520,6 +588,17 @@ bool BootAnimation::movie() if(exitPending() && !part.playUntilComplete) break; + // only play audio file the first time we animate the part + if (r == 0 && mAudioPlayer != NULL && part.audioFile) { + mAudioPlayer->playFile(part.audioFile); + } + + glClearColor( + part.backgroundColor[0], + part.backgroundColor[1], + part.backgroundColor[2], + 1.0f); + for (size_t j=0 ; j<fcount && (!exitPending() || part.playUntilComplete) ; j++) { const Animation::Frame& frame(part.frames[j]); nsecs_t lastFrame = systemTime(); diff --git a/cmds/bootanimation/BootAnimation.h b/cmds/bootanimation/BootAnimation.h index ba1c507..f968b25 100644 --- a/cmds/bootanimation/BootAnimation.h +++ b/cmds/bootanimation/BootAnimation.h @@ -21,7 +21,7 @@ #include <sys/types.h> #include <androidfw/AssetManager.h> -#include <utils/threads.h> +#include <utils/Thread.h> #include <EGL/egl.h> #include <GLES/gl.h> @@ -30,6 +30,7 @@ class SkBitmap; namespace android { +class AudioPlayer; class Surface; class SurfaceComposerClient; class SurfaceControl; @@ -71,6 +72,8 @@ private: String8 path; SortedVector<Frame> frames; bool playUntilComplete; + float backgroundColor[3]; + FileMap* audioFile; }; int fps; int width; @@ -81,11 +84,13 @@ private: status_t initTexture(Texture* texture, AssetManager& asset, const char* name); status_t initTexture(const Animation::Frame& frame); bool android(); + bool readFile(const char* name, String8& outString); bool movie(); void checkExit(); sp<SurfaceComposerClient> mSession; + sp<AudioPlayer> mAudioPlayer; AssetManager mAssets; Texture mAndroid[2]; int mWidth; |