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>
21a90c54c90e1cb668cd74f218370f868763bbd009Wei Wang#include <inttypes.h>
229748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi#include <sys/inotify.h>
239748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi#include <sys/poll.h>
249748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi#include <sys/stat.h>
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <sys/types.h>
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <math.h>
279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <fcntl.h>
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <utils/misc.h>
29b4d5a72691846bce5779cc3db056f09a5031d7ccMathias Agopian#include <signal.h>
30bb94f3107ea567ddf67bed4617c3bcbd602538dfElliott Hughes#include <time.h>
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
32bd9a08d318f94a3d0b2f8f9d7b16b10736d80c5cJason parks#include <cutils/properties.h>
33bd9a08d318f94a3d0b2f8f9d7b16b10736d80c5cJason parks
34b13b9bdad2baf6ad1ec2e56b6b7598fa20f55fc4Mathias Agopian#include <androidfw/AssetManager.h>
35ac31a3b8b09aba1c5ebc73f0cf65cac2210aa6b7Mathias Agopian#include <binder/IPCThreadState.h>
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <utils/Atomic.h>
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <utils/Errors.h>
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <utils/Log.h>
39a90c54c90e1cb668cd74f218370f868763bbd009Wei Wang#include <utils/SystemClock.h>
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
41b593842063770f9e75c623a4bc7bb41b4c1830c6Keun-young Park#include <android-base/properties.h>
42b593842063770f9e75c623a4bc7bb41b4c1830c6Keun-young Park
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <ui/PixelFormat.h>
449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <ui/Rect.h>
459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <ui/Region.h>
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <ui/DisplayInfo.h>
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
480b722fe9ce98d97dbcb6fefd170b85ab7037e528Jeff Brown#include <gui/ISurfaceComposer.h>
498335f1ccccedb6655d96d9d5b697a7f0938235ddMathias Agopian#include <gui/Surface.h>
508335f1ccccedb6655d96d9d5b697a7f0938235ddMathias Agopian#include <gui/SurfaceComposerClient.h>
51000479f9e325b4e426a67033abd92d47da412725Mathias Agopian
52cfedceb8c180a2e176154d461659e0c3569dc931Andreas Gampe// TODO: Fix Skia.
53cfedceb8c180a2e176154d461659e0c3569dc931Andreas Gampe#pragma GCC diagnostic push
54cfedceb8c180a2e176154d461659e0c3569dc931Andreas Gampe#pragma GCC diagnostic ignored "-Wunused-parameter"
55eece0dda56ae29fff6e9003df97594f6ac50b6e2Derek Sollenberger#include <SkBitmap.h>
568898c16987831db47542a92151ed7209e22268aaMatt Sarett#include <SkImage.h>
57eece0dda56ae29fff6e9003df97594f6ac50b6e2Derek Sollenberger#include <SkStream.h>
58cfedceb8c180a2e176154d461659e0c3569dc931Andreas Gampe#pragma GCC diagnostic pop
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <GLES/gl.h>
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <GLES/glext.h>
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <EGL/eglext.h>
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "BootAnimation.h"
65d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch#include "audioplay.h"
669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectnamespace android {
689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
699748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchistatic const char OEM_BOOTANIMATION_FILE[] = "/oem/media/bootanimation.zip";
709748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchistatic const char SYSTEM_BOOTANIMATION_FILE[] = "/system/media/bootanimation.zip";
719748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchistatic const char SYSTEM_ENCRYPTED_BOOTANIMATION_FILE[] = "/system/media/bootanimation-encrypted.zip";
72b593842063770f9e75c623a4bc7bb41b4c1830c6Keun-young Parkstatic const char OEM_SHUTDOWNANIMATION_FILE[] = "/oem/media/shutdownanimation.zip";
73b593842063770f9e75c623a4bc7bb41b4c1830c6Keun-young Parkstatic const char SYSTEM_SHUTDOWNANIMATION_FILE[] = "/system/media/shutdownanimation.zip";
74b593842063770f9e75c623a4bc7bb41b4c1830c6Keun-young Park
759748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchistatic const char SYSTEM_DATA_DIR_PATH[] = "/data/system";
769748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchistatic const char SYSTEM_TIME_DIR_NAME[] = "time";
779748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchistatic const char SYSTEM_TIME_DIR_PATH[] = "/data/system/time";
780e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchistatic const char CLOCK_FONT_ASSET[] = "images/clock_font.png";
790e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchistatic const char CLOCK_FONT_ZIP_NAME[] = "clock_font.png";
809748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchistatic const char LAST_TIME_CHANGED_FILE_NAME[] = "last_time_change";
819748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchistatic const char LAST_TIME_CHANGED_FILE_PATH[] = "/data/system/time/last_time_change";
829748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchistatic const char ACCURATE_TIME_FLAG_FILE_NAME[] = "time_is_accurate";
839748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchistatic const char ACCURATE_TIME_FLAG_FILE_PATH[] = "/data/system/time/time_is_accurate";
849071db1d370573bad80f127898e34066f56c4e64Damien Bargiacchistatic const char TIME_FORMAT_12_HOUR_FLAG_FILE_PATH[] = "/data/system/time/time_format_12_hour";
859676281c4f0b34707e34cf9d2f5a866f1979c405Damien Bargiacchi// Java timestamp format. Don't show the clock if the date is before 2000-01-01 00:00:00.
869676281c4f0b34707e34cf9d2f5a866f1979c405Damien Bargiacchistatic const long long ACCURATE_TIME_EPOCH = 946684800000;
870e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchistatic constexpr char FONT_BEGIN_CHAR = ' ';
880e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchistatic constexpr char FONT_END_CHAR = '~' + 1;
890e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchistatic constexpr size_t FONT_NUM_CHARS = FONT_END_CHAR - FONT_BEGIN_CHAR + 1;
900e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchistatic constexpr size_t FONT_NUM_COLS = 16;
910e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchistatic constexpr size_t FONT_NUM_ROWS = FONT_NUM_CHARS / FONT_NUM_COLS;
920e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchistatic const int TEXT_CENTER_VALUE = INT_MAX;
930e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchistatic const int TEXT_MISSING_VALUE = INT_MIN;
949748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchistatic const char EXIT_PROP_NAME[] = "service.bootanim.exit";
95305087991d1b88d98c5e5e03fcf5a6a6e93ad356Geoffrey Pitschstatic const char PLAY_SOUND_PROP_NAME[] = "persist.sys.bootanim.play_sound";
96afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamathstatic const int ANIM_ENTRY_NAME_MAX = 256;
970e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchistatic constexpr size_t TEXT_POS_LEN_MAX = 16;
98290c4350edc66de5663e27c54e694c8ee8cf0e0eGeoffrey Pitschstatic const char BOOT_COMPLETED_PROP_NAME[] = "sys.boot_completed";
99290c4350edc66de5663e27c54e694c8ee8cf0e0eGeoffrey Pitschstatic const char BOOTREASON_PROP_NAME[] = "ro.boot.bootreason";
100290c4350edc66de5663e27c54e694c8ee8cf0e0eGeoffrey Pitsch// bootreasons list in "system/core/bootstat/bootstat.cpp".
101290c4350edc66de5663e27c54e694c8ee8cf0e0eGeoffrey Pitschstatic const std::vector<std::string> PLAY_SOUND_BOOTREASON_BLACKLIST {
102290c4350edc66de5663e27c54e694c8ee8cf0e0eGeoffrey Pitsch  "kernel_panic",
103290c4350edc66de5663e27c54e694c8ee8cf0e0eGeoffrey Pitsch  "Panic",
104290c4350edc66de5663e27c54e694c8ee8cf0e0eGeoffrey Pitsch  "Watchdog",
105290c4350edc66de5663e27c54e694c8ee8cf0e0eGeoffrey Pitsch};
106afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath
1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// ---------------------------------------------------------------------------
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1099748086fe267e21d243a49df1775905094a28dd9Damien BargiacchiBootAnimation::BootAnimation() : Thread(false), mClockEnabled(true), mTimeIsAccurate(false),
1109071db1d370573bad80f127898e34066f56c4e64Damien Bargiacchi        mTimeFormat12Hour(false), mTimeCheckThread(NULL) {
111627e7b50be41e4fdee758a1bfad3a55de56b4e27Mathias Agopian    mSession = new SurfaceComposerClient();
112290c4350edc66de5663e27c54e694c8ee8cf0e0eGeoffrey Pitsch
113290c4350edc66de5663e27c54e694c8ee8cf0e0eGeoffrey Pitsch    // If the system has already booted, the animation is not being used for a boot.
114b593842063770f9e75c623a4bc7bb41b4c1830c6Keun-young Park    mSystemBoot = !android::base::GetBoolProperty(BOOT_COMPLETED_PROP_NAME, false);
115b593842063770f9e75c623a4bc7bb41b4c1830c6Keun-young Park    std::string powerCtl = android::base::GetProperty("sys.powerctl", "");
116b593842063770f9e75c623a4bc7bb41b4c1830c6Keun-young Park    if (powerCtl.empty()) {
117b593842063770f9e75c623a4bc7bb41b4c1830c6Keun-young Park        mShuttingDown = false;
118b593842063770f9e75c623a4bc7bb41b4c1830c6Keun-young Park    } else {
119b593842063770f9e75c623a4bc7bb41b4c1830c6Keun-young Park        mShuttingDown = true;
120b593842063770f9e75c623a4bc7bb41b4c1830c6Keun-young Park    }
1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectvoid BootAnimation::onFirstRef() {
124bc7261130a51dc9f3461d3970eee1b923bcbf193Mathias Agopian    status_t err = mSession->linkToComposerDeath(this);
1253762c311729fe9f3af085c14c5c1fb471d994c03Steve Block    ALOGE_IF(err, "linkToComposerDeath failed (%s) ", strerror(-err));
1268434c5369304e639efe8eab368ca410c589d87c2Mathias Agopian    if (err == NO_ERROR) {
127bc7261130a51dc9f3461d3970eee1b923bcbf193Mathias Agopian        run("BootAnimation", PRIORITY_DISPLAY);
128bc7261130a51dc9f3461d3970eee1b923bcbf193Mathias Agopian    }
1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
131bc7261130a51dc9f3461d3970eee1b923bcbf193Mathias Agopiansp<SurfaceComposerClient> BootAnimation::session() const {
1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return mSession;
1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
135bc7261130a51dc9f3461d3970eee1b923bcbf193Mathias Agopian
136afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamathvoid BootAnimation::binderDied(const wp<IBinder>&)
137bc7261130a51dc9f3461d3970eee1b923bcbf193Mathias Agopian{
138bc7261130a51dc9f3461d3970eee1b923bcbf193Mathias Agopian    // woah, surfaceflinger died!
1395baa3a62a97544669fba6d65a11c07f252e654ddSteve Block    ALOGD("SurfaceFlinger died, exiting...");
140bc7261130a51dc9f3461d3970eee1b923bcbf193Mathias Agopian
141bc7261130a51dc9f3461d3970eee1b923bcbf193Mathias Agopian    // calling requestExit() is not enough here because the Surface code
142bc7261130a51dc9f3461d3970eee1b923bcbf193Mathias Agopian    // might be blocked on a condition variable that will never be updated.
143bc7261130a51dc9f3461d3970eee1b923bcbf193Mathias Agopian    kill( getpid(), SIGKILL );
144bc7261130a51dc9f3461d3970eee1b923bcbf193Mathias Agopian    requestExit();
145d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch    audioplay::destroy();
146bc7261130a51dc9f3461d3970eee1b923bcbf193Mathias Agopian}
147bc7261130a51dc9f3461d3970eee1b923bcbf193Mathias Agopian
1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatus_t BootAnimation::initTexture(Texture* texture, AssetManager& assets,
1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        const char* name) {
1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    Asset* asset = assets.open(name, Asset::ACCESS_BUFFER);
151cfedceb8c180a2e176154d461659e0c3569dc931Andreas Gampe    if (asset == NULL)
1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return NO_INIT;
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    SkBitmap bitmap;
1548898c16987831db47542a92151ed7209e22268aaMatt Sarett    sk_sp<SkData> data = SkData::MakeWithoutCopy(asset->getBuffer(false),
1558898c16987831db47542a92151ed7209e22268aaMatt Sarett            asset->getLength());
1568898c16987831db47542a92151ed7209e22268aaMatt Sarett    sk_sp<SkImage> image = SkImage::MakeFromEncoded(data);
1578898c16987831db47542a92151ed7209e22268aaMatt Sarett    image->asLegacyBitmap(&bitmap, SkImage::kRO_LegacyBitmapMode);
1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    asset->close();
1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    delete asset;
1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // ensure we can call getPixels(). No need to call unlock, since the
1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // bitmap will go out of scope when we return from this method.
1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    bitmap.lockPixels();
1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    const int w = bitmap.width();
1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    const int h = bitmap.height();
1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    const void* p = bitmap.getPixels();
1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    GLint crop[4] = { 0, h, w, -h };
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    texture->w = w;
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    texture->h = h;
1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    glGenTextures(1, &texture->name);
1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    glBindTexture(GL_TEXTURE_2D, texture->name);
1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
17642a1d08df7d417fd4e67eabc91ff05ee77fd9995Mike Reed    switch (bitmap.colorType()) {
17742a1d08df7d417fd4e67eabc91ff05ee77fd9995Mike Reed        case kAlpha_8_SkColorType:
1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, w, h, 0, GL_ALPHA,
1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    GL_UNSIGNED_BYTE, p);
1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            break;
18142a1d08df7d417fd4e67eabc91ff05ee77fd9995Mike Reed        case kARGB_4444_SkColorType:
1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA,
1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    GL_UNSIGNED_SHORT_4_4_4_4, p);
1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            break;
18542a1d08df7d417fd4e67eabc91ff05ee77fd9995Mike Reed        case kN32_SkColorType:
1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA,
1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    GL_UNSIGNED_BYTE, p);
1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            break;
18942a1d08df7d417fd4e67eabc91ff05ee77fd9995Mike Reed        case kRGB_565_SkColorType:
1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB,
1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    GL_UNSIGNED_SHORT_5_6_5, p);
1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            break;
1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        default:
1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            break;
1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
2020e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi
2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return NO_ERROR;
2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2060e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchistatus_t BootAnimation::initTexture(FileMap* map, int* width, int* height)
207a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian{
208a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    SkBitmap bitmap;
209f67b317c102db72182046ec2a2cffe2331017709Damien Bargiacchi    sk_sp<SkData> data = SkData::MakeWithoutCopy(map->getDataPtr(),
210f67b317c102db72182046ec2a2cffe2331017709Damien Bargiacchi            map->getDataLength());
2118898c16987831db47542a92151ed7209e22268aaMatt Sarett    sk_sp<SkImage> image = SkImage::MakeFromEncoded(data);
2128898c16987831db47542a92151ed7209e22268aaMatt Sarett    image->asLegacyBitmap(&bitmap, SkImage::kRO_LegacyBitmapMode);
213a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
2140c1eeb3c8ab53954218d3b8f4be08ff21be3e985Mykola Kondratenko    // FileMap memory is never released until application exit.
2150c1eeb3c8ab53954218d3b8f4be08ff21be3e985Mykola Kondratenko    // Release it now as the texture is already loaded and the memory used for
2160c1eeb3c8ab53954218d3b8f4be08ff21be3e985Mykola Kondratenko    // the packed resource can be released.
2170e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi    delete map;
2180c1eeb3c8ab53954218d3b8f4be08ff21be3e985Mykola Kondratenko
219a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    // ensure we can call getPixels(). No need to call unlock, since the
220a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    // bitmap will go out of scope when we return from this method.
221a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    bitmap.lockPixels();
222a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
223a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    const int w = bitmap.width();
224a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    const int h = bitmap.height();
225a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    const void* p = bitmap.getPixels();
226a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
227a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    GLint crop[4] = { 0, h, w, -h };
228a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    int tw = 1 << (31 - __builtin_clz(w));
229a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    int th = 1 << (31 - __builtin_clz(h));
230a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    if (tw < w) tw <<= 1;
231a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    if (th < h) th <<= 1;
232a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
23342a1d08df7d417fd4e67eabc91ff05ee77fd9995Mike Reed    switch (bitmap.colorType()) {
23442a1d08df7d417fd4e67eabc91ff05ee77fd9995Mike Reed        case kN32_SkColorType:
235271674930a1f9020a291827a8ecb6ab68782c4faSai Kiran Korwar            if (!mUseNpotTextures && (tw != w || th != h)) {
236a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tw, th, 0, GL_RGBA,
237a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                        GL_UNSIGNED_BYTE, 0);
238a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                glTexSubImage2D(GL_TEXTURE_2D, 0,
239a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                        0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, p);
240a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian            } else {
241271674930a1f9020a291827a8ecb6ab68782c4faSai Kiran Korwar                glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA,
242a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                        GL_UNSIGNED_BYTE, p);
243a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian            }
244a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian            break;
245a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
24642a1d08df7d417fd4e67eabc91ff05ee77fd9995Mike Reed        case kRGB_565_SkColorType:
247271674930a1f9020a291827a8ecb6ab68782c4faSai Kiran Korwar            if (!mUseNpotTextures && (tw != w || th != h)) {
248a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tw, th, 0, GL_RGB,
249a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                        GL_UNSIGNED_SHORT_5_6_5, 0);
250a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                glTexSubImage2D(GL_TEXTURE_2D, 0,
251a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                        0, 0, w, h, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, p);
252a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian            } else {
253271674930a1f9020a291827a8ecb6ab68782c4faSai Kiran Korwar                glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB,
254a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                        GL_UNSIGNED_SHORT_5_6_5, p);
255a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian            }
256a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian            break;
257a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian        default:
258a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian            break;
259a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    }
260a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
261a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
262a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
2630e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi    *width = w;
2640e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi    *height = h;
2650e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi
266a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    return NO_ERROR;
267a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian}
268a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
2699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatus_t BootAnimation::readyToRun() {
2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mAssets.addDefaultAssets();
2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2720b722fe9ce98d97dbcb6fefd170b85ab7037e528Jeff Brown    sp<IBinder> dtoken(SurfaceComposerClient::getBuiltInDisplay(
2730b722fe9ce98d97dbcb6fefd170b85ab7037e528Jeff Brown            ISurfaceComposer::eDisplayIdMain));
2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    DisplayInfo dinfo;
2750b722fe9ce98d97dbcb6fefd170b85ab7037e528Jeff Brown    status_t status = SurfaceComposerClient::getDisplayInfo(dtoken, &dinfo);
2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (status)
2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return -1;
2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // create the native surface
2800b722fe9ce98d97dbcb6fefd170b85ab7037e528Jeff Brown    sp<SurfaceControl> control = session()->createSurface(String8("BootAnimation"),
2810b722fe9ce98d97dbcb6fefd170b85ab7037e528Jeff Brown            dinfo.w, dinfo.h, PIXEL_FORMAT_RGB_565);
282439863f3b3e725b5de1cba4940a21900369961c0Mathias Agopian
283439863f3b3e725b5de1cba4940a21900369961c0Mathias Agopian    SurfaceComposerClient::openGlobalTransaction();
28417f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian    control->setLayer(0x40000000);
285439863f3b3e725b5de1cba4940a21900369961c0Mathias Agopian    SurfaceComposerClient::closeGlobalTransaction();
2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
28717f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian    sp<Surface> s = control->getSurface();
28817f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian
2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // initialize opengl and egl
290738b9a45399485893fa9541fae19c47e01bc4af4Mathias Agopian    const EGLint attribs[] = {
2911b253b702a356619ae3c5e68ee92062b5305c5d7Mathias Agopian            EGL_RED_SIZE,   8,
2921b253b702a356619ae3c5e68ee92062b5305c5d7Mathias Agopian            EGL_GREEN_SIZE, 8,
2931b253b702a356619ae3c5e68ee92062b5305c5d7Mathias Agopian            EGL_BLUE_SIZE,  8,
294a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian            EGL_DEPTH_SIZE, 0,
295a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian            EGL_NONE
296738b9a45399485893fa9541fae19c47e01bc4af4Mathias Agopian    };
297cfedceb8c180a2e176154d461659e0c3569dc931Andreas Gampe    EGLint w, h;
2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    EGLint numConfigs;
2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    EGLConfig config;
3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    EGLSurface surface;
3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    EGLContext context;
302627e7b50be41e4fdee758a1bfad3a55de56b4e27Mathias Agopian
3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
304627e7b50be41e4fdee758a1bfad3a55de56b4e27Mathias Agopian
305627e7b50be41e4fdee758a1bfad3a55de56b4e27Mathias Agopian    eglInitialize(display, 0, 0);
3061b253b702a356619ae3c5e68ee92062b5305c5d7Mathias Agopian    eglChooseConfig(display, attribs, &config, 1, &numConfigs);
3071473f46cbc82aa6f0ba744cc896a36923823d55bMathias Agopian    surface = eglCreateWindowSurface(display, config, s.get(), NULL);
3089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    context = eglCreateContext(display, config, NULL, NULL);
3099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    eglQuerySurface(display, surface, EGL_WIDTH, &w);
3109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    eglQuerySurface(display, surface, EGL_HEIGHT, &h);
311a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
312abac01052c1c40f8582fe9f010c2efe6013e25c6Mathias Agopian    if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE)
313abac01052c1c40f8582fe9f010c2efe6013e25c6Mathias Agopian        return NO_INIT;
314a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mDisplay = display;
3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mContext = context;
3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mSurface = surface;
3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mWidth = w;
3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mHeight = h;
32017f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian    mFlingerSurfaceControl = control;
3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mFlingerSurface = s;
3229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
323c367d48c55e5a3fa0df14fd62889e4bb6b63cb01Elliott Hughes    // If the device has encryption turned on or is in process
324bd9a08d318f94a3d0b2f8f9d7b16b10736d80c5cJason parks    // of being encrypted we show the encrypted boot animation.
325bd9a08d318f94a3d0b2f8f9d7b16b10736d80c5cJason parks    char decrypt[PROPERTY_VALUE_MAX];
326bd9a08d318f94a3d0b2f8f9d7b16b10736d80c5cJason parks    property_get("vold.decrypt", decrypt, "");
327bd9a08d318f94a3d0b2f8f9d7b16b10736d80c5cJason parks
328b593842063770f9e75c623a4bc7bb41b4c1830c6Keun-young Park    bool encryptedAnimation = atoi(decrypt) != 0 ||
329b593842063770f9e75c623a4bc7bb41b4c1830c6Keun-young Park        !strcmp("trigger_restart_min_framework", decrypt);
330bd9a08d318f94a3d0b2f8f9d7b16b10736d80c5cJason parks
331b593842063770f9e75c623a4bc7bb41b4c1830c6Keun-young Park    if (!mShuttingDown && encryptedAnimation &&
332b593842063770f9e75c623a4bc7bb41b4c1830c6Keun-young Park        (access(SYSTEM_ENCRYPTED_BOOTANIMATION_FILE, R_OK) == 0)) {
33339218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy        mZipFileName = SYSTEM_ENCRYPTED_BOOTANIMATION_FILE;
334b593842063770f9e75c623a4bc7bb41b4c1830c6Keun-young Park        return NO_ERROR;
33539218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    }
336b593842063770f9e75c623a4bc7bb41b4c1830c6Keun-young Park    static const char* bootFiles[] = {OEM_BOOTANIMATION_FILE, SYSTEM_BOOTANIMATION_FILE};
337b593842063770f9e75c623a4bc7bb41b4c1830c6Keun-young Park    static const char* shutdownFiles[] =
338b593842063770f9e75c623a4bc7bb41b4c1830c6Keun-young Park        {OEM_SHUTDOWNANIMATION_FILE, SYSTEM_SHUTDOWNANIMATION_FILE};
339b593842063770f9e75c623a4bc7bb41b4c1830c6Keun-young Park
340b593842063770f9e75c623a4bc7bb41b4c1830c6Keun-young Park    for (const char* f : (!mShuttingDown ? bootFiles : shutdownFiles)) {
341b593842063770f9e75c623a4bc7bb41b4c1830c6Keun-young Park        if (access(f, R_OK) == 0) {
342b593842063770f9e75c623a4bc7bb41b4c1830c6Keun-young Park            mZipFileName = f;
343b593842063770f9e75c623a4bc7bb41b4c1830c6Keun-young Park            return NO_ERROR;
344b593842063770f9e75c623a4bc7bb41b4c1830c6Keun-young Park        }
345bd9a08d318f94a3d0b2f8f9d7b16b10736d80c5cJason parks    }
3469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return NO_ERROR;
3479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
349a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopianbool BootAnimation::threadLoop()
350a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian{
351a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    bool r;
352afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath    // We have no bootanimation file, so we use the stock android logo
353afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath    // animation.
35439218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    if (mZipFileName.isEmpty()) {
355a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian        r = android();
356a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    } else {
357a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian        r = movie();
358a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    }
359a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
3609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
3619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    eglDestroyContext(mDisplay, mContext);
3629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    eglDestroySurface(mDisplay, mSurface);
3636cf0db228ca275dfcda57d79c55e5fa306809632Mathias Agopian    mFlingerSurface.clear();
36417f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian    mFlingerSurfaceControl.clear();
365627e7b50be41e4fdee758a1bfad3a55de56b4e27Mathias Agopian    eglTerminate(mDisplay);
3663eee9fbb6df1dbbcefe1f0dfdf1295c95ddf3279Sai Kiran Korwar    eglReleaseThread();
367627e7b50be41e4fdee758a1bfad3a55de56b4e27Mathias Agopian    IPCThreadState::self()->stopProcess();
3689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return r;
3699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
3709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
371a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopianbool BootAnimation::android()
372a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian{
373d1794cdbb4183774ac68e9d445ca87835fbe6461Keun-young Park    ALOGD("%sAnimationShownTiming start time: %" PRId64 "ms", mShuttingDown ? "Shutdown" : "Boot",
374d1794cdbb4183774ac68e9d445ca87835fbe6461Keun-young Park            elapsedRealtime());
375b2cf954cb47a73065aa4b7fed753877615614f41Mathias Agopian    initTexture(&mAndroid[0], mAssets, "images/android-logo-mask.png");
376b2cf954cb47a73065aa4b7fed753877615614f41Mathias Agopian    initTexture(&mAndroid[1], mAssets, "images/android-logo-shine.png");
3779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // clear screen
379a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    glShadeModel(GL_FLAT);
380b2cf954cb47a73065aa4b7fed753877615614f41Mathias Agopian    glDisable(GL_DITHER);
381b2cf954cb47a73065aa4b7fed753877615614f41Mathias Agopian    glDisable(GL_SCISSOR_TEST);
38259f19e48c1c043bb9debdc35d166e397e2125d33Mathias Agopian    glClearColor(0,0,0,1);
3839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    glClear(GL_COLOR_BUFFER_BIT);
3849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    eglSwapBuffers(mDisplay, mSurface);
3859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
386a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    glEnable(GL_TEXTURE_2D);
387a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
388a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
389b2cf954cb47a73065aa4b7fed753877615614f41Mathias Agopian    const GLint xc = (mWidth  - mAndroid[0].w) / 2;
390b2cf954cb47a73065aa4b7fed753877615614f41Mathias Agopian    const GLint yc = (mHeight - mAndroid[0].h) / 2;
391b2cf954cb47a73065aa4b7fed753877615614f41Mathias Agopian    const Rect updateRect(xc, yc, xc + mAndroid[0].w, yc + mAndroid[0].h);
3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    glScissor(updateRect.left, mHeight - updateRect.bottom, updateRect.width(),
3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            updateRect.height());
3959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
396b2cf954cb47a73065aa4b7fed753877615614f41Mathias Agopian    // Blend state
397b2cf954cb47a73065aa4b7fed753877615614f41Mathias Agopian    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
398b2cf954cb47a73065aa4b7fed753877615614f41Mathias Agopian    glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
399b2cf954cb47a73065aa4b7fed753877615614f41Mathias Agopian
4009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    const nsecs_t startTime = systemTime();
4019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    do {
4021379665abdb8330caf813fb77902914d1545bcd9Mathias Agopian        nsecs_t now = systemTime();
4031379665abdb8330caf813fb77902914d1545bcd9Mathias Agopian        double time = now - startTime;
404b2cf954cb47a73065aa4b7fed753877615614f41Mathias Agopian        float t = 4.0f * float(time / us2ns(16667)) / mAndroid[1].w;
405b2cf954cb47a73065aa4b7fed753877615614f41Mathias Agopian        GLint offset = (1 - (t - floorf(t))) * mAndroid[1].w;
406b2cf954cb47a73065aa4b7fed753877615614f41Mathias Agopian        GLint x = xc - offset;
4079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4088166864e42bc20c1544b2028e8dd65b90f29a0eaMathias Agopian        glDisable(GL_SCISSOR_TEST);
4098166864e42bc20c1544b2028e8dd65b90f29a0eaMathias Agopian        glClear(GL_COLOR_BUFFER_BIT);
4108166864e42bc20c1544b2028e8dd65b90f29a0eaMathias Agopian
4118166864e42bc20c1544b2028e8dd65b90f29a0eaMathias Agopian        glEnable(GL_SCISSOR_TEST);
4129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        glDisable(GL_BLEND);
4139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        glBindTexture(GL_TEXTURE_2D, mAndroid[1].name);
414b2cf954cb47a73065aa4b7fed753877615614f41Mathias Agopian        glDrawTexiOES(x,                 yc, 0, mAndroid[1].w, mAndroid[1].h);
415b2cf954cb47a73065aa4b7fed753877615614f41Mathias Agopian        glDrawTexiOES(x + mAndroid[1].w, yc, 0, mAndroid[1].w, mAndroid[1].h);
4169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
417b2cf954cb47a73065aa4b7fed753877615614f41Mathias Agopian        glEnable(GL_BLEND);
418b2cf954cb47a73065aa4b7fed753877615614f41Mathias Agopian        glBindTexture(GL_TEXTURE_2D, mAndroid[0].name);
419b2cf954cb47a73065aa4b7fed753877615614f41Mathias Agopian        glDrawTexiOES(xc, yc, 0, mAndroid[0].w, mAndroid[0].h);
4209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
421627e7b50be41e4fdee758a1bfad3a55de56b4e27Mathias Agopian        EGLBoolean res = eglSwapBuffers(mDisplay, mSurface);
422627e7b50be41e4fdee758a1bfad3a55de56b4e27Mathias Agopian        if (res == EGL_FALSE)
423627e7b50be41e4fdee758a1bfad3a55de56b4e27Mathias Agopian            break;
424627e7b50be41e4fdee758a1bfad3a55de56b4e27Mathias Agopian
4251379665abdb8330caf813fb77902914d1545bcd9Mathias Agopian        // 12fps: don't animate too fast to preserve CPU
4261379665abdb8330caf813fb77902914d1545bcd9Mathias Agopian        const nsecs_t sleepTime = 83333 - ns2us(systemTime() - now);
4271379665abdb8330caf813fb77902914d1545bcd9Mathias Agopian        if (sleepTime > 0)
428a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian            usleep(sleepTime);
429d3782b26b2026e60a8e0d4b967a156369f2a46f8Kevin Hester
430d3782b26b2026e60a8e0d4b967a156369f2a46f8Kevin Hester        checkExit();
4319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    } while (!exitPending());
4329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    glDeleteTextures(1, &mAndroid[0].name);
4349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    glDeleteTextures(1, &mAndroid[1].name);
4359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return false;
4369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
4379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
438d3782b26b2026e60a8e0d4b967a156369f2a46f8Kevin Hestervoid BootAnimation::checkExit() {
439d3782b26b2026e60a8e0d4b967a156369f2a46f8Kevin Hester    // Allow surface flinger to gracefully request shutdown
440d3782b26b2026e60a8e0d4b967a156369f2a46f8Kevin Hester    char value[PROPERTY_VALUE_MAX];
441d3782b26b2026e60a8e0d4b967a156369f2a46f8Kevin Hester    property_get(EXIT_PROP_NAME, value, "0");
442d3782b26b2026e60a8e0d4b967a156369f2a46f8Kevin Hester    int exitnow = atoi(value);
443d3782b26b2026e60a8e0d4b967a156369f2a46f8Kevin Hester    if (exitnow) {
444d3782b26b2026e60a8e0d4b967a156369f2a46f8Kevin Hester        requestExit();
445d3782b26b2026e60a8e0d4b967a156369f2a46f8Kevin Hester    }
446d3782b26b2026e60a8e0d4b967a156369f2a46f8Kevin Hester}
447d3782b26b2026e60a8e0d4b967a156369f2a46f8Kevin Hester
4480e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchibool BootAnimation::validClock(const Animation::Part& part) {
4490e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi    return part.clockPosX != TEXT_MISSING_VALUE && part.clockPosY != TEXT_MISSING_VALUE;
4500e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi}
4510e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi
4520e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchibool parseTextCoord(const char* str, int* dest) {
4530e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi    if (strcmp("c", str) == 0) {
4540e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi        *dest = TEXT_CENTER_VALUE;
4550e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi        return true;
4560e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi    }
4570e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi
4580e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi    char* end;
4590e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi    int val = (int) strtol(str, &end, 0);
4600e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi    if (end == str || *end != '\0' || val == INT_MAX || val == INT_MIN) {
4610e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi        return false;
4620e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi    }
4630e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi    *dest = val;
4640e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi    return true;
4650e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi}
4660e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi
4670e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi// Parse two position coordinates. If only string is non-empty, treat it as the y value.
4680e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchivoid parsePosition(const char* str1, const char* str2, int* x, int* y) {
4690e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi    bool success = false;
4700e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi    if (strlen(str1) == 0) {  // No values were specified
4710e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi        // success = false
4720e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi    } else if (strlen(str2) == 0) {  // we have only one value
4730e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi        if (parseTextCoord(str1, y)) {
4740e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi            *x = TEXT_CENTER_VALUE;
4750e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi            success = true;
4760e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi        }
4770e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi    } else {
4780e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi        if (parseTextCoord(str1, x) && parseTextCoord(str2, y)) {
4790e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi            success = true;
4800e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi        }
4810e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi    }
4820e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi
4830e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi    if (!success) {
4840e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi        *x = TEXT_MISSING_VALUE;
4850e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi        *y = TEXT_MISSING_VALUE;
4860e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi    }
4870e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi}
4880e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi
489083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall// Parse a color represented as an HTML-style 'RRGGBB' string: each pair of
490083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall// characters in str is a hex number in [0, 255], which are converted to
491083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall// floating point values in the range [0.0, 1.0] and placed in the
492083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall// corresponding elements of color.
493083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall//
494083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall// If the input string isn't valid, parseColor returns false and color is
495083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall// left unchanged.
496083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hallstatic bool parseColor(const char str[7], float color[3]) {
497083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall    float tmpColor[3];
498083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall    for (int i = 0; i < 3; i++) {
499083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall        int val = 0;
500083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall        for (int j = 0; j < 2; j++) {
501083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall            val *= 16;
502083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall            char c = str[2*i + j];
503083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall            if      (c >= '0' && c <= '9') val += c - '0';
504083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall            else if (c >= 'A' && c <= 'F') val += (c - 'A') + 10;
505083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall            else if (c >= 'a' && c <= 'f') val += (c - 'a') + 10;
506083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall            else                           return false;
507083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall        }
508083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall        tmpColor[i] = static_cast<float>(val) / 255.0f;
509083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall    }
510083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall    memcpy(color, tmpColor, sizeof(tmpColor));
511083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall    return true;
512083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall}
513083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall
51439218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy
51539218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyystatic bool readFile(ZipFileRO* zip, const char* name, String8& outString)
516a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian{
51739218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    ZipEntryRO entry = zip->findEntryByName(name);
518ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood    ALOGE_IF(!entry, "couldn't find %s", name);
519ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood    if (!entry) {
520afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath        return false;
521afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath    }
522a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
52339218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    FileMap* entryMap = zip->createEntryFileMap(entry);
52439218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    zip->releaseEntry(entry);
525ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood    ALOGE_IF(!entryMap, "entryMap is null");
526ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood    if (!entryMap) {
527a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian        return false;
528a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    }
529a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
530ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood    outString.setTo((char const*)entryMap->getDataPtr(), entryMap->getDataLength());
531688ff4cf0f93d1a886437884f23874e5595d59a3Narayan Kamath    delete entryMap;
532ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood    return true;
533ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood}
534ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood
5350e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi// The font image should be a 96x2 array of character images.  The
5360e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi// columns are the printable ASCII characters 0x20 - 0x7f.  The
5370e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi// top row is regular text; the bottom row is bold.
5380e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchistatus_t BootAnimation::initFont(Font* font, const char* fallback) {
5390e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi    status_t status = NO_ERROR;
540a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi
5410e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi    if (font->map != nullptr) {
5420e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi        glGenTextures(1, &font->texture.name);
5430e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi        glBindTexture(GL_TEXTURE_2D, font->texture.name);
544a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi
5450e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi        status = initTexture(font->map, &font->texture.w, &font->texture.h);
5460e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi
5470e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi        glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5480e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi        glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5490e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi        glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
5500e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi        glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
5510e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi    } else if (fallback != nullptr) {
5520e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi        status = initTexture(&font->texture, mAssets, fallback);
5530e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi    } else {
5540e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi        return NO_INIT;
555a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi    }
556a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi
5570e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi    if (status == NO_ERROR) {
5580e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi        font->char_width = font->texture.w / FONT_NUM_COLS;
5590e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi        font->char_height = font->texture.h / FONT_NUM_ROWS / 2;  // There are bold and regular rows
5600e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi    }
561a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi
5620e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi    return status;
5630e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi}
564a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi
5650e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchivoid BootAnimation::drawText(const char* str, const Font& font, bool bold, int* x, int* y) {
5660e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi    glEnable(GL_BLEND);  // Allow us to draw on top of the animation
5670e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi    glBindTexture(GL_TEXTURE_2D, font.texture.name);
5680e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi
5690e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi    const int len = strlen(str);
5700e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi    const int strWidth = font.char_width * len;
5710e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi
5720e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi    if (*x == TEXT_CENTER_VALUE) {
5730e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi        *x = (mWidth - strWidth) / 2;
5740e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi    } else if (*x < 0) {
5750e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi        *x = mWidth + *x - strWidth;
5760e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi    }
5770e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi    if (*y == TEXT_CENTER_VALUE) {
5780e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi        *y = (mHeight - font.char_height) / 2;
5790e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi    } else if (*y < 0) {
5800e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi        *y = mHeight + *y - font.char_height;
581a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi    }
582a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi
5830e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi    int cropRect[4] = { 0, 0, font.char_width, -font.char_height };
584a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi
5850e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi    for (int i = 0; i < len; i++) {
5860e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi        char c = str[i];
587a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi
5880e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi        if (c < FONT_BEGIN_CHAR || c > FONT_END_CHAR) {
5890e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi            c = '?';
590a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi        }
591a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi
592a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi        // Crop the texture to only the pixels in the current glyph
5930e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi        const int charPos = (c - FONT_BEGIN_CHAR);  // Position in the list of valid characters
5940e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi        const int row = charPos / FONT_NUM_COLS;
5950e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi        const int col = charPos % FONT_NUM_COLS;
5960e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi        cropRect[0] = col * font.char_width;  // Left of column
5970e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi        cropRect[1] = row * font.char_height * 2; // Top of row
5980e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi        // Move down to bottom of regular (one char_heigh) or bold (two char_heigh) line
5990e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi        cropRect[1] += bold ? 2 * font.char_height : font.char_height;
600a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi        glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, cropRect);
601a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi
6020e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi        glDrawTexiOES(*x, *y, 0, font.char_width, font.char_height);
603a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi
6040e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi        *x += font.char_width;
605a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi    }
606a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi
607a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi    glDisable(GL_BLEND);  // Return to the animation's default behaviour
608a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi    glBindTexture(GL_TEXTURE_2D, 0);
609a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi}
610a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi
6119071db1d370573bad80f127898e34066f56c4e64Damien Bargiacchi// We render 12 or 24 hour time.
6120e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchivoid BootAnimation::drawClock(const Font& font, const int xPos, const int yPos) {
6139071db1d370573bad80f127898e34066f56c4e64Damien Bargiacchi    static constexpr char TIME_FORMAT_12[] = "%l:%M";
6149071db1d370573bad80f127898e34066f56c4e64Damien Bargiacchi    static constexpr char TIME_FORMAT_24[] = "%H:%M";
6150e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi    static constexpr int TIME_LENGTH = 6;
6160e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi
6170e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi    time_t rawtime;
6180e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi    time(&rawtime);
6190e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi    struct tm* timeInfo = localtime(&rawtime);
6200e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi
6210e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi    char timeBuff[TIME_LENGTH];
6229071db1d370573bad80f127898e34066f56c4e64Damien Bargiacchi    const char* timeFormat = mTimeFormat12Hour ? TIME_FORMAT_12 : TIME_FORMAT_24;
6239071db1d370573bad80f127898e34066f56c4e64Damien Bargiacchi    size_t length = strftime(timeBuff, TIME_LENGTH, timeFormat, timeInfo);
6240e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi
6250e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi    if (length != TIME_LENGTH - 1) {
6260e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi        ALOGE("Couldn't format time; abandoning boot animation clock");
6270e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi        mClockEnabled = false;
6280e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi        return;
6290e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi    }
6300e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi
63145a764400485fb6fb9b0d3566e24feac446e616cDamien Bargiacchi    char* out = timeBuff[0] == ' ' ? &timeBuff[1] : &timeBuff[0];
6320e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi    int x = xPos;
6330e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi    int y = yPos;
63445a764400485fb6fb9b0d3566e24feac446e616cDamien Bargiacchi    drawText(out, font, false, &x, &y);
6350e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi}
6360e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi
63739218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyybool BootAnimation::parseAnimationDesc(Animation& animation)
638ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood{
639ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood    String8 desString;
640ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood
64139218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    if (!readFile(animation.zip, "desc.txt", desString)) {
642ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood        return false;
643ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood    }
644a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    char const* s = desString.string();
645a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
646a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    // Parse the description file
647a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    for (;;) {
648a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian        const char* endl = strstr(s, "\n");
649cfedceb8c180a2e176154d461659e0c3569dc931Andreas Gampe        if (endl == NULL) break;
650a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian        String8 line(s, endl - s);
651a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian        const char* l = line.string();
652a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi        int fps = 0;
653a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi        int width = 0;
654a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi        int height = 0;
655a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi        int count = 0;
656a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi        int pause = 0;
657afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath        char path[ANIM_ENTRY_NAME_MAX];
658083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall        char color[7] = "000000"; // default to black if unspecified
6590e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi        char clockPos1[TEXT_POS_LEN_MAX + 1] = "";
6600e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi        char clockPos2[TEXT_POS_LEN_MAX + 1] = "";
661083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall
662d3782b26b2026e60a8e0d4b967a156369f2a46f8Kevin Hester        char pathType;
663a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian        if (sscanf(l, "%d %d %d", &width, &height, &fps) == 3) {
664083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall            // ALOGD("> w=%d, h=%d, fps=%d", width, height, fps);
665a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian            animation.width = width;
666a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian            animation.height = height;
667a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian            animation.fps = fps;
6680e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi        } else if (sscanf(l, " %c %d %d %s #%6s %16s %16s",
6690e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi                          &pathType, &count, &pause, path, color, clockPos1, clockPos2) >= 4) {
6700e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi            //ALOGD("> type=%c, count=%d, pause=%d, path=%s, color=%s, clockPos1=%s, clockPos2=%s",
6710e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi            //    pathType, count, pause, path, color, clockPos1, clockPos2);
672a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian            Animation::Part part;
673d3782b26b2026e60a8e0d4b967a156369f2a46f8Kevin Hester            part.playUntilComplete = pathType == 'c';
674a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian            part.count = count;
675a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian            part.pause = pause;
676a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian            part.path = path;
677d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch            part.audioData = NULL;
67839218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy            part.animation = NULL;
679083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall            if (!parseColor(color, part.backgroundColor)) {
680083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall                ALOGE("> invalid color '#%s'", color);
681083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall                part.backgroundColor[0] = 0.0f;
682083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall                part.backgroundColor[1] = 0.0f;
683083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall                part.backgroundColor[2] = 0.0f;
684083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall            }
6850e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi            parsePosition(clockPos1, clockPos2, &part.clockPosX, &part.clockPosY);
686a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian            animation.parts.add(part);
687a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian        }
68839218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy        else if (strcmp(l, "$SYSTEM") == 0) {
68939218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy            // ALOGD("> SYSTEM");
69039218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy            Animation::Part part;
69139218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy            part.playUntilComplete = false;
69239218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy            part.count = 1;
69339218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy            part.pause = 0;
694d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch            part.audioData = NULL;
69539218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy            part.animation = loadAnimation(String8(SYSTEM_BOOTANIMATION_FILE));
69639218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy            if (part.animation != NULL)
69739218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy                animation.parts.add(part);
69839218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy        }
699a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian        s = ++endl;
700a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    }
701a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
70239218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    return true;
70339218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy}
70439218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy
70539218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyybool BootAnimation::preloadZip(Animation& animation)
70639218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy{
707a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    // read all the data structures
708a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    const size_t pcount = animation.parts.size();
709afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath    void *cookie = NULL;
710dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch    ZipFileRO* zip = animation.zip;
711dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch    if (!zip->startIteration(&cookie)) {
712afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath        return false;
713afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath    }
714afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath
715a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch    Animation::Part* partWithAudio = NULL;
716afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath    ZipEntryRO entry;
717afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath    char name[ANIM_ENTRY_NAME_MAX];
718dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch    while ((entry = zip->nextEntry(cookie)) != NULL) {
719dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch        const int foundEntryName = zip->getEntryFileName(entry, name, ANIM_ENTRY_NAME_MAX);
720afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath        if (foundEntryName > ANIM_ENTRY_NAME_MAX || foundEntryName == -1) {
721afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath            ALOGE("Error fetching entry file name");
722afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath            continue;
723afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath        }
724afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath
725afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath        const String8 entryName(name);
726afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath        const String8 path(entryName.getPathDir());
727afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath        const String8 leaf(entryName.getPathLeaf());
728afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath        if (leaf.size() > 0) {
7290e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi            if (entryName == CLOCK_FONT_ZIP_NAME) {
7300e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi                FileMap* map = zip->createEntryFileMap(entry);
7310e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi                if (map) {
7320e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi                    animation.clockFont.map = map;
7330e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi                }
7340e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi                continue;
7350e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi            }
7360e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi
737dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch            for (size_t j = 0; j < pcount; j++) {
738afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath                if (path == animation.parts[j].path) {
7394600dd053dbdbd4b95f3b11057a1cc55b99f9c77Narayan Kamath                    uint16_t method;
740afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath                    // supports only stored png files
741dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch                    if (zip->getEntryInfo(entry, &method, NULL, NULL, NULL, NULL, NULL)) {
742afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath                        if (method == ZipFileRO::kCompressStored) {
743dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch                            FileMap* map = zip->createEntryFileMap(entry);
744afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath                            if (map) {
745afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath                                Animation::Part& part(animation.parts.editItemAt(j));
746ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood                                if (leaf == "audio.wav") {
747ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood                                    // a part may have at most one audio file
748d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch                                    part.audioData = (uint8_t *)map->getDataPtr();
749d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch                                    part.audioLength = map->getDataLength();
750a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch                                    partWithAudio = &part;
751dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch                                } else if (leaf == "trim.txt") {
752dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch                                    part.trimData.setTo((char const*)map->getDataPtr(),
753dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch                                                        map->getDataLength());
754ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood                                } else {
755ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood                                    Animation::Frame frame;
756ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood                                    frame.name = leaf;
757ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood                                    frame.map = map;
758dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch                                    frame.trimWidth = animation.width;
759dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch                                    frame.trimHeight = animation.height;
760dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch                                    frame.trimX = 0;
761dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch                                    frame.trimY = 0;
762ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood                                    part.frames.add(frame);
763ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood                                }
764a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                            }
765d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch                        } else {
766d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch                            ALOGE("bootanimation.zip is compressed; must be only stored");
767a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                        }
768a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                    }
769a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                }
770a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian            }
771a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian        }
772a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    }
773a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
774dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch    // If there is trimData present, override the positioning defaults.
775dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch    for (Animation::Part& part : animation.parts) {
776dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch        const char* trimDataStr = part.trimData.string();
777dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch        for (size_t frameIdx = 0; frameIdx < part.frames.size(); frameIdx++) {
778dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch            const char* endl = strstr(trimDataStr, "\n");
779dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch            // No more trimData for this part.
780dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch            if (endl == NULL) {
781dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch                break;
782dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch            }
783dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch            String8 line(trimDataStr, endl - trimDataStr);
784dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch            const char* lineStr = line.string();
785dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch            trimDataStr = ++endl;
786dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch            int width = 0, height = 0, x = 0, y = 0;
787dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch            if (sscanf(lineStr, "%dx%d+%d+%d", &width, &height, &x, &y) == 4) {
788dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch                Animation::Frame& frame(part.frames.editItemAt(frameIdx));
789dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch                frame.trimWidth = width;
790dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch                frame.trimHeight = height;
791dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch                frame.trimX = x;
792dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch                frame.trimY = y;
793dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch            } else {
794dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch                ALOGE("Error parsing trim.txt, line: %s", lineStr);
795dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch                break;
796dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch            }
797dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch        }
798dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch    }
799dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch
800d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch    // Create and initialize audioplay if there is a wav file in any of the animations.
801a917353da0ed6079d45487a8c96b892c5d754637Geoffrey Pitsch    // Do it on a separate thread so we don't hold up the animation intro.
802a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch    if (partWithAudio != NULL) {
803d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch        ALOGD("found audio.wav, creating playback engine");
804a917353da0ed6079d45487a8c96b892c5d754637Geoffrey Pitsch        mInitAudioThread = new InitAudioThread(partWithAudio->audioData,
805a917353da0ed6079d45487a8c96b892c5d754637Geoffrey Pitsch                                               partWithAudio->audioLength);
806a917353da0ed6079d45487a8c96b892c5d754637Geoffrey Pitsch        mInitAudioThread->run("BootAnimation::InitAudioThread", PRIORITY_NORMAL);
807d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch    }
808d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch
809dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch    zip->endIteration(cookie);
810afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath
81139218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    return true;
81239218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy}
81339218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy
81439218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyybool BootAnimation::movie()
81539218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy{
81639218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    Animation* animation = loadAnimation(mZipFileName);
81739218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    if (animation == NULL)
81839218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy        return false;
81939218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy
8209748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    bool anyPartHasClock = false;
8219748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    for (size_t i=0; i < animation->parts.size(); i++) {
8220e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi        if(validClock(animation->parts[i])) {
8239748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi            anyPartHasClock = true;
8249748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi            break;
8259748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        }
8269748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    }
8279748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    if (!anyPartHasClock) {
8289748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        mClockEnabled = false;
8299748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    }
8309748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi
831271674930a1f9020a291827a8ecb6ab68782c4faSai Kiran Korwar    // Check if npot textures are supported
832271674930a1f9020a291827a8ecb6ab68782c4faSai Kiran Korwar    mUseNpotTextures = false;
833271674930a1f9020a291827a8ecb6ab68782c4faSai Kiran Korwar    String8 gl_extensions;
834271674930a1f9020a291827a8ecb6ab68782c4faSai Kiran Korwar    const char* exts = reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS));
835271674930a1f9020a291827a8ecb6ab68782c4faSai Kiran Korwar    if (!exts) {
836271674930a1f9020a291827a8ecb6ab68782c4faSai Kiran Korwar        glGetError();
837271674930a1f9020a291827a8ecb6ab68782c4faSai Kiran Korwar    } else {
838271674930a1f9020a291827a8ecb6ab68782c4faSai Kiran Korwar        gl_extensions.setTo(exts);
839271674930a1f9020a291827a8ecb6ab68782c4faSai Kiran Korwar        if ((gl_extensions.find("GL_ARB_texture_non_power_of_two") != -1) ||
840271674930a1f9020a291827a8ecb6ab68782c4faSai Kiran Korwar            (gl_extensions.find("GL_OES_texture_npot") != -1)) {
841271674930a1f9020a291827a8ecb6ab68782c4faSai Kiran Korwar            mUseNpotTextures = true;
842271674930a1f9020a291827a8ecb6ab68782c4faSai Kiran Korwar        }
843271674930a1f9020a291827a8ecb6ab68782c4faSai Kiran Korwar    }
844271674930a1f9020a291827a8ecb6ab68782c4faSai Kiran Korwar
845a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi    // Blend required to draw time on top of animation frames.
846a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
847a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    glShadeModel(GL_FLAT);
848a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    glDisable(GL_DITHER);
849a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    glDisable(GL_SCISSOR_TEST);
850a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    glDisable(GL_BLEND);
851a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
852a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    glBindTexture(GL_TEXTURE_2D, 0);
853a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    glEnable(GL_TEXTURE_2D);
854a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
855a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
856a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
857a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
858a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
859a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
8600e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi    bool clockFontInitialized = false;
861a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi    if (mClockEnabled) {
8620e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi        clockFontInitialized =
8630e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi            (initFont(&animation->clockFont, CLOCK_FONT_ASSET) == NO_ERROR);
8640e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi        mClockEnabled = clockFontInitialized;
865a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi    }
866a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi
8679748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    if (mClockEnabled && !updateIsTimeAccurate()) {
8689748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        mTimeCheckThread = new TimeCheckThread(this);
8699748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        mTimeCheckThread->run("BootAnimation::TimeCheckThread", PRIORITY_NORMAL);
8709748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    }
8719748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi
87239218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    playAnimation(*animation);
8739748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi
874a917353da0ed6079d45487a8c96b892c5d754637Geoffrey Pitsch    if (mTimeCheckThread != nullptr) {
8759748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        mTimeCheckThread->requestExit();
876a917353da0ed6079d45487a8c96b892c5d754637Geoffrey Pitsch        mTimeCheckThread = nullptr;
877a917353da0ed6079d45487a8c96b892c5d754637Geoffrey Pitsch    }
878a917353da0ed6079d45487a8c96b892c5d754637Geoffrey Pitsch
879a90c54c90e1cb668cd74f218370f868763bbd009Wei Wang    // We should have joined mInitAudioThread thread in playAnimation
880a917353da0ed6079d45487a8c96b892c5d754637Geoffrey Pitsch    if (mInitAudioThread != nullptr) {
881a917353da0ed6079d45487a8c96b892c5d754637Geoffrey Pitsch        mInitAudioThread = nullptr;
8829748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    }
8839748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi
88439218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    releaseAnimation(animation);
88539218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy
8860e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi    if (clockFontInitialized) {
8870e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi        glDeleteTextures(1, &animation->clockFont.texture.name);
888815e51d76cc284f3ca59534d9f9372d3dd50f574Andriy Naborskyy    }
889815e51d76cc284f3ca59534d9f9372d3dd50f574Andriy Naborskyy
89039218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    return false;
89139218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy}
89239218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy
89339218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyybool BootAnimation::playAnimation(const Animation& animation)
89439218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy{
89539218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    const size_t pcount = animation.parts.size();
896a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    nsecs_t frameDuration = s2ns(1) / animation.fps;
897dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch    const int animationX = (mWidth - animation.width) / 2;
898dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch    const int animationY = (mHeight - animation.height) / 2;
8999f3020db15e50d07ee1ace42e47d90b076f2ce54Mathias Agopian
900d1794cdbb4183774ac68e9d445ca87835fbe6461Keun-young Park    ALOGD("%sAnimationShownTiming start time: %" PRId64 "ms", mShuttingDown ? "Shutdown" : "Boot",
901d1794cdbb4183774ac68e9d445ca87835fbe6461Keun-young Park            elapsedRealtime());
902afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath    for (size_t i=0 ; i<pcount ; i++) {
903a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian        const Animation::Part& part(animation.parts[i]);
904a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian        const size_t fcount = part.frames.size();
905a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian        glBindTexture(GL_TEXTURE_2D, 0);
906a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
90739218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy        // Handle animation package
90839218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy        if (part.animation != NULL) {
90939218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy            playAnimation(*part.animation);
91039218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy            if (exitPending())
91139218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy                break;
91239218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy            continue; //to next part
91339218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy        }
91439218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy
915a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian        for (int r=0 ; !part.count || r<part.count ; r++) {
916d3782b26b2026e60a8e0d4b967a156369f2a46f8Kevin Hester            // Exit any non playuntil complete parts immediately
917d3782b26b2026e60a8e0d4b967a156369f2a46f8Kevin Hester            if(exitPending() && !part.playUntilComplete)
918d3782b26b2026e60a8e0d4b967a156369f2a46f8Kevin Hester                break;
919d3782b26b2026e60a8e0d4b967a156369f2a46f8Kevin Hester
920ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood            // only play audio file the first time we animate the part
921290c4350edc66de5663e27c54e694c8ee8cf0e0eGeoffrey Pitsch            if (r == 0 && part.audioData && playSoundsAllowed()) {
922290c4350edc66de5663e27c54e694c8ee8cf0e0eGeoffrey Pitsch                ALOGD("playing clip for part%d, size=%d", (int) i, part.audioLength);
923a917353da0ed6079d45487a8c96b892c5d754637Geoffrey Pitsch                // Block until the audio engine is finished initializing.
924a917353da0ed6079d45487a8c96b892c5d754637Geoffrey Pitsch                if (mInitAudioThread != nullptr) {
925a917353da0ed6079d45487a8c96b892c5d754637Geoffrey Pitsch                    mInitAudioThread->join();
926a917353da0ed6079d45487a8c96b892c5d754637Geoffrey Pitsch                }
927290c4350edc66de5663e27c54e694c8ee8cf0e0eGeoffrey Pitsch                audioplay::playClip(part.audioData, part.audioLength);
928ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood            }
929ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood
930083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall            glClearColor(
931083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall                    part.backgroundColor[0],
932083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall                    part.backgroundColor[1],
933083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall                    part.backgroundColor[2],
934083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall                    1.0f);
935083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall
936afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath            for (size_t j=0 ; j<fcount && (!exitPending() || part.playUntilComplete) ; j++) {
937a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                const Animation::Frame& frame(part.frames[j]);
938db7dd2af93ae96e5749cfbe978c2695049d9d782Mathias Agopian                nsecs_t lastFrame = systemTime();
939a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
940a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                if (r > 0) {
941a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                    glBindTexture(GL_TEXTURE_2D, frame.tid);
942a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                } else {
943a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                    if (part.count != 1) {
944a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                        glGenTextures(1, &frame.tid);
945a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                        glBindTexture(GL_TEXTURE_2D, frame.tid);
946a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                        glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
947a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                        glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
948a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                    }
9490e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi                    int w, h;
9500e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi                    initTexture(frame.map, &w, &h);
951a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                }
952a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
953dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch                const int xc = animationX + frame.trimX;
954dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch                const int yc = animationY + frame.trimY;
955dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch                Region clearReg(Rect(mWidth, mHeight));
956dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch                clearReg.subtractSelf(Rect(xc, yc, xc+frame.trimWidth, yc+frame.trimHeight));
9579f3020db15e50d07ee1ace42e47d90b076f2ce54Mathias Agopian                if (!clearReg.isEmpty()) {
9589f3020db15e50d07ee1ace42e47d90b076f2ce54Mathias Agopian                    Region::const_iterator head(clearReg.begin());
9599f3020db15e50d07ee1ace42e47d90b076f2ce54Mathias Agopian                    Region::const_iterator tail(clearReg.end());
9609f3020db15e50d07ee1ace42e47d90b076f2ce54Mathias Agopian                    glEnable(GL_SCISSOR_TEST);
9619f3020db15e50d07ee1ace42e47d90b076f2ce54Mathias Agopian                    while (head != tail) {
962cfedceb8c180a2e176154d461659e0c3569dc931Andreas Gampe                        const Rect& r2(*head++);
963dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch                        glScissor(r2.left, mHeight - r2.bottom, r2.width(), r2.height());
9649f3020db15e50d07ee1ace42e47d90b076f2ce54Mathias Agopian                        glClear(GL_COLOR_BUFFER_BIT);
9659f3020db15e50d07ee1ace42e47d90b076f2ce54Mathias Agopian                    }
9669f3020db15e50d07ee1ace42e47d90b076f2ce54Mathias Agopian                    glDisable(GL_SCISSOR_TEST);
9679f3020db15e50d07ee1ace42e47d90b076f2ce54Mathias Agopian                }
968dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch                // specify the y center as ceiling((mHeight - frame.trimHeight) / 2)
969dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch                // which is equivalent to mHeight - (yc + frame.trimHeight)
970dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch                glDrawTexiOES(xc, mHeight - (yc + frame.trimHeight),
971dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch                              0, frame.trimWidth, frame.trimHeight);
9720e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi                if (mClockEnabled && mTimeIsAccurate && validClock(part)) {
9730e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi                    drawClock(animation.clockFont, part.clockPosX, part.clockPosY);
974a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi                }
975a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi
976a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                eglSwapBuffers(mDisplay, mSurface);
977a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
978a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                nsecs_t now = systemTime();
979a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                nsecs_t delay = frameDuration - (now - lastFrame);
980db7dd2af93ae96e5749cfbe978c2695049d9d782Mathias Agopian                //ALOGD("%lld, %lld", ns2ms(now - lastFrame), ns2ms(delay));
981a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                lastFrame = now;
982db7dd2af93ae96e5749cfbe978c2695049d9d782Mathias Agopian
983db7dd2af93ae96e5749cfbe978c2695049d9d782Mathias Agopian                if (delay > 0) {
984db7dd2af93ae96e5749cfbe978c2695049d9d782Mathias Agopian                    struct timespec spec;
985db7dd2af93ae96e5749cfbe978c2695049d9d782Mathias Agopian                    spec.tv_sec  = (now + delay) / 1000000000;
986db7dd2af93ae96e5749cfbe978c2695049d9d782Mathias Agopian                    spec.tv_nsec = (now + delay) % 1000000000;
987db7dd2af93ae96e5749cfbe978c2695049d9d782Mathias Agopian                    int err;
988db7dd2af93ae96e5749cfbe978c2695049d9d782Mathias Agopian                    do {
989db7dd2af93ae96e5749cfbe978c2695049d9d782Mathias Agopian                        err = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &spec, NULL);
990db7dd2af93ae96e5749cfbe978c2695049d9d782Mathias Agopian                    } while (err<0 && errno == EINTR);
991db7dd2af93ae96e5749cfbe978c2695049d9d782Mathias Agopian                }
992d3782b26b2026e60a8e0d4b967a156369f2a46f8Kevin Hester
993d3782b26b2026e60a8e0d4b967a156369f2a46f8Kevin Hester                checkExit();
994a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian            }
995d3782b26b2026e60a8e0d4b967a156369f2a46f8Kevin Hester
996a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian            usleep(part.pause * ns2us(frameDuration));
997d3782b26b2026e60a8e0d4b967a156369f2a46f8Kevin Hester
998d3782b26b2026e60a8e0d4b967a156369f2a46f8Kevin Hester            // For infinite parts, we've now played them at least once, so perhaps exit
999d3782b26b2026e60a8e0d4b967a156369f2a46f8Kevin Hester            if(exitPending() && !part.count)
1000d3782b26b2026e60a8e0d4b967a156369f2a46f8Kevin Hester                break;
1001a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian        }
1002a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
10032fb30fb68e9acb121a3e0dae0cd2790b3a7cc17dGeoffrey Pitsch    }
10042fb30fb68e9acb121a3e0dae0cd2790b3a7cc17dGeoffrey Pitsch
10052fb30fb68e9acb121a3e0dae0cd2790b3a7cc17dGeoffrey Pitsch    // Free textures created for looping parts now that the animation is done.
10062fb30fb68e9acb121a3e0dae0cd2790b3a7cc17dGeoffrey Pitsch    for (const Animation::Part& part : animation.parts) {
1007a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian        if (part.count != 1) {
10082fb30fb68e9acb121a3e0dae0cd2790b3a7cc17dGeoffrey Pitsch            const size_t fcount = part.frames.size();
10092fb30fb68e9acb121a3e0dae0cd2790b3a7cc17dGeoffrey Pitsch            for (size_t j = 0; j < fcount; j++) {
1010a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                const Animation::Frame& frame(part.frames[j]);
1011a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                glDeleteTextures(1, &frame.tid);
1012a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian            }
1013a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian        }
1014a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    }
1015d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch
1016d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch    // we've finally played everything we're going to play
1017d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch    audioplay::setPlaying(false);
1018d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch    audioplay::destroy();
1019d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch
102039218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    return true;
102139218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy}
1022a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
102339218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyyvoid BootAnimation::releaseAnimation(Animation* animation) const
102439218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy{
102539218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    for (Vector<Animation::Part>::iterator it = animation->parts.begin(),
102639218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy         e = animation->parts.end(); it != e; ++it) {
102739218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy        if (it->animation)
102839218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy            releaseAnimation(it->animation);
102939218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    }
103039218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    if (animation->zip)
103139218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy        delete animation->zip;
103239218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    delete animation;
1033a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian}
1034a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
103539218ba26d5bb8646f04273f2c3731598721c1daAndriy NaborskyyBootAnimation::Animation* BootAnimation::loadAnimation(const String8& fn)
103639218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy{
103739218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    if (mLoadedFiles.indexOf(fn) >= 0) {
103839218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy        ALOGE("File \"%s\" is already loaded. Cyclic ref is not allowed",
103939218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy            fn.string());
104039218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy        return NULL;
104139218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    }
104239218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    ZipFileRO *zip = ZipFileRO::open(fn);
104339218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    if (zip == NULL) {
104439218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy        ALOGE("Failed to open animation zip \"%s\": %s",
104539218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy            fn.string(), strerror(errno));
104639218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy        return NULL;
1047a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi    }
1048a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi
104939218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    Animation *animation =  new Animation;
105039218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    animation->fileName = fn;
105139218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    animation->zip = zip;
10520e3d2ab6d2988a1ae70d13d6d77a0f8109eb66e1Damien Bargiacchi    animation->clockFont.map = nullptr;
105339218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    mLoadedFiles.add(animation->fileName);
105439218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy
105539218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    parseAnimationDesc(*animation);
1056a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch    if (!preloadZip(*animation)) {
1057a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch        return NULL;
1058a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch    }
1059a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch
1060a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
106139218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    mLoadedFiles.remove(fn);
106239218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    return animation;
106339218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy}
10649748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi
1065290c4350edc66de5663e27c54e694c8ee8cf0e0eGeoffrey Pitschbool BootAnimation::playSoundsAllowed() const {
1066290c4350edc66de5663e27c54e694c8ee8cf0e0eGeoffrey Pitsch    // Only play sounds for system boots, not runtime restarts.
1067290c4350edc66de5663e27c54e694c8ee8cf0e0eGeoffrey Pitsch    if (!mSystemBoot) {
1068290c4350edc66de5663e27c54e694c8ee8cf0e0eGeoffrey Pitsch        return false;
1069290c4350edc66de5663e27c54e694c8ee8cf0e0eGeoffrey Pitsch    }
1070b593842063770f9e75c623a4bc7bb41b4c1830c6Keun-young Park    if (mShuttingDown) { // no audio while shutting down
1071b593842063770f9e75c623a4bc7bb41b4c1830c6Keun-young Park        return false;
1072b593842063770f9e75c623a4bc7bb41b4c1830c6Keun-young Park    }
1073290c4350edc66de5663e27c54e694c8ee8cf0e0eGeoffrey Pitsch    // Read the system property to see if we should play the sound.
1074290c4350edc66de5663e27c54e694c8ee8cf0e0eGeoffrey Pitsch    // If it's not present, default to allowed.
1075290c4350edc66de5663e27c54e694c8ee8cf0e0eGeoffrey Pitsch    if (!property_get_bool(PLAY_SOUND_PROP_NAME, 1)) {
1076290c4350edc66de5663e27c54e694c8ee8cf0e0eGeoffrey Pitsch        return false;
1077290c4350edc66de5663e27c54e694c8ee8cf0e0eGeoffrey Pitsch    }
1078290c4350edc66de5663e27c54e694c8ee8cf0e0eGeoffrey Pitsch
1079290c4350edc66de5663e27c54e694c8ee8cf0e0eGeoffrey Pitsch    // Don't play sounds if this is a reboot due to an error.
1080290c4350edc66de5663e27c54e694c8ee8cf0e0eGeoffrey Pitsch    char bootreason[PROPERTY_VALUE_MAX];
1081290c4350edc66de5663e27c54e694c8ee8cf0e0eGeoffrey Pitsch    if (property_get(BOOTREASON_PROP_NAME, bootreason, nullptr) > 0) {
1082290c4350edc66de5663e27c54e694c8ee8cf0e0eGeoffrey Pitsch        for (const auto& str : PLAY_SOUND_BOOTREASON_BLACKLIST) {
1083290c4350edc66de5663e27c54e694c8ee8cf0e0eGeoffrey Pitsch            if (strcasecmp(str.c_str(), bootreason) == 0) {
1084290c4350edc66de5663e27c54e694c8ee8cf0e0eGeoffrey Pitsch                return false;
1085290c4350edc66de5663e27c54e694c8ee8cf0e0eGeoffrey Pitsch            }
1086290c4350edc66de5663e27c54e694c8ee8cf0e0eGeoffrey Pitsch        }
1087290c4350edc66de5663e27c54e694c8ee8cf0e0eGeoffrey Pitsch    }
1088290c4350edc66de5663e27c54e694c8ee8cf0e0eGeoffrey Pitsch    return true;
1089290c4350edc66de5663e27c54e694c8ee8cf0e0eGeoffrey Pitsch}
1090290c4350edc66de5663e27c54e694c8ee8cf0e0eGeoffrey Pitsch
10919748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchibool BootAnimation::updateIsTimeAccurate() {
10929748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    static constexpr long long MAX_TIME_IN_PAST =   60000LL * 60LL * 24LL * 30LL;  // 30 days
10939748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    static constexpr long long MAX_TIME_IN_FUTURE = 60000LL * 90LL;  // 90 minutes
10949748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi
10959748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    if (mTimeIsAccurate) {
10969748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        return true;
10979748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    }
1098b593842063770f9e75c623a4bc7bb41b4c1830c6Keun-young Park    if (mShuttingDown) return true;
10999748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    struct stat statResult;
11009071db1d370573bad80f127898e34066f56c4e64Damien Bargiacchi
11019071db1d370573bad80f127898e34066f56c4e64Damien Bargiacchi    if(stat(TIME_FORMAT_12_HOUR_FLAG_FILE_PATH, &statResult) == 0) {
11029071db1d370573bad80f127898e34066f56c4e64Damien Bargiacchi        mTimeFormat12Hour = true;
11039071db1d370573bad80f127898e34066f56c4e64Damien Bargiacchi    }
11049071db1d370573bad80f127898e34066f56c4e64Damien Bargiacchi
11059748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    if(stat(ACCURATE_TIME_FLAG_FILE_PATH, &statResult) == 0) {
11069748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        mTimeIsAccurate = true;
11079748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        return true;
11089748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    }
11099748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi
11109748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    FILE* file = fopen(LAST_TIME_CHANGED_FILE_PATH, "r");
11119748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    if (file != NULL) {
11129748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi      long long lastChangedTime = 0;
11139748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi      fscanf(file, "%lld", &lastChangedTime);
11149748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi      fclose(file);
11159748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi      if (lastChangedTime > 0) {
11169748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        struct timespec now;
11179748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        clock_gettime(CLOCK_REALTIME, &now);
11189748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        // Match the Java timestamp format
11199748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        long long rtcNow = (now.tv_sec * 1000LL) + (now.tv_nsec / 1000000LL);
11209676281c4f0b34707e34cf9d2f5a866f1979c405Damien Bargiacchi        if (ACCURATE_TIME_EPOCH < rtcNow
11219676281c4f0b34707e34cf9d2f5a866f1979c405Damien Bargiacchi            && lastChangedTime > (rtcNow - MAX_TIME_IN_PAST)
11229676281c4f0b34707e34cf9d2f5a866f1979c405Damien Bargiacchi            && lastChangedTime < (rtcNow + MAX_TIME_IN_FUTURE)) {
11239748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi            mTimeIsAccurate = true;
11249748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        }
11259748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi      }
11269748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    }
11279748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi
11289748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    return mTimeIsAccurate;
11299748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi}
11309748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi
11319748086fe267e21d243a49df1775905094a28dd9Damien BargiacchiBootAnimation::TimeCheckThread::TimeCheckThread(BootAnimation* bootAnimation) : Thread(false),
11329748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    mInotifyFd(-1), mSystemWd(-1), mTimeWd(-1), mBootAnimation(bootAnimation) {}
11339748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi
11349748086fe267e21d243a49df1775905094a28dd9Damien BargiacchiBootAnimation::TimeCheckThread::~TimeCheckThread() {
11359748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    // mInotifyFd may be -1 but that's ok since we're not at risk of attempting to close a valid FD.
11369748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    close(mInotifyFd);
11379748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi}
11389748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi
11399748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchibool BootAnimation::TimeCheckThread::threadLoop() {
11409748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    bool shouldLoop = doThreadLoop() && !mBootAnimation->mTimeIsAccurate
11419748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        && mBootAnimation->mClockEnabled;
11429748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    if (!shouldLoop) {
11439748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        close(mInotifyFd);
11449748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        mInotifyFd = -1;
11459748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    }
11469748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    return shouldLoop;
11479748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi}
11489748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi
11499748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchibool BootAnimation::TimeCheckThread::doThreadLoop() {
11509748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    static constexpr int BUFF_LEN (10 * (sizeof(struct inotify_event) + NAME_MAX + 1));
11519748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi
11529748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    // Poll instead of doing a blocking read so the Thread can exit if requested.
11539748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    struct pollfd pfd = { mInotifyFd, POLLIN, 0 };
11549748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    ssize_t pollResult = poll(&pfd, 1, 1000);
11559748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi
11569748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    if (pollResult == 0) {
11579748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        return true;
11589748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    } else if (pollResult < 0) {
11599748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        ALOGE("Could not poll inotify events");
11609748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        return false;
11619748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    }
11629748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi
11639748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    char buff[BUFF_LEN] __attribute__ ((aligned(__alignof__(struct inotify_event))));;
11649748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    ssize_t length = read(mInotifyFd, buff, BUFF_LEN);
11659748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    if (length == 0) {
11669748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        return true;
11679748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    } else if (length < 0) {
11689748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        ALOGE("Could not read inotify events");
11699748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        return false;
11709748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    }
11719748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi
11729748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    const struct inotify_event *event;
11739748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    for (char* ptr = buff; ptr < buff + length; ptr += sizeof(struct inotify_event) + event->len) {
11749748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        event = (const struct inotify_event *) ptr;
11759748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        if (event->wd == mSystemWd && strcmp(SYSTEM_TIME_DIR_NAME, event->name) == 0) {
11769748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi            addTimeDirWatch();
11779748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        } else if (event->wd == mTimeWd && (strcmp(LAST_TIME_CHANGED_FILE_NAME, event->name) == 0
11789748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi                || strcmp(ACCURATE_TIME_FLAG_FILE_NAME, event->name) == 0)) {
11799748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi            return !mBootAnimation->updateIsTimeAccurate();
11809748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        }
11819748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    }
11829748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi
11839748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    return true;
11849748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi}
11859748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi
11869748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchivoid BootAnimation::TimeCheckThread::addTimeDirWatch() {
11879748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        mTimeWd = inotify_add_watch(mInotifyFd, SYSTEM_TIME_DIR_PATH,
11889748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi                IN_CLOSE_WRITE | IN_MOVED_TO | IN_ATTRIB);
11899748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        if (mTimeWd > 0) {
11909748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi            // No need to watch for the time directory to be created if it already exists
11919748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi            inotify_rm_watch(mInotifyFd, mSystemWd);
11929748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi            mSystemWd = -1;
11939748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        }
11949748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi}
11959748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi
11969748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchistatus_t BootAnimation::TimeCheckThread::readyToRun() {
11979748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    mInotifyFd = inotify_init();
11989748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    if (mInotifyFd < 0) {
11999748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        ALOGE("Could not initialize inotify fd");
12009748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        return NO_INIT;
12019748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    }
12029748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi
12039748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    mSystemWd = inotify_add_watch(mInotifyFd, SYSTEM_DATA_DIR_PATH, IN_CREATE | IN_ATTRIB);
12049748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    if (mSystemWd < 0) {
12059748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        close(mInotifyFd);
12069748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        mInotifyFd = -1;
12079748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        ALOGE("Could not add watch for %s", SYSTEM_DATA_DIR_PATH);
12089748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        return NO_INIT;
12099748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    }
12109748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi
12119748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    addTimeDirWatch();
12129748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi
12139748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    if (mBootAnimation->updateIsTimeAccurate()) {
12149748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        close(mInotifyFd);
12159748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        mInotifyFd = -1;
12169748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        return ALREADY_EXISTS;
12179748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    }
12189748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi
12199748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    return NO_ERROR;
12209748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi}
12219748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi
1222a917353da0ed6079d45487a8c96b892c5d754637Geoffrey PitschBootAnimation::InitAudioThread::InitAudioThread(uint8_t* exampleAudioData, int exampleAudioLength)
1223a917353da0ed6079d45487a8c96b892c5d754637Geoffrey Pitsch    : Thread(false),
1224a917353da0ed6079d45487a8c96b892c5d754637Geoffrey Pitsch      mExampleAudioData(exampleAudioData),
1225a917353da0ed6079d45487a8c96b892c5d754637Geoffrey Pitsch      mExampleAudioLength(exampleAudioLength) {}
1226a917353da0ed6079d45487a8c96b892c5d754637Geoffrey Pitsch
1227a917353da0ed6079d45487a8c96b892c5d754637Geoffrey Pitschbool BootAnimation::InitAudioThread::threadLoop() {
1228a917353da0ed6079d45487a8c96b892c5d754637Geoffrey Pitsch    audioplay::create(mExampleAudioData, mExampleAudioLength);
1229a917353da0ed6079d45487a8c96b892c5d754637Geoffrey Pitsch    // Exit immediately
1230a917353da0ed6079d45487a8c96b892c5d754637Geoffrey Pitsch    return false;
1231a917353da0ed6079d45487a8c96b892c5d754637Geoffrey Pitsch}
1232a917353da0ed6079d45487a8c96b892c5d754637Geoffrey Pitsch
12339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// ---------------------------------------------------------------------------
12349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
12369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project; // namespace android
1237