BootAnimation.cpp revision 9748086fe267e21d243a49df1775905094a28dd9
19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2007 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
17ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood#define LOG_NDEBUG 0
18bc7261130a51dc9f3461d3970eee1b923bcbf193Mathias Agopian#define LOG_TAG "BootAnimation"
19bc7261130a51dc9f3461d3970eee1b923bcbf193Mathias Agopian
209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <stdint.h>
219748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi#include <sys/inotify.h>
229748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi#include <sys/poll.h>
239748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi#include <sys/stat.h>
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <sys/types.h>
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <math.h>
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <fcntl.h>
279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <utils/misc.h>
28b4d5a72691846bce5779cc3db056f09a5031d7ccMathias Agopian#include <signal.h>
29bb94f3107ea567ddf67bed4617c3bcbd602538dfElliott Hughes#include <time.h>
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
31bd9a08d318f94a3d0b2f8f9d7b16b10736d80c5cJason parks#include <cutils/properties.h>
32bd9a08d318f94a3d0b2f8f9d7b16b10736d80c5cJason parks
33b13b9bdad2baf6ad1ec2e56b6b7598fa20f55fc4Mathias Agopian#include <androidfw/AssetManager.h>
34ac31a3b8b09aba1c5ebc73f0cf65cac2210aa6b7Mathias Agopian#include <binder/IPCThreadState.h>
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <utils/Atomic.h>
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <utils/Errors.h>
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <utils/Log.h>
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <ui/PixelFormat.h>
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <ui/Rect.h>
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <ui/Region.h>
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <ui/DisplayInfo.h>
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
440b722fe9ce98d97dbcb6fefd170b85ab7037e528Jeff Brown#include <gui/ISurfaceComposer.h>
458335f1ccccedb6655d96d9d5b697a7f0938235ddMathias Agopian#include <gui/Surface.h>
468335f1ccccedb6655d96d9d5b697a7f0938235ddMathias Agopian#include <gui/SurfaceComposerClient.h>
47000479f9e325b4e426a67033abd92d47da412725Mathias Agopian
48cfedceb8c180a2e176154d461659e0c3569dc931Andreas Gampe// TODO: Fix Skia.
49cfedceb8c180a2e176154d461659e0c3569dc931Andreas Gampe#pragma GCC diagnostic push
50cfedceb8c180a2e176154d461659e0c3569dc931Andreas Gampe#pragma GCC diagnostic ignored "-Wunused-parameter"
51eece0dda56ae29fff6e9003df97594f6ac50b6e2Derek Sollenberger#include <SkBitmap.h>
52eece0dda56ae29fff6e9003df97594f6ac50b6e2Derek Sollenberger#include <SkStream.h>
53eece0dda56ae29fff6e9003df97594f6ac50b6e2Derek Sollenberger#include <SkImageDecoder.h>
54cfedceb8c180a2e176154d461659e0c3569dc931Andreas Gampe#pragma GCC diagnostic pop
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <GLES/gl.h>
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <GLES/glext.h>
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <EGL/eglext.h>
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "BootAnimation.h"
61ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood#include "AudioPlayer.h"
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectnamespace android {
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
659748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchistatic const char OEM_BOOTANIMATION_FILE[] = "/oem/media/bootanimation.zip";
669748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchistatic const char SYSTEM_BOOTANIMATION_FILE[] = "/system/media/bootanimation.zip";
679748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchistatic const char SYSTEM_ENCRYPTED_BOOTANIMATION_FILE[] = "/system/media/bootanimation-encrypted.zip";
689748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchistatic const char SYSTEM_DATA_DIR_PATH[] = "/data/system";
699748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchistatic const char SYSTEM_TIME_DIR_NAME[] = "time";
709748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchistatic const char SYSTEM_TIME_DIR_PATH[] = "/data/system/time";
719748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchistatic const char LAST_TIME_CHANGED_FILE_NAME[] = "last_time_change";
729748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchistatic const char LAST_TIME_CHANGED_FILE_PATH[] = "/data/system/time/last_time_change";
739748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchistatic const char ACCURATE_TIME_FLAG_FILE_NAME[] = "time_is_accurate";
749748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchistatic const char ACCURATE_TIME_FLAG_FILE_PATH[] = "/data/system/time/time_is_accurate";
759748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchistatic const char EXIT_PROP_NAME[] = "service.bootanim.exit";
76afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamathstatic const int ANIM_ENTRY_NAME_MAX = 256;
77afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// ---------------------------------------------------------------------------
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
809748086fe267e21d243a49df1775905094a28dd9Damien BargiacchiBootAnimation::BootAnimation() : Thread(false), mClockEnabled(true), mTimeIsAccurate(false),
819748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        mTimeCheckThread(NULL) {
82627e7b50be41e4fdee758a1bfad3a55de56b4e27Mathias Agopian    mSession = new SurfaceComposerClient();
839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
859748086fe267e21d243a49df1775905094a28dd9Damien BargiacchiBootAnimation::~BootAnimation() {}
869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectvoid BootAnimation::onFirstRef() {
88bc7261130a51dc9f3461d3970eee1b923bcbf193Mathias Agopian    status_t err = mSession->linkToComposerDeath(this);
893762c311729fe9f3af085c14c5c1fb471d994c03Steve Block    ALOGE_IF(err, "linkToComposerDeath failed (%s) ", strerror(-err));
908434c5369304e639efe8eab368ca410c589d87c2Mathias Agopian    if (err == NO_ERROR) {
91bc7261130a51dc9f3461d3970eee1b923bcbf193Mathias Agopian        run("BootAnimation", PRIORITY_DISPLAY);
92bc7261130a51dc9f3461d3970eee1b923bcbf193Mathias Agopian    }
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
95bc7261130a51dc9f3461d3970eee1b923bcbf193Mathias Agopiansp<SurfaceComposerClient> BootAnimation::session() const {
969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return mSession;
979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
99bc7261130a51dc9f3461d3970eee1b923bcbf193Mathias Agopian
100afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamathvoid BootAnimation::binderDied(const wp<IBinder>&)
101bc7261130a51dc9f3461d3970eee1b923bcbf193Mathias Agopian{
102bc7261130a51dc9f3461d3970eee1b923bcbf193Mathias Agopian    // woah, surfaceflinger died!
1035baa3a62a97544669fba6d65a11c07f252e654ddSteve Block    ALOGD("SurfaceFlinger died, exiting...");
104bc7261130a51dc9f3461d3970eee1b923bcbf193Mathias Agopian
105bc7261130a51dc9f3461d3970eee1b923bcbf193Mathias Agopian    // calling requestExit() is not enough here because the Surface code
106bc7261130a51dc9f3461d3970eee1b923bcbf193Mathias Agopian    // might be blocked on a condition variable that will never be updated.
107bc7261130a51dc9f3461d3970eee1b923bcbf193Mathias Agopian    kill( getpid(), SIGKILL );
108bc7261130a51dc9f3461d3970eee1b923bcbf193Mathias Agopian    requestExit();
109ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood    if (mAudioPlayer != NULL) {
110ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood        mAudioPlayer->requestExit();
111ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood    }
112bc7261130a51dc9f3461d3970eee1b923bcbf193Mathias Agopian}
113bc7261130a51dc9f3461d3970eee1b923bcbf193Mathias Agopian
1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatus_t BootAnimation::initTexture(Texture* texture, AssetManager& assets,
1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        const char* name) {
1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    Asset* asset = assets.open(name, Asset::ACCESS_BUFFER);
117cfedceb8c180a2e176154d461659e0c3569dc931Andreas Gampe    if (asset == NULL)
1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return NO_INIT;
1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    SkBitmap bitmap;
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    SkImageDecoder::DecodeMemory(asset->getBuffer(false), asset->getLength(),
12142a1d08df7d417fd4e67eabc91ff05ee77fd9995Mike Reed            &bitmap, kUnknown_SkColorType, SkImageDecoder::kDecodePixels_Mode);
1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    asset->close();
1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    delete asset;
1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // ensure we can call getPixels(). No need to call unlock, since the
1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // bitmap will go out of scope when we return from this method.
1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    bitmap.lockPixels();
1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    const int w = bitmap.width();
1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    const int h = bitmap.height();
1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    const void* p = bitmap.getPixels();
1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    GLint crop[4] = { 0, h, w, -h };
1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    texture->w = w;
1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    texture->h = h;
1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    glGenTextures(1, &texture->name);
1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    glBindTexture(GL_TEXTURE_2D, texture->name);
1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14042a1d08df7d417fd4e67eabc91ff05ee77fd9995Mike Reed    switch (bitmap.colorType()) {
14142a1d08df7d417fd4e67eabc91ff05ee77fd9995Mike Reed        case kAlpha_8_SkColorType:
1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, w, h, 0, GL_ALPHA,
1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    GL_UNSIGNED_BYTE, p);
1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            break;
14542a1d08df7d417fd4e67eabc91ff05ee77fd9995Mike Reed        case kARGB_4444_SkColorType:
1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA,
1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    GL_UNSIGNED_SHORT_4_4_4_4, p);
1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            break;
14942a1d08df7d417fd4e67eabc91ff05ee77fd9995Mike Reed        case kN32_SkColorType:
1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA,
1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    GL_UNSIGNED_BYTE, p);
1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            break;
15342a1d08df7d417fd4e67eabc91ff05ee77fd9995Mike Reed        case kRGB_565_SkColorType:
1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB,
1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    GL_UNSIGNED_SHORT_5_6_5, p);
1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            break;
1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        default:
1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            break;
1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return NO_ERROR;
1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1690c1eeb3c8ab53954218d3b8f4be08ff21be3e985Mykola Kondratenkostatus_t BootAnimation::initTexture(const Animation::Frame& frame)
170a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian{
171a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    //StopWatch watch("blah");
172a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
173a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    SkBitmap bitmap;
1740c1eeb3c8ab53954218d3b8f4be08ff21be3e985Mykola Kondratenko    SkMemoryStream  stream(frame.map->getDataPtr(), frame.map->getDataLength());
1752b99e55ee3a0956a43a276f8018356ff9d08eafcMathias Agopian    SkImageDecoder* codec = SkImageDecoder::Factory(&stream);
176cfedceb8c180a2e176154d461659e0c3569dc931Andreas Gampe    if (codec != NULL) {
177c367d48c55e5a3fa0df14fd62889e4bb6b63cb01Elliott Hughes        codec->setDitherImage(false);
1782b99e55ee3a0956a43a276f8018356ff9d08eafcMathias Agopian        codec->decode(&stream, &bitmap,
17942a1d08df7d417fd4e67eabc91ff05ee77fd9995Mike Reed                kN32_SkColorType,
1802b99e55ee3a0956a43a276f8018356ff9d08eafcMathias Agopian                SkImageDecoder::kDecodePixels_Mode);
1812b99e55ee3a0956a43a276f8018356ff9d08eafcMathias Agopian        delete codec;
1822b99e55ee3a0956a43a276f8018356ff9d08eafcMathias Agopian    }
183a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
1840c1eeb3c8ab53954218d3b8f4be08ff21be3e985Mykola Kondratenko    // FileMap memory is never released until application exit.
1850c1eeb3c8ab53954218d3b8f4be08ff21be3e985Mykola Kondratenko    // Release it now as the texture is already loaded and the memory used for
1860c1eeb3c8ab53954218d3b8f4be08ff21be3e985Mykola Kondratenko    // the packed resource can be released.
187688ff4cf0f93d1a886437884f23874e5595d59a3Narayan Kamath    delete frame.map;
1880c1eeb3c8ab53954218d3b8f4be08ff21be3e985Mykola Kondratenko
189a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    // ensure we can call getPixels(). No need to call unlock, since the
190a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    // bitmap will go out of scope when we return from this method.
191a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    bitmap.lockPixels();
192a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
193a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    const int w = bitmap.width();
194a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    const int h = bitmap.height();
195a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    const void* p = bitmap.getPixels();
196a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
197a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    GLint crop[4] = { 0, h, w, -h };
198a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    int tw = 1 << (31 - __builtin_clz(w));
199a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    int th = 1 << (31 - __builtin_clz(h));
200a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    if (tw < w) tw <<= 1;
201a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    if (th < h) th <<= 1;
202a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
20342a1d08df7d417fd4e67eabc91ff05ee77fd9995Mike Reed    switch (bitmap.colorType()) {
20442a1d08df7d417fd4e67eabc91ff05ee77fd9995Mike Reed        case kN32_SkColorType:
205a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian            if (tw != w || th != h) {
206a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tw, th, 0, GL_RGBA,
207a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                        GL_UNSIGNED_BYTE, 0);
208a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                glTexSubImage2D(GL_TEXTURE_2D, 0,
209a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                        0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, p);
210a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian            } else {
211a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tw, th, 0, GL_RGBA,
212a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                        GL_UNSIGNED_BYTE, p);
213a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian            }
214a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian            break;
215a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
21642a1d08df7d417fd4e67eabc91ff05ee77fd9995Mike Reed        case kRGB_565_SkColorType:
217a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian            if (tw != w || th != h) {
218a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tw, th, 0, GL_RGB,
219a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                        GL_UNSIGNED_SHORT_5_6_5, 0);
220a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                glTexSubImage2D(GL_TEXTURE_2D, 0,
221a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                        0, 0, w, h, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, p);
222a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian            } else {
223a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tw, th, 0, GL_RGB,
224a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                        GL_UNSIGNED_SHORT_5_6_5, p);
225a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian            }
226a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian            break;
227a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian        default:
228a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian            break;
229a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    }
230a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
231a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
232a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
233a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    return NO_ERROR;
234a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian}
235a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatus_t BootAnimation::readyToRun() {
2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mAssets.addDefaultAssets();
2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2390b722fe9ce98d97dbcb6fefd170b85ab7037e528Jeff Brown    sp<IBinder> dtoken(SurfaceComposerClient::getBuiltInDisplay(
2400b722fe9ce98d97dbcb6fefd170b85ab7037e528Jeff Brown            ISurfaceComposer::eDisplayIdMain));
2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    DisplayInfo dinfo;
2420b722fe9ce98d97dbcb6fefd170b85ab7037e528Jeff Brown    status_t status = SurfaceComposerClient::getDisplayInfo(dtoken, &dinfo);
2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (status)
2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return -1;
2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // create the native surface
2470b722fe9ce98d97dbcb6fefd170b85ab7037e528Jeff Brown    sp<SurfaceControl> control = session()->createSurface(String8("BootAnimation"),
2480b722fe9ce98d97dbcb6fefd170b85ab7037e528Jeff Brown            dinfo.w, dinfo.h, PIXEL_FORMAT_RGB_565);
249439863f3b3e725b5de1cba4940a21900369961c0Mathias Agopian
250439863f3b3e725b5de1cba4940a21900369961c0Mathias Agopian    SurfaceComposerClient::openGlobalTransaction();
25117f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian    control->setLayer(0x40000000);
252439863f3b3e725b5de1cba4940a21900369961c0Mathias Agopian    SurfaceComposerClient::closeGlobalTransaction();
2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
25417f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian    sp<Surface> s = control->getSurface();
25517f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian
2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // initialize opengl and egl
257738b9a45399485893fa9541fae19c47e01bc4af4Mathias Agopian    const EGLint attribs[] = {
2581b253b702a356619ae3c5e68ee92062b5305c5d7Mathias Agopian            EGL_RED_SIZE,   8,
2591b253b702a356619ae3c5e68ee92062b5305c5d7Mathias Agopian            EGL_GREEN_SIZE, 8,
2601b253b702a356619ae3c5e68ee92062b5305c5d7Mathias Agopian            EGL_BLUE_SIZE,  8,
261a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian            EGL_DEPTH_SIZE, 0,
262a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian            EGL_NONE
263738b9a45399485893fa9541fae19c47e01bc4af4Mathias Agopian    };
264cfedceb8c180a2e176154d461659e0c3569dc931Andreas Gampe    EGLint w, h;
2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    EGLint numConfigs;
2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    EGLConfig config;
2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    EGLSurface surface;
2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    EGLContext context;
269627e7b50be41e4fdee758a1bfad3a55de56b4e27Mathias Agopian
2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
271627e7b50be41e4fdee758a1bfad3a55de56b4e27Mathias Agopian
272627e7b50be41e4fdee758a1bfad3a55de56b4e27Mathias Agopian    eglInitialize(display, 0, 0);
2731b253b702a356619ae3c5e68ee92062b5305c5d7Mathias Agopian    eglChooseConfig(display, attribs, &config, 1, &numConfigs);
2741473f46cbc82aa6f0ba744cc896a36923823d55bMathias Agopian    surface = eglCreateWindowSurface(display, config, s.get(), NULL);
2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    context = eglCreateContext(display, config, NULL, NULL);
2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    eglQuerySurface(display, surface, EGL_WIDTH, &w);
2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    eglQuerySurface(display, surface, EGL_HEIGHT, &h);
278a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
279abac01052c1c40f8582fe9f010c2efe6013e25c6Mathias Agopian    if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE)
280abac01052c1c40f8582fe9f010c2efe6013e25c6Mathias Agopian        return NO_INIT;
281a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mDisplay = display;
2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mContext = context;
2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mSurface = surface;
2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mWidth = w;
2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mHeight = h;
28717f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian    mFlingerSurfaceControl = control;
2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mFlingerSurface = s;
2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
290c367d48c55e5a3fa0df14fd62889e4bb6b63cb01Elliott Hughes    // If the device has encryption turned on or is in process
291bd9a08d318f94a3d0b2f8f9d7b16b10736d80c5cJason parks    // of being encrypted we show the encrypted boot animation.
292bd9a08d318f94a3d0b2f8f9d7b16b10736d80c5cJason parks    char decrypt[PROPERTY_VALUE_MAX];
293bd9a08d318f94a3d0b2f8f9d7b16b10736d80c5cJason parks    property_get("vold.decrypt", decrypt, "");
294bd9a08d318f94a3d0b2f8f9d7b16b10736d80c5cJason parks
295bd9a08d318f94a3d0b2f8f9d7b16b10736d80c5cJason parks    bool encryptedAnimation = atoi(decrypt) != 0 || !strcmp("trigger_restart_min_framework", decrypt);
296bd9a08d318f94a3d0b2f8f9d7b16b10736d80c5cJason parks
29739218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    if (encryptedAnimation && (access(SYSTEM_ENCRYPTED_BOOTANIMATION_FILE, R_OK) == 0)) {
29839218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy        mZipFileName = SYSTEM_ENCRYPTED_BOOTANIMATION_FILE;
29939218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    }
30039218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    else if (access(OEM_BOOTANIMATION_FILE, R_OK) == 0) {
30139218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy        mZipFileName = OEM_BOOTANIMATION_FILE;
30239218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    }
30339218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    else if (access(SYSTEM_BOOTANIMATION_FILE, R_OK) == 0) {
30439218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy        mZipFileName = SYSTEM_BOOTANIMATION_FILE;
305bd9a08d318f94a3d0b2f8f9d7b16b10736d80c5cJason parks    }
3069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return NO_ERROR;
3079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
3089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
309a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopianbool BootAnimation::threadLoop()
310a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian{
311a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    bool r;
312afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath    // We have no bootanimation file, so we use the stock android logo
313afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath    // animation.
31439218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    if (mZipFileName.isEmpty()) {
315a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian        r = android();
316a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    } else {
317a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian        r = movie();
318a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    }
319a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    eglDestroyContext(mDisplay, mContext);
3229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    eglDestroySurface(mDisplay, mSurface);
3236cf0db228ca275dfcda57d79c55e5fa306809632Mathias Agopian    mFlingerSurface.clear();
32417f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian    mFlingerSurfaceControl.clear();
325627e7b50be41e4fdee758a1bfad3a55de56b4e27Mathias Agopian    eglTerminate(mDisplay);
326627e7b50be41e4fdee758a1bfad3a55de56b4e27Mathias Agopian    IPCThreadState::self()->stopProcess();
3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return r;
3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
330a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopianbool BootAnimation::android()
331a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian{
332b2cf954cb47a73065aa4b7fed753877615614f41Mathias Agopian    initTexture(&mAndroid[0], mAssets, "images/android-logo-mask.png");
333b2cf954cb47a73065aa4b7fed753877615614f41Mathias Agopian    initTexture(&mAndroid[1], mAssets, "images/android-logo-shine.png");
3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // clear screen
336a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    glShadeModel(GL_FLAT);
337b2cf954cb47a73065aa4b7fed753877615614f41Mathias Agopian    glDisable(GL_DITHER);
338b2cf954cb47a73065aa4b7fed753877615614f41Mathias Agopian    glDisable(GL_SCISSOR_TEST);
33959f19e48c1c043bb9debdc35d166e397e2125d33Mathias Agopian    glClearColor(0,0,0,1);
3409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    glClear(GL_COLOR_BUFFER_BIT);
3419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    eglSwapBuffers(mDisplay, mSurface);
3429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
343a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    glEnable(GL_TEXTURE_2D);
344a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
345a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
346b2cf954cb47a73065aa4b7fed753877615614f41Mathias Agopian    const GLint xc = (mWidth  - mAndroid[0].w) / 2;
347b2cf954cb47a73065aa4b7fed753877615614f41Mathias Agopian    const GLint yc = (mHeight - mAndroid[0].h) / 2;
348b2cf954cb47a73065aa4b7fed753877615614f41Mathias Agopian    const Rect updateRect(xc, yc, xc + mAndroid[0].w, yc + mAndroid[0].h);
3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    glScissor(updateRect.left, mHeight - updateRect.bottom, updateRect.width(),
3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            updateRect.height());
3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
353b2cf954cb47a73065aa4b7fed753877615614f41Mathias Agopian    // Blend state
354b2cf954cb47a73065aa4b7fed753877615614f41Mathias Agopian    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
355b2cf954cb47a73065aa4b7fed753877615614f41Mathias Agopian    glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
356b2cf954cb47a73065aa4b7fed753877615614f41Mathias Agopian
3579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    const nsecs_t startTime = systemTime();
3589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    do {
3591379665abdb8330caf813fb77902914d1545bcd9Mathias Agopian        nsecs_t now = systemTime();
3601379665abdb8330caf813fb77902914d1545bcd9Mathias Agopian        double time = now - startTime;
361b2cf954cb47a73065aa4b7fed753877615614f41Mathias Agopian        float t = 4.0f * float(time / us2ns(16667)) / mAndroid[1].w;
362b2cf954cb47a73065aa4b7fed753877615614f41Mathias Agopian        GLint offset = (1 - (t - floorf(t))) * mAndroid[1].w;
363b2cf954cb47a73065aa4b7fed753877615614f41Mathias Agopian        GLint x = xc - offset;
3649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3658166864e42bc20c1544b2028e8dd65b90f29a0eaMathias Agopian        glDisable(GL_SCISSOR_TEST);
3668166864e42bc20c1544b2028e8dd65b90f29a0eaMathias Agopian        glClear(GL_COLOR_BUFFER_BIT);
3678166864e42bc20c1544b2028e8dd65b90f29a0eaMathias Agopian
3688166864e42bc20c1544b2028e8dd65b90f29a0eaMathias Agopian        glEnable(GL_SCISSOR_TEST);
3699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        glDisable(GL_BLEND);
3709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        glBindTexture(GL_TEXTURE_2D, mAndroid[1].name);
371b2cf954cb47a73065aa4b7fed753877615614f41Mathias Agopian        glDrawTexiOES(x,                 yc, 0, mAndroid[1].w, mAndroid[1].h);
372b2cf954cb47a73065aa4b7fed753877615614f41Mathias Agopian        glDrawTexiOES(x + mAndroid[1].w, yc, 0, mAndroid[1].w, mAndroid[1].h);
3739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
374b2cf954cb47a73065aa4b7fed753877615614f41Mathias Agopian        glEnable(GL_BLEND);
375b2cf954cb47a73065aa4b7fed753877615614f41Mathias Agopian        glBindTexture(GL_TEXTURE_2D, mAndroid[0].name);
376b2cf954cb47a73065aa4b7fed753877615614f41Mathias Agopian        glDrawTexiOES(xc, yc, 0, mAndroid[0].w, mAndroid[0].h);
3779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
378627e7b50be41e4fdee758a1bfad3a55de56b4e27Mathias Agopian        EGLBoolean res = eglSwapBuffers(mDisplay, mSurface);
379627e7b50be41e4fdee758a1bfad3a55de56b4e27Mathias Agopian        if (res == EGL_FALSE)
380627e7b50be41e4fdee758a1bfad3a55de56b4e27Mathias Agopian            break;
381627e7b50be41e4fdee758a1bfad3a55de56b4e27Mathias Agopian
3821379665abdb8330caf813fb77902914d1545bcd9Mathias Agopian        // 12fps: don't animate too fast to preserve CPU
3831379665abdb8330caf813fb77902914d1545bcd9Mathias Agopian        const nsecs_t sleepTime = 83333 - ns2us(systemTime() - now);
3841379665abdb8330caf813fb77902914d1545bcd9Mathias Agopian        if (sleepTime > 0)
385a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian            usleep(sleepTime);
386d3782b26b2026e60a8e0d4b967a156369f2a46f8Kevin Hester
387d3782b26b2026e60a8e0d4b967a156369f2a46f8Kevin Hester        checkExit();
3889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    } while (!exitPending());
3899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    glDeleteTextures(1, &mAndroid[0].name);
3919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    glDeleteTextures(1, &mAndroid[1].name);
3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return false;
3939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
395a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
396d3782b26b2026e60a8e0d4b967a156369f2a46f8Kevin Hestervoid BootAnimation::checkExit() {
397d3782b26b2026e60a8e0d4b967a156369f2a46f8Kevin Hester    // Allow surface flinger to gracefully request shutdown
398d3782b26b2026e60a8e0d4b967a156369f2a46f8Kevin Hester    char value[PROPERTY_VALUE_MAX];
399d3782b26b2026e60a8e0d4b967a156369f2a46f8Kevin Hester    property_get(EXIT_PROP_NAME, value, "0");
400d3782b26b2026e60a8e0d4b967a156369f2a46f8Kevin Hester    int exitnow = atoi(value);
401d3782b26b2026e60a8e0d4b967a156369f2a46f8Kevin Hester    if (exitnow) {
402d3782b26b2026e60a8e0d4b967a156369f2a46f8Kevin Hester        requestExit();
403ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood        if (mAudioPlayer != NULL) {
404ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood            mAudioPlayer->requestExit();
405ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood        }
406d3782b26b2026e60a8e0d4b967a156369f2a46f8Kevin Hester    }
407d3782b26b2026e60a8e0d4b967a156369f2a46f8Kevin Hester}
408d3782b26b2026e60a8e0d4b967a156369f2a46f8Kevin Hester
409083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall// Parse a color represented as an HTML-style 'RRGGBB' string: each pair of
410083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall// characters in str is a hex number in [0, 255], which are converted to
411083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall// floating point values in the range [0.0, 1.0] and placed in the
412083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall// corresponding elements of color.
413083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall//
414083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall// If the input string isn't valid, parseColor returns false and color is
415083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall// left unchanged.
416083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hallstatic bool parseColor(const char str[7], float color[3]) {
417083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall    float tmpColor[3];
418083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall    for (int i = 0; i < 3; i++) {
419083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall        int val = 0;
420083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall        for (int j = 0; j < 2; j++) {
421083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall            val *= 16;
422083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall            char c = str[2*i + j];
423083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall            if      (c >= '0' && c <= '9') val += c - '0';
424083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall            else if (c >= 'A' && c <= 'F') val += (c - 'A') + 10;
425083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall            else if (c >= 'a' && c <= 'f') val += (c - 'a') + 10;
426083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall            else                           return false;
427083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall        }
428083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall        tmpColor[i] = static_cast<float>(val) / 255.0f;
429083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall    }
430083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall    memcpy(color, tmpColor, sizeof(tmpColor));
431083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall    return true;
432083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall}
433083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall
43439218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy
43539218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyystatic bool readFile(ZipFileRO* zip, const char* name, String8& outString)
436a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian{
43739218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    ZipEntryRO entry = zip->findEntryByName(name);
438ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood    ALOGE_IF(!entry, "couldn't find %s", name);
439ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood    if (!entry) {
440afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath        return false;
441afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath    }
442a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
44339218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    FileMap* entryMap = zip->createEntryFileMap(entry);
44439218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    zip->releaseEntry(entry);
445ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood    ALOGE_IF(!entryMap, "entryMap is null");
446ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood    if (!entryMap) {
447a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian        return false;
448a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    }
449a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
450ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood    outString.setTo((char const*)entryMap->getDataPtr(), entryMap->getDataLength());
451688ff4cf0f93d1a886437884f23874e5595d59a3Narayan Kamath    delete entryMap;
452ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood    return true;
453ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood}
454ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood
455a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi// The time glyphs are stored in a single image of height 64 pixels. Each digit is 40 pixels wide,
456a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi// and the colon character is half that at 20 pixels. The glyph order is '0123456789:'.
457a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi// We render 24 hour time.
458a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchivoid BootAnimation::drawTime(const Texture& clockTex, const int yPos) {
459a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi    static constexpr char TIME_FORMAT[] = "%H:%M";
460a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi    static constexpr int TIME_LENGTH = sizeof(TIME_FORMAT);
461a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi
462a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi    static constexpr int DIGIT_HEIGHT = 64;
463a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi    static constexpr int DIGIT_WIDTH = 40;
464a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi    static constexpr int COLON_WIDTH = DIGIT_WIDTH / 2;
465a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi    static constexpr int TIME_WIDTH = (DIGIT_WIDTH * 4) + COLON_WIDTH;
466a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi
467a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi    if (clockTex.h < DIGIT_HEIGHT || clockTex.w < (10 * DIGIT_WIDTH + COLON_WIDTH)) {
468a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi        ALOGE("Clock texture is too small; abandoning boot animation clock");
469a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi        mClockEnabled = false;
470a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi        return;
471a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi    }
472a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi
473a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi    time_t rawtime;
474a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi    time(&rawtime);
475a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi    struct tm* timeInfo = localtime(&rawtime);
476a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi
477a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi    char timeBuff[TIME_LENGTH];
478a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi    size_t length = strftime(timeBuff, TIME_LENGTH, TIME_FORMAT, timeInfo);
479a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi
480a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi    if (length != TIME_LENGTH - 1) {
481a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi        ALOGE("Couldn't format time; abandoning boot animation clock");
482a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi        mClockEnabled = false;
483a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi        return;
484a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi    }
485a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi
486a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi    glEnable(GL_BLEND);  // Allow us to draw on top of the animation
487a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi    glBindTexture(GL_TEXTURE_2D, clockTex.name);
488a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi
489a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi    int xPos = (mWidth - TIME_WIDTH) / 2;
490a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi    int cropRect[4] = { 0, DIGIT_HEIGHT, DIGIT_WIDTH, -DIGIT_HEIGHT };
491a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi
492a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi    for (int i = 0; i < TIME_LENGTH - 1; i++) {
493a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi        char c = timeBuff[i];
494a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi        int width = DIGIT_WIDTH;
495a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi        int pos = c - '0';  // Position in the character list
496a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi        if (pos < 0 || pos > 10) {
497a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi            continue;
498a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi        }
499a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi        if (c == ':') {
500a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi            width = COLON_WIDTH;
501a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi        }
502a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi
503a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi        // Crop the texture to only the pixels in the current glyph
504a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi        int left = pos * DIGIT_WIDTH;
505a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi        cropRect[0] = left;
506a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi        cropRect[2] = width;
507a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi        glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, cropRect);
508a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi
509a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi        glDrawTexiOES(xPos, yPos, 0, width, DIGIT_HEIGHT);
510a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi
511a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi        xPos += width;
512a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi    }
513a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi
514a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi    glDisable(GL_BLEND);  // Return to the animation's default behaviour
515a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi    glBindTexture(GL_TEXTURE_2D, 0);
516a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi}
517a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi
51839218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyybool BootAnimation::parseAnimationDesc(Animation& animation)
519ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood{
520ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood    String8 desString;
521ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood
52239218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    if (!readFile(animation.zip, "desc.txt", desString)) {
523ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood        return false;
524ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood    }
525a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    char const* s = desString.string();
526a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
527ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood    // Create and initialize an AudioPlayer if we have an audio_conf.txt file
528ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood    String8 audioConf;
52939218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    if (readFile(animation.zip, "audio_conf.txt", audioConf)) {
530ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood        mAudioPlayer = new AudioPlayer;
531ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood        if (!mAudioPlayer->init(audioConf.string())) {
532ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood            ALOGE("mAudioPlayer.init failed");
533ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood            mAudioPlayer = NULL;
534ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood        }
535ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood    }
536ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood
537a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    // Parse the description file
538a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    for (;;) {
539a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian        const char* endl = strstr(s, "\n");
540cfedceb8c180a2e176154d461659e0c3569dc931Andreas Gampe        if (endl == NULL) break;
541a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian        String8 line(s, endl - s);
542a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian        const char* l = line.string();
543a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi        int fps = 0;
544a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi        int width = 0;
545a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi        int height = 0;
546a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi        int count = 0;
547a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi        int pause = 0;
548a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi        int clockPosY = -1;
549afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath        char path[ANIM_ENTRY_NAME_MAX];
550083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall        char color[7] = "000000"; // default to black if unspecified
551083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall
552d3782b26b2026e60a8e0d4b967a156369f2a46f8Kevin Hester        char pathType;
553a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian        if (sscanf(l, "%d %d %d", &width, &height, &fps) == 3) {
554083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall            // ALOGD("> w=%d, h=%d, fps=%d", width, height, fps);
555a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian            animation.width = width;
556a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian            animation.height = height;
557a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian            animation.fps = fps;
558a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi        } else if (sscanf(l, " %c %d %d %s #%6s %d",
559a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi                          &pathType, &count, &pause, path, color, &clockPosY) >= 4) {
560a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi            // ALOGD("> type=%c, count=%d, pause=%d, path=%s, color=%s, clockPosY=%d", pathType, count, pause, path, color, clockPosY);
561a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian            Animation::Part part;
562d3782b26b2026e60a8e0d4b967a156369f2a46f8Kevin Hester            part.playUntilComplete = pathType == 'c';
563a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian            part.count = count;
564a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian            part.pause = pause;
565a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian            part.path = path;
566a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi            part.clockPosY = clockPosY;
567ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood            part.audioFile = NULL;
56839218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy            part.animation = NULL;
569083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall            if (!parseColor(color, part.backgroundColor)) {
570083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall                ALOGE("> invalid color '#%s'", color);
571083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall                part.backgroundColor[0] = 0.0f;
572083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall                part.backgroundColor[1] = 0.0f;
573083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall                part.backgroundColor[2] = 0.0f;
574083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall            }
575a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian            animation.parts.add(part);
576a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian        }
57739218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy        else if (strcmp(l, "$SYSTEM") == 0) {
57839218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy            // ALOGD("> SYSTEM");
57939218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy            Animation::Part part;
58039218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy            part.playUntilComplete = false;
58139218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy            part.count = 1;
58239218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy            part.pause = 0;
58339218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy            part.audioFile = NULL;
58439218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy            part.animation = loadAnimation(String8(SYSTEM_BOOTANIMATION_FILE));
58539218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy            if (part.animation != NULL)
58639218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy                animation.parts.add(part);
58739218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy        }
588a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian        s = ++endl;
589a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    }
590a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
59139218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    return true;
59239218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy}
59339218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy
59439218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyybool BootAnimation::preloadZip(Animation& animation)
59539218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy{
596a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    // read all the data structures
597a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    const size_t pcount = animation.parts.size();
598afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath    void *cookie = NULL;
59939218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    ZipFileRO* mZip = animation.zip;
600afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath    if (!mZip->startIteration(&cookie)) {
601afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath        return false;
602afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath    }
603afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath
604afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath    ZipEntryRO entry;
605afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath    char name[ANIM_ENTRY_NAME_MAX];
606afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath    while ((entry = mZip->nextEntry(cookie)) != NULL) {
607afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath        const int foundEntryName = mZip->getEntryFileName(entry, name, ANIM_ENTRY_NAME_MAX);
608afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath        if (foundEntryName > ANIM_ENTRY_NAME_MAX || foundEntryName == -1) {
609afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath            ALOGE("Error fetching entry file name");
610afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath            continue;
611afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath        }
612afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath
613afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath        const String8 entryName(name);
614afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath        const String8 path(entryName.getPathDir());
615afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath        const String8 leaf(entryName.getPathLeaf());
616afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath        if (leaf.size() > 0) {
617afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath            for (size_t j=0 ; j<pcount ; j++) {
618afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath                if (path == animation.parts[j].path) {
6194600dd053dbdbd4b95f3b11057a1cc55b99f9c77Narayan Kamath                    uint16_t method;
620afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath                    // supports only stored png files
621afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath                    if (mZip->getEntryInfo(entry, &method, NULL, NULL, NULL, NULL, NULL)) {
622afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath                        if (method == ZipFileRO::kCompressStored) {
623afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath                            FileMap* map = mZip->createEntryFileMap(entry);
624afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath                            if (map) {
625afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath                                Animation::Part& part(animation.parts.editItemAt(j));
626ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood                                if (leaf == "audio.wav") {
627ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood                                    // a part may have at most one audio file
628ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood                                    part.audioFile = map;
629ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood                                } else {
630ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood                                    Animation::Frame frame;
631ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood                                    frame.name = leaf;
632ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood                                    frame.map = map;
633ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood                                    part.frames.add(frame);
634ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood                                }
635a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                            }
636a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                        }
637a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                    }
638a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                }
639a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian            }
640a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian        }
641a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    }
642a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
643afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath    mZip->endIteration(cookie);
644afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath
64539218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    return true;
64639218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy}
64739218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy
64839218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyybool BootAnimation::movie()
64939218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy{
65039218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    Animation* animation = loadAnimation(mZipFileName);
65139218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    if (animation == NULL)
65239218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy        return false;
65339218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy
6549748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    bool anyPartHasClock = false;
6559748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    for (size_t i=0; i < animation->parts.size(); i++) {
6569748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        if(animation->parts[i].clockPosY >= 0) {
6579748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi            anyPartHasClock = true;
6589748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi            break;
6599748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        }
6609748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    }
6619748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    if (!anyPartHasClock) {
6629748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        mClockEnabled = false;
6639748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    }
6649748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi
665a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi    // Blend required to draw time on top of animation frames.
666a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
667a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    glShadeModel(GL_FLAT);
668a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    glDisable(GL_DITHER);
669a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    glDisable(GL_SCISSOR_TEST);
670a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    glDisable(GL_BLEND);
671a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
672a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    glBindTexture(GL_TEXTURE_2D, 0);
673a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    glEnable(GL_TEXTURE_2D);
674a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
675a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
676a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
677a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
678a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
679a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
680a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi    bool clockTextureInitialized = false;
681a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi    if (mClockEnabled) {
682a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi        clockTextureInitialized = (initTexture(&mClock, mAssets, "images/clock64.png") == NO_ERROR);
683a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi        mClockEnabled = clockTextureInitialized;
684a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi    }
685a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi
6869748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    if (mClockEnabled && !updateIsTimeAccurate()) {
6879748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        mTimeCheckThread = new TimeCheckThread(this);
6889748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        mTimeCheckThread->run("BootAnimation::TimeCheckThread", PRIORITY_NORMAL);
6899748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    }
6909748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi
69139218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    playAnimation(*animation);
6929748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi
6939748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    if (mTimeCheckThread != NULL) {
6949748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        mTimeCheckThread->requestExit();
6959748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        mTimeCheckThread = NULL;
6969748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    }
6979748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi
69839218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    releaseAnimation(animation);
69939218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy
700815e51d76cc284f3ca59534d9f9372d3dd50f574Andriy Naborskyy    if (clockTextureInitialized) {
701815e51d76cc284f3ca59534d9f9372d3dd50f574Andriy Naborskyy        glDeleteTextures(1, &mClock.name);
702815e51d76cc284f3ca59534d9f9372d3dd50f574Andriy Naborskyy    }
703815e51d76cc284f3ca59534d9f9372d3dd50f574Andriy Naborskyy
70439218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    return false;
70539218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy}
70639218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy
70739218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyybool BootAnimation::playAnimation(const Animation& animation)
70839218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy{
70939218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    const size_t pcount = animation.parts.size();
710a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    const int xc = (mWidth - animation.width) / 2;
711a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    const int yc = ((mHeight - animation.height) / 2);
712a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    nsecs_t frameDuration = s2ns(1) / animation.fps;
713a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
7149f3020db15e50d07ee1ace42e47d90b076f2ce54Mathias Agopian    Region clearReg(Rect(mWidth, mHeight));
7159f3020db15e50d07ee1ace42e47d90b076f2ce54Mathias Agopian    clearReg.subtractSelf(Rect(xc, yc, xc+animation.width, yc+animation.height));
7169f3020db15e50d07ee1ace42e47d90b076f2ce54Mathias Agopian
717afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath    for (size_t i=0 ; i<pcount ; i++) {
718a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian        const Animation::Part& part(animation.parts[i]);
719a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian        const size_t fcount = part.frames.size();
720a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian        glBindTexture(GL_TEXTURE_2D, 0);
721a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
72239218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy        // Handle animation package
72339218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy        if (part.animation != NULL) {
72439218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy            playAnimation(*part.animation);
72539218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy            if (exitPending())
72639218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy                break;
72739218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy            continue; //to next part
72839218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy        }
72939218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy
730a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian        for (int r=0 ; !part.count || r<part.count ; r++) {
731d3782b26b2026e60a8e0d4b967a156369f2a46f8Kevin Hester            // Exit any non playuntil complete parts immediately
732d3782b26b2026e60a8e0d4b967a156369f2a46f8Kevin Hester            if(exitPending() && !part.playUntilComplete)
733d3782b26b2026e60a8e0d4b967a156369f2a46f8Kevin Hester                break;
734d3782b26b2026e60a8e0d4b967a156369f2a46f8Kevin Hester
735ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood            // only play audio file the first time we animate the part
736ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood            if (r == 0 && mAudioPlayer != NULL && part.audioFile) {
737ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood                mAudioPlayer->playFile(part.audioFile);
738ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood            }
739ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood
740083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall            glClearColor(
741083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall                    part.backgroundColor[0],
742083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall                    part.backgroundColor[1],
743083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall                    part.backgroundColor[2],
744083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall                    1.0f);
745083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall
746afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath            for (size_t j=0 ; j<fcount && (!exitPending() || part.playUntilComplete) ; j++) {
747a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                const Animation::Frame& frame(part.frames[j]);
748db7dd2af93ae96e5749cfbe978c2695049d9d782Mathias Agopian                nsecs_t lastFrame = systemTime();
749a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
750a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                if (r > 0) {
751a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                    glBindTexture(GL_TEXTURE_2D, frame.tid);
752a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                } else {
753a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                    if (part.count != 1) {
754a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                        glGenTextures(1, &frame.tid);
755a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                        glBindTexture(GL_TEXTURE_2D, frame.tid);
756a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                        glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
757a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                        glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
758a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                    }
7590c1eeb3c8ab53954218d3b8f4be08ff21be3e985Mykola Kondratenko                    initTexture(frame);
760a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                }
761a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
7629f3020db15e50d07ee1ace42e47d90b076f2ce54Mathias Agopian                if (!clearReg.isEmpty()) {
7639f3020db15e50d07ee1ace42e47d90b076f2ce54Mathias Agopian                    Region::const_iterator head(clearReg.begin());
7649f3020db15e50d07ee1ace42e47d90b076f2ce54Mathias Agopian                    Region::const_iterator tail(clearReg.end());
7659f3020db15e50d07ee1ace42e47d90b076f2ce54Mathias Agopian                    glEnable(GL_SCISSOR_TEST);
7669f3020db15e50d07ee1ace42e47d90b076f2ce54Mathias Agopian                    while (head != tail) {
767cfedceb8c180a2e176154d461659e0c3569dc931Andreas Gampe                        const Rect& r2(*head++);
768cfedceb8c180a2e176154d461659e0c3569dc931Andreas Gampe                        glScissor(r2.left, mHeight - r2.bottom,
769cfedceb8c180a2e176154d461659e0c3569dc931Andreas Gampe                                r2.width(), r2.height());
7709f3020db15e50d07ee1ace42e47d90b076f2ce54Mathias Agopian                        glClear(GL_COLOR_BUFFER_BIT);
7719f3020db15e50d07ee1ace42e47d90b076f2ce54Mathias Agopian                    }
7729f3020db15e50d07ee1ace42e47d90b076f2ce54Mathias Agopian                    glDisable(GL_SCISSOR_TEST);
7739f3020db15e50d07ee1ace42e47d90b076f2ce54Mathias Agopian                }
774d13d504e4b7548f0ce4f9c4f0eee5c1ac2ce6794Chris Elliott                // specify the y center as ceiling((mHeight - animation.height) / 2)
775d13d504e4b7548f0ce4f9c4f0eee5c1ac2ce6794Chris Elliott                // which is equivalent to mHeight - (yc + animation.height)
776d13d504e4b7548f0ce4f9c4f0eee5c1ac2ce6794Chris Elliott                glDrawTexiOES(xc, mHeight - (yc + animation.height),
777d13d504e4b7548f0ce4f9c4f0eee5c1ac2ce6794Chris Elliott                              0, animation.width, animation.height);
7789748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi                if (mClockEnabled && mTimeIsAccurate && part.clockPosY >= 0) {
779a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi                    drawTime(mClock, part.clockPosY);
780a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi                }
781a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi
782a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                eglSwapBuffers(mDisplay, mSurface);
783a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
784a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                nsecs_t now = systemTime();
785a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                nsecs_t delay = frameDuration - (now - lastFrame);
786db7dd2af93ae96e5749cfbe978c2695049d9d782Mathias Agopian                //ALOGD("%lld, %lld", ns2ms(now - lastFrame), ns2ms(delay));
787a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                lastFrame = now;
788db7dd2af93ae96e5749cfbe978c2695049d9d782Mathias Agopian
789db7dd2af93ae96e5749cfbe978c2695049d9d782Mathias Agopian                if (delay > 0) {
790db7dd2af93ae96e5749cfbe978c2695049d9d782Mathias Agopian                    struct timespec spec;
791db7dd2af93ae96e5749cfbe978c2695049d9d782Mathias Agopian                    spec.tv_sec  = (now + delay) / 1000000000;
792db7dd2af93ae96e5749cfbe978c2695049d9d782Mathias Agopian                    spec.tv_nsec = (now + delay) % 1000000000;
793db7dd2af93ae96e5749cfbe978c2695049d9d782Mathias Agopian                    int err;
794db7dd2af93ae96e5749cfbe978c2695049d9d782Mathias Agopian                    do {
795db7dd2af93ae96e5749cfbe978c2695049d9d782Mathias Agopian                        err = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &spec, NULL);
796db7dd2af93ae96e5749cfbe978c2695049d9d782Mathias Agopian                    } while (err<0 && errno == EINTR);
797db7dd2af93ae96e5749cfbe978c2695049d9d782Mathias Agopian                }
798d3782b26b2026e60a8e0d4b967a156369f2a46f8Kevin Hester
799d3782b26b2026e60a8e0d4b967a156369f2a46f8Kevin Hester                checkExit();
800a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian            }
801d3782b26b2026e60a8e0d4b967a156369f2a46f8Kevin Hester
802a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian            usleep(part.pause * ns2us(frameDuration));
803d3782b26b2026e60a8e0d4b967a156369f2a46f8Kevin Hester
804d3782b26b2026e60a8e0d4b967a156369f2a46f8Kevin Hester            // For infinite parts, we've now played them at least once, so perhaps exit
805d3782b26b2026e60a8e0d4b967a156369f2a46f8Kevin Hester            if(exitPending() && !part.count)
806d3782b26b2026e60a8e0d4b967a156369f2a46f8Kevin Hester                break;
807a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian        }
808a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
809a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian        // free the textures for this part
810a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian        if (part.count != 1) {
811afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath            for (size_t j=0 ; j<fcount ; j++) {
812a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                const Animation::Frame& frame(part.frames[j]);
813a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                glDeleteTextures(1, &frame.tid);
814a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian            }
815a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian        }
816a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    }
81739218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    return true;
81839218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy}
819a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
82039218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyyvoid BootAnimation::releaseAnimation(Animation* animation) const
82139218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy{
82239218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    for (Vector<Animation::Part>::iterator it = animation->parts.begin(),
82339218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy         e = animation->parts.end(); it != e; ++it) {
82439218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy        if (it->animation)
82539218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy            releaseAnimation(it->animation);
82639218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    }
82739218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    if (animation->zip)
82839218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy        delete animation->zip;
82939218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    delete animation;
830a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian}
831a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
83239218ba26d5bb8646f04273f2c3731598721c1daAndriy NaborskyyBootAnimation::Animation* BootAnimation::loadAnimation(const String8& fn)
83339218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy{
83439218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    if (mLoadedFiles.indexOf(fn) >= 0) {
83539218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy        ALOGE("File \"%s\" is already loaded. Cyclic ref is not allowed",
83639218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy            fn.string());
83739218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy        return NULL;
83839218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    }
83939218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    ZipFileRO *zip = ZipFileRO::open(fn);
84039218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    if (zip == NULL) {
84139218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy        ALOGE("Failed to open animation zip \"%s\": %s",
84239218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy            fn.string(), strerror(errno));
84339218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy        return NULL;
844a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi    }
845a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi
84639218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    Animation *animation =  new Animation;
84739218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    animation->fileName = fn;
84839218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    animation->zip = zip;
84939218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    mLoadedFiles.add(animation->fileName);
85039218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy
85139218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    parseAnimationDesc(*animation);
85239218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    preloadZip(*animation);
853a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
85439218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    mLoadedFiles.remove(fn);
85539218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    return animation;
85639218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy}
8579748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi
8589748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchibool BootAnimation::updateIsTimeAccurate() {
8599748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    static constexpr long long MAX_TIME_IN_PAST =   60000LL * 60LL * 24LL * 30LL;  // 30 days
8609748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    static constexpr long long MAX_TIME_IN_FUTURE = 60000LL * 90LL;  // 90 minutes
8619748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi
8629748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    if (mTimeIsAccurate) {
8639748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        return true;
8649748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    }
8659748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi
8669748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    struct stat statResult;
8679748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    if(stat(ACCURATE_TIME_FLAG_FILE_PATH, &statResult) == 0) {
8689748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        mTimeIsAccurate = true;
8699748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        return true;
8709748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    }
8719748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi
8729748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    FILE* file = fopen(LAST_TIME_CHANGED_FILE_PATH, "r");
8739748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    if (file != NULL) {
8749748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi      long long lastChangedTime = 0;
8759748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi      fscanf(file, "%lld", &lastChangedTime);
8769748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi      fclose(file);
8779748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi      if (lastChangedTime > 0) {
8789748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        struct timespec now;
8799748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        clock_gettime(CLOCK_REALTIME, &now);
8809748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        // Match the Java timestamp format
8819748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        long long rtcNow = (now.tv_sec * 1000LL) + (now.tv_nsec / 1000000LL);
8829748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        if (lastChangedTime > rtcNow - MAX_TIME_IN_PAST
8839748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi            && lastChangedTime < rtcNow + MAX_TIME_IN_FUTURE) {
8849748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi            mTimeIsAccurate = true;
8859748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        }
8869748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi      }
8879748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    }
8889748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi
8899748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    return mTimeIsAccurate;
8909748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi}
8919748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi
8929748086fe267e21d243a49df1775905094a28dd9Damien BargiacchiBootAnimation::TimeCheckThread::TimeCheckThread(BootAnimation* bootAnimation) : Thread(false),
8939748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    mInotifyFd(-1), mSystemWd(-1), mTimeWd(-1), mBootAnimation(bootAnimation) {}
8949748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi
8959748086fe267e21d243a49df1775905094a28dd9Damien BargiacchiBootAnimation::TimeCheckThread::~TimeCheckThread() {
8969748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    // mInotifyFd may be -1 but that's ok since we're not at risk of attempting to close a valid FD.
8979748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    close(mInotifyFd);
8989748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi}
8999748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi
9009748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchibool BootAnimation::TimeCheckThread::threadLoop() {
9019748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    bool shouldLoop = doThreadLoop() && !mBootAnimation->mTimeIsAccurate
9029748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        && mBootAnimation->mClockEnabled;
9039748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    if (!shouldLoop) {
9049748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        close(mInotifyFd);
9059748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        mInotifyFd = -1;
9069748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    }
9079748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    return shouldLoop;
9089748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi}
9099748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi
9109748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchibool BootAnimation::TimeCheckThread::doThreadLoop() {
9119748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    static constexpr int BUFF_LEN (10 * (sizeof(struct inotify_event) + NAME_MAX + 1));
9129748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi
9139748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    // Poll instead of doing a blocking read so the Thread can exit if requested.
9149748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    struct pollfd pfd = { mInotifyFd, POLLIN, 0 };
9159748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    ssize_t pollResult = poll(&pfd, 1, 1000);
9169748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi
9179748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    if (pollResult == 0) {
9189748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        return true;
9199748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    } else if (pollResult < 0) {
9209748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        ALOGE("Could not poll inotify events");
9219748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        return false;
9229748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    }
9239748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi
9249748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    char buff[BUFF_LEN] __attribute__ ((aligned(__alignof__(struct inotify_event))));;
9259748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    ssize_t length = read(mInotifyFd, buff, BUFF_LEN);
9269748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    if (length == 0) {
9279748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        return true;
9289748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    } else if (length < 0) {
9299748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        ALOGE("Could not read inotify events");
9309748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        return false;
9319748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    }
9329748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi
9339748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    const struct inotify_event *event;
9349748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    for (char* ptr = buff; ptr < buff + length; ptr += sizeof(struct inotify_event) + event->len) {
9359748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        event = (const struct inotify_event *) ptr;
9369748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        if (event->wd == mSystemWd && strcmp(SYSTEM_TIME_DIR_NAME, event->name) == 0) {
9379748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi            addTimeDirWatch();
9389748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        } else if (event->wd == mTimeWd && (strcmp(LAST_TIME_CHANGED_FILE_NAME, event->name) == 0
9399748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi                || strcmp(ACCURATE_TIME_FLAG_FILE_NAME, event->name) == 0)) {
9409748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi            return !mBootAnimation->updateIsTimeAccurate();
9419748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        }
9429748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    }
9439748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi
9449748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    return true;
9459748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi}
9469748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi
9479748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchivoid BootAnimation::TimeCheckThread::addTimeDirWatch() {
9489748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        mTimeWd = inotify_add_watch(mInotifyFd, SYSTEM_TIME_DIR_PATH,
9499748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi                IN_CLOSE_WRITE | IN_MOVED_TO | IN_ATTRIB);
9509748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        if (mTimeWd > 0) {
9519748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi            // No need to watch for the time directory to be created if it already exists
9529748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi            inotify_rm_watch(mInotifyFd, mSystemWd);
9539748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi            mSystemWd = -1;
9549748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        }
9559748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi}
9569748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi
9579748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchistatus_t BootAnimation::TimeCheckThread::readyToRun() {
9589748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    mInotifyFd = inotify_init();
9599748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    if (mInotifyFd < 0) {
9609748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        ALOGE("Could not initialize inotify fd");
9619748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        return NO_INIT;
9629748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    }
9639748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi
9649748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    mSystemWd = inotify_add_watch(mInotifyFd, SYSTEM_DATA_DIR_PATH, IN_CREATE | IN_ATTRIB);
9659748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    if (mSystemWd < 0) {
9669748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        close(mInotifyFd);
9679748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        mInotifyFd = -1;
9689748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        ALOGE("Could not add watch for %s", SYSTEM_DATA_DIR_PATH);
9699748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        return NO_INIT;
9709748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    }
9719748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi
9729748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    addTimeDirWatch();
9739748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi
9749748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    if (mBootAnimation->updateIsTimeAccurate()) {
9759748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        close(mInotifyFd);
9769748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        mInotifyFd = -1;
9779748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        return ALREADY_EXISTS;
9789748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    }
9799748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi
9809748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    return NO_ERROR;
9819748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi}
9829748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi
9839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// ---------------------------------------------------------------------------
9849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
9869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project; // namespace android
987