BootAnimation.cpp revision 290c4350edc66de5663e27c54e694c8ee8cf0e0e
19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2007 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
17ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood#define LOG_NDEBUG 0
18bc7261130a51dc9f3461d3970eee1b923bcbf193Mathias Agopian#define LOG_TAG "BootAnimation"
19bc7261130a51dc9f3461d3970eee1b923bcbf193Mathias Agopian
209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <stdint.h>
219748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi#include <sys/inotify.h>
229748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi#include <sys/poll.h>
239748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi#include <sys/stat.h>
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <sys/types.h>
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <math.h>
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <fcntl.h>
279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <utils/misc.h>
28b4d5a72691846bce5779cc3db056f09a5031d7ccMathias Agopian#include <signal.h>
29bb94f3107ea567ddf67bed4617c3bcbd602538dfElliott Hughes#include <time.h>
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
31bd9a08d318f94a3d0b2f8f9d7b16b10736d80c5cJason parks#include <cutils/properties.h>
32bd9a08d318f94a3d0b2f8f9d7b16b10736d80c5cJason parks
33b13b9bdad2baf6ad1ec2e56b6b7598fa20f55fc4Mathias Agopian#include <androidfw/AssetManager.h>
34ac31a3b8b09aba1c5ebc73f0cf65cac2210aa6b7Mathias Agopian#include <binder/IPCThreadState.h>
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <utils/Atomic.h>
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <utils/Errors.h>
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <utils/Log.h>
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <ui/PixelFormat.h>
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <ui/Rect.h>
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <ui/Region.h>
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <ui/DisplayInfo.h>
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
440b722fe9ce98d97dbcb6fefd170b85ab7037e528Jeff Brown#include <gui/ISurfaceComposer.h>
458335f1ccccedb6655d96d9d5b697a7f0938235ddMathias Agopian#include <gui/Surface.h>
468335f1ccccedb6655d96d9d5b697a7f0938235ddMathias Agopian#include <gui/SurfaceComposerClient.h>
47000479f9e325b4e426a67033abd92d47da412725Mathias Agopian
48cfedceb8c180a2e176154d461659e0c3569dc931Andreas Gampe// TODO: Fix Skia.
49cfedceb8c180a2e176154d461659e0c3569dc931Andreas Gampe#pragma GCC diagnostic push
50cfedceb8c180a2e176154d461659e0c3569dc931Andreas Gampe#pragma GCC diagnostic ignored "-Wunused-parameter"
51eece0dda56ae29fff6e9003df97594f6ac50b6e2Derek Sollenberger#include <SkBitmap.h>
52eece0dda56ae29fff6e9003df97594f6ac50b6e2Derek Sollenberger#include <SkStream.h>
53eece0dda56ae29fff6e9003df97594f6ac50b6e2Derek Sollenberger#include <SkImageDecoder.h>
54cfedceb8c180a2e176154d461659e0c3569dc931Andreas Gampe#pragma GCC diagnostic pop
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <GLES/gl.h>
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <GLES/glext.h>
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <EGL/eglext.h>
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "BootAnimation.h"
61d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch#include "audioplay.h"
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectnamespace android {
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
659748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchistatic const char OEM_BOOTANIMATION_FILE[] = "/oem/media/bootanimation.zip";
669748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchistatic const char SYSTEM_BOOTANIMATION_FILE[] = "/system/media/bootanimation.zip";
679748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchistatic const char SYSTEM_ENCRYPTED_BOOTANIMATION_FILE[] = "/system/media/bootanimation-encrypted.zip";
689748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchistatic const char SYSTEM_DATA_DIR_PATH[] = "/data/system";
699748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchistatic const char SYSTEM_TIME_DIR_NAME[] = "time";
709748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchistatic const char SYSTEM_TIME_DIR_PATH[] = "/data/system/time";
719748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchistatic const char LAST_TIME_CHANGED_FILE_NAME[] = "last_time_change";
729748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchistatic const char LAST_TIME_CHANGED_FILE_PATH[] = "/data/system/time/last_time_change";
739748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchistatic const char ACCURATE_TIME_FLAG_FILE_NAME[] = "time_is_accurate";
749748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchistatic const char ACCURATE_TIME_FLAG_FILE_PATH[] = "/data/system/time/time_is_accurate";
759676281c4f0b34707e34cf9d2f5a866f1979c405Damien Bargiacchi// Java timestamp format. Don't show the clock if the date is before 2000-01-01 00:00:00.
769676281c4f0b34707e34cf9d2f5a866f1979c405Damien Bargiacchistatic const long long ACCURATE_TIME_EPOCH = 946684800000;
779748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchistatic const char EXIT_PROP_NAME[] = "service.bootanim.exit";
78305087991d1b88d98c5e5e03fcf5a6a6e93ad356Geoffrey Pitschstatic const char PLAY_SOUND_PROP_NAME[] = "persist.sys.bootanim.play_sound";
79afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamathstatic const int ANIM_ENTRY_NAME_MAX = 256;
80290c4350edc66de5663e27c54e694c8ee8cf0e0eGeoffrey Pitschstatic const char BOOT_COMPLETED_PROP_NAME[] = "sys.boot_completed";
81290c4350edc66de5663e27c54e694c8ee8cf0e0eGeoffrey Pitschstatic const char BOOTREASON_PROP_NAME[] = "ro.boot.bootreason";
82290c4350edc66de5663e27c54e694c8ee8cf0e0eGeoffrey Pitsch// bootreasons list in "system/core/bootstat/bootstat.cpp".
83290c4350edc66de5663e27c54e694c8ee8cf0e0eGeoffrey Pitschstatic const std::vector<std::string> PLAY_SOUND_BOOTREASON_BLACKLIST {
84290c4350edc66de5663e27c54e694c8ee8cf0e0eGeoffrey Pitsch  "kernel_panic",
85290c4350edc66de5663e27c54e694c8ee8cf0e0eGeoffrey Pitsch  "Panic",
86290c4350edc66de5663e27c54e694c8ee8cf0e0eGeoffrey Pitsch  "Watchdog",
87290c4350edc66de5663e27c54e694c8ee8cf0e0eGeoffrey Pitsch};
88afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath
899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// ---------------------------------------------------------------------------
909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
919748086fe267e21d243a49df1775905094a28dd9Damien BargiacchiBootAnimation::BootAnimation() : Thread(false), mClockEnabled(true), mTimeIsAccurate(false),
929748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        mTimeCheckThread(NULL) {
93627e7b50be41e4fdee758a1bfad3a55de56b4e27Mathias Agopian    mSession = new SurfaceComposerClient();
94290c4350edc66de5663e27c54e694c8ee8cf0e0eGeoffrey Pitsch
95290c4350edc66de5663e27c54e694c8ee8cf0e0eGeoffrey Pitsch    // If the system has already booted, the animation is not being used for a boot.
96290c4350edc66de5663e27c54e694c8ee8cf0e0eGeoffrey Pitsch    mSystemBoot = !property_get_bool(BOOT_COMPLETED_PROP_NAME, 0);
979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
999748086fe267e21d243a49df1775905094a28dd9Damien BargiacchiBootAnimation::~BootAnimation() {}
1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectvoid BootAnimation::onFirstRef() {
102bc7261130a51dc9f3461d3970eee1b923bcbf193Mathias Agopian    status_t err = mSession->linkToComposerDeath(this);
1033762c311729fe9f3af085c14c5c1fb471d994c03Steve Block    ALOGE_IF(err, "linkToComposerDeath failed (%s) ", strerror(-err));
1048434c5369304e639efe8eab368ca410c589d87c2Mathias Agopian    if (err == NO_ERROR) {
105bc7261130a51dc9f3461d3970eee1b923bcbf193Mathias Agopian        run("BootAnimation", PRIORITY_DISPLAY);
106bc7261130a51dc9f3461d3970eee1b923bcbf193Mathias Agopian    }
1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
109bc7261130a51dc9f3461d3970eee1b923bcbf193Mathias Agopiansp<SurfaceComposerClient> BootAnimation::session() const {
1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return mSession;
1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
113bc7261130a51dc9f3461d3970eee1b923bcbf193Mathias Agopian
114afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamathvoid BootAnimation::binderDied(const wp<IBinder>&)
115bc7261130a51dc9f3461d3970eee1b923bcbf193Mathias Agopian{
116bc7261130a51dc9f3461d3970eee1b923bcbf193Mathias Agopian    // woah, surfaceflinger died!
1175baa3a62a97544669fba6d65a11c07f252e654ddSteve Block    ALOGD("SurfaceFlinger died, exiting...");
118bc7261130a51dc9f3461d3970eee1b923bcbf193Mathias Agopian
119bc7261130a51dc9f3461d3970eee1b923bcbf193Mathias Agopian    // calling requestExit() is not enough here because the Surface code
120bc7261130a51dc9f3461d3970eee1b923bcbf193Mathias Agopian    // might be blocked on a condition variable that will never be updated.
121bc7261130a51dc9f3461d3970eee1b923bcbf193Mathias Agopian    kill( getpid(), SIGKILL );
122bc7261130a51dc9f3461d3970eee1b923bcbf193Mathias Agopian    requestExit();
123d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch    audioplay::destroy();
124bc7261130a51dc9f3461d3970eee1b923bcbf193Mathias Agopian}
125bc7261130a51dc9f3461d3970eee1b923bcbf193Mathias Agopian
1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatus_t BootAnimation::initTexture(Texture* texture, AssetManager& assets,
1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        const char* name) {
1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    Asset* asset = assets.open(name, Asset::ACCESS_BUFFER);
129cfedceb8c180a2e176154d461659e0c3569dc931Andreas Gampe    if (asset == NULL)
1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return NO_INIT;
1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    SkBitmap bitmap;
1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    SkImageDecoder::DecodeMemory(asset->getBuffer(false), asset->getLength(),
13342a1d08df7d417fd4e67eabc91ff05ee77fd9995Mike Reed            &bitmap, kUnknown_SkColorType, SkImageDecoder::kDecodePixels_Mode);
1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    asset->close();
1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    delete asset;
1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // ensure we can call getPixels(). No need to call unlock, since the
1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // bitmap will go out of scope when we return from this method.
1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    bitmap.lockPixels();
1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    const int w = bitmap.width();
1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    const int h = bitmap.height();
1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    const void* p = bitmap.getPixels();
1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    GLint crop[4] = { 0, h, w, -h };
1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    texture->w = w;
1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    texture->h = h;
1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    glGenTextures(1, &texture->name);
1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    glBindTexture(GL_TEXTURE_2D, texture->name);
1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15242a1d08df7d417fd4e67eabc91ff05ee77fd9995Mike Reed    switch (bitmap.colorType()) {
15342a1d08df7d417fd4e67eabc91ff05ee77fd9995Mike Reed        case kAlpha_8_SkColorType:
1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, w, h, 0, GL_ALPHA,
1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    GL_UNSIGNED_BYTE, p);
1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            break;
15742a1d08df7d417fd4e67eabc91ff05ee77fd9995Mike Reed        case kARGB_4444_SkColorType:
1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA,
1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    GL_UNSIGNED_SHORT_4_4_4_4, p);
1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            break;
16142a1d08df7d417fd4e67eabc91ff05ee77fd9995Mike Reed        case kN32_SkColorType:
1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA,
1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    GL_UNSIGNED_BYTE, p);
1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            break;
16542a1d08df7d417fd4e67eabc91ff05ee77fd9995Mike Reed        case kRGB_565_SkColorType:
1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB,
1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    GL_UNSIGNED_SHORT_5_6_5, p);
1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            break;
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        default:
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            break;
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return NO_ERROR;
1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1810c1eeb3c8ab53954218d3b8f4be08ff21be3e985Mykola Kondratenkostatus_t BootAnimation::initTexture(const Animation::Frame& frame)
182a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian{
183a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    //StopWatch watch("blah");
184a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
185a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    SkBitmap bitmap;
1860c1eeb3c8ab53954218d3b8f4be08ff21be3e985Mykola Kondratenko    SkMemoryStream  stream(frame.map->getDataPtr(), frame.map->getDataLength());
1872b99e55ee3a0956a43a276f8018356ff9d08eafcMathias Agopian    SkImageDecoder* codec = SkImageDecoder::Factory(&stream);
188cfedceb8c180a2e176154d461659e0c3569dc931Andreas Gampe    if (codec != NULL) {
189c367d48c55e5a3fa0df14fd62889e4bb6b63cb01Elliott Hughes        codec->setDitherImage(false);
1902b99e55ee3a0956a43a276f8018356ff9d08eafcMathias Agopian        codec->decode(&stream, &bitmap,
19142a1d08df7d417fd4e67eabc91ff05ee77fd9995Mike Reed                kN32_SkColorType,
1922b99e55ee3a0956a43a276f8018356ff9d08eafcMathias Agopian                SkImageDecoder::kDecodePixels_Mode);
1932b99e55ee3a0956a43a276f8018356ff9d08eafcMathias Agopian        delete codec;
1942b99e55ee3a0956a43a276f8018356ff9d08eafcMathias Agopian    }
195a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
1960c1eeb3c8ab53954218d3b8f4be08ff21be3e985Mykola Kondratenko    // FileMap memory is never released until application exit.
1970c1eeb3c8ab53954218d3b8f4be08ff21be3e985Mykola Kondratenko    // Release it now as the texture is already loaded and the memory used for
1980c1eeb3c8ab53954218d3b8f4be08ff21be3e985Mykola Kondratenko    // the packed resource can be released.
199688ff4cf0f93d1a886437884f23874e5595d59a3Narayan Kamath    delete frame.map;
2000c1eeb3c8ab53954218d3b8f4be08ff21be3e985Mykola Kondratenko
201a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    // ensure we can call getPixels(). No need to call unlock, since the
202a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    // bitmap will go out of scope when we return from this method.
203a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    bitmap.lockPixels();
204a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
205a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    const int w = bitmap.width();
206a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    const int h = bitmap.height();
207a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    const void* p = bitmap.getPixels();
208a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
209a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    GLint crop[4] = { 0, h, w, -h };
210a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    int tw = 1 << (31 - __builtin_clz(w));
211a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    int th = 1 << (31 - __builtin_clz(h));
212a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    if (tw < w) tw <<= 1;
213a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    if (th < h) th <<= 1;
214a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
21542a1d08df7d417fd4e67eabc91ff05ee77fd9995Mike Reed    switch (bitmap.colorType()) {
21642a1d08df7d417fd4e67eabc91ff05ee77fd9995Mike Reed        case kN32_SkColorType:
217271674930a1f9020a291827a8ecb6ab68782c4faSai Kiran Korwar            if (!mUseNpotTextures && (tw != w || th != h)) {
218a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tw, th, 0, GL_RGBA,
219a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                        GL_UNSIGNED_BYTE, 0);
220a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                glTexSubImage2D(GL_TEXTURE_2D, 0,
221a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                        0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, p);
222a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian            } else {
223271674930a1f9020a291827a8ecb6ab68782c4faSai Kiran Korwar                glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA,
224a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                        GL_UNSIGNED_BYTE, p);
225a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian            }
226a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian            break;
227a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
22842a1d08df7d417fd4e67eabc91ff05ee77fd9995Mike Reed        case kRGB_565_SkColorType:
229271674930a1f9020a291827a8ecb6ab68782c4faSai Kiran Korwar            if (!mUseNpotTextures && (tw != w || th != h)) {
230a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tw, th, 0, GL_RGB,
231a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                        GL_UNSIGNED_SHORT_5_6_5, 0);
232a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                glTexSubImage2D(GL_TEXTURE_2D, 0,
233a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                        0, 0, w, h, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, p);
234a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian            } else {
235271674930a1f9020a291827a8ecb6ab68782c4faSai Kiran Korwar                glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB,
236a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                        GL_UNSIGNED_SHORT_5_6_5, p);
237a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian            }
238a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian            break;
239a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian        default:
240a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian            break;
241a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    }
242a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
243a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
244a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
245a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    return NO_ERROR;
246a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian}
247a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatus_t BootAnimation::readyToRun() {
2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mAssets.addDefaultAssets();
2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2510b722fe9ce98d97dbcb6fefd170b85ab7037e528Jeff Brown    sp<IBinder> dtoken(SurfaceComposerClient::getBuiltInDisplay(
2520b722fe9ce98d97dbcb6fefd170b85ab7037e528Jeff Brown            ISurfaceComposer::eDisplayIdMain));
2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    DisplayInfo dinfo;
2540b722fe9ce98d97dbcb6fefd170b85ab7037e528Jeff Brown    status_t status = SurfaceComposerClient::getDisplayInfo(dtoken, &dinfo);
2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (status)
2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return -1;
2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // create the native surface
2590b722fe9ce98d97dbcb6fefd170b85ab7037e528Jeff Brown    sp<SurfaceControl> control = session()->createSurface(String8("BootAnimation"),
2600b722fe9ce98d97dbcb6fefd170b85ab7037e528Jeff Brown            dinfo.w, dinfo.h, PIXEL_FORMAT_RGB_565);
261439863f3b3e725b5de1cba4940a21900369961c0Mathias Agopian
262439863f3b3e725b5de1cba4940a21900369961c0Mathias Agopian    SurfaceComposerClient::openGlobalTransaction();
26317f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian    control->setLayer(0x40000000);
264439863f3b3e725b5de1cba4940a21900369961c0Mathias Agopian    SurfaceComposerClient::closeGlobalTransaction();
2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
26617f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian    sp<Surface> s = control->getSurface();
26717f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian
2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // initialize opengl and egl
269738b9a45399485893fa9541fae19c47e01bc4af4Mathias Agopian    const EGLint attribs[] = {
2701b253b702a356619ae3c5e68ee92062b5305c5d7Mathias Agopian            EGL_RED_SIZE,   8,
2711b253b702a356619ae3c5e68ee92062b5305c5d7Mathias Agopian            EGL_GREEN_SIZE, 8,
2721b253b702a356619ae3c5e68ee92062b5305c5d7Mathias Agopian            EGL_BLUE_SIZE,  8,
273a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian            EGL_DEPTH_SIZE, 0,
274a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian            EGL_NONE
275738b9a45399485893fa9541fae19c47e01bc4af4Mathias Agopian    };
276cfedceb8c180a2e176154d461659e0c3569dc931Andreas Gampe    EGLint w, h;
2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    EGLint numConfigs;
2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    EGLConfig config;
2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    EGLSurface surface;
2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    EGLContext context;
281627e7b50be41e4fdee758a1bfad3a55de56b4e27Mathias Agopian
2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
283627e7b50be41e4fdee758a1bfad3a55de56b4e27Mathias Agopian
284627e7b50be41e4fdee758a1bfad3a55de56b4e27Mathias Agopian    eglInitialize(display, 0, 0);
2851b253b702a356619ae3c5e68ee92062b5305c5d7Mathias Agopian    eglChooseConfig(display, attribs, &config, 1, &numConfigs);
2861473f46cbc82aa6f0ba744cc896a36923823d55bMathias Agopian    surface = eglCreateWindowSurface(display, config, s.get(), NULL);
2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    context = eglCreateContext(display, config, NULL, NULL);
2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    eglQuerySurface(display, surface, EGL_WIDTH, &w);
2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    eglQuerySurface(display, surface, EGL_HEIGHT, &h);
290a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
291abac01052c1c40f8582fe9f010c2efe6013e25c6Mathias Agopian    if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE)
292abac01052c1c40f8582fe9f010c2efe6013e25c6Mathias Agopian        return NO_INIT;
293a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mDisplay = display;
2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mContext = context;
2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mSurface = surface;
2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mWidth = w;
2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mHeight = h;
29917f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian    mFlingerSurfaceControl = control;
3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mFlingerSurface = s;
3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
302c367d48c55e5a3fa0df14fd62889e4bb6b63cb01Elliott Hughes    // If the device has encryption turned on or is in process
303bd9a08d318f94a3d0b2f8f9d7b16b10736d80c5cJason parks    // of being encrypted we show the encrypted boot animation.
304bd9a08d318f94a3d0b2f8f9d7b16b10736d80c5cJason parks    char decrypt[PROPERTY_VALUE_MAX];
305bd9a08d318f94a3d0b2f8f9d7b16b10736d80c5cJason parks    property_get("vold.decrypt", decrypt, "");
306bd9a08d318f94a3d0b2f8f9d7b16b10736d80c5cJason parks
307bd9a08d318f94a3d0b2f8f9d7b16b10736d80c5cJason parks    bool encryptedAnimation = atoi(decrypt) != 0 || !strcmp("trigger_restart_min_framework", decrypt);
308bd9a08d318f94a3d0b2f8f9d7b16b10736d80c5cJason parks
30939218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    if (encryptedAnimation && (access(SYSTEM_ENCRYPTED_BOOTANIMATION_FILE, R_OK) == 0)) {
31039218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy        mZipFileName = SYSTEM_ENCRYPTED_BOOTANIMATION_FILE;
31139218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    }
31239218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    else if (access(OEM_BOOTANIMATION_FILE, R_OK) == 0) {
31339218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy        mZipFileName = OEM_BOOTANIMATION_FILE;
31439218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    }
31539218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    else if (access(SYSTEM_BOOTANIMATION_FILE, R_OK) == 0) {
31639218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy        mZipFileName = SYSTEM_BOOTANIMATION_FILE;
317bd9a08d318f94a3d0b2f8f9d7b16b10736d80c5cJason parks    }
3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return NO_ERROR;
3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
321a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopianbool BootAnimation::threadLoop()
322a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian{
323a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    bool r;
324afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath    // We have no bootanimation file, so we use the stock android logo
325afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath    // animation.
32639218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    if (mZipFileName.isEmpty()) {
327a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian        r = android();
328a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    } else {
329a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian        r = movie();
330a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    }
331a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
3329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
3339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    eglDestroyContext(mDisplay, mContext);
3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    eglDestroySurface(mDisplay, mSurface);
3356cf0db228ca275dfcda57d79c55e5fa306809632Mathias Agopian    mFlingerSurface.clear();
33617f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian    mFlingerSurfaceControl.clear();
337627e7b50be41e4fdee758a1bfad3a55de56b4e27Mathias Agopian    eglTerminate(mDisplay);
338627e7b50be41e4fdee758a1bfad3a55de56b4e27Mathias Agopian    IPCThreadState::self()->stopProcess();
3399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return r;
3409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
3419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
342a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopianbool BootAnimation::android()
343a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian{
344b2cf954cb47a73065aa4b7fed753877615614f41Mathias Agopian    initTexture(&mAndroid[0], mAssets, "images/android-logo-mask.png");
345b2cf954cb47a73065aa4b7fed753877615614f41Mathias Agopian    initTexture(&mAndroid[1], mAssets, "images/android-logo-shine.png");
3469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // clear screen
348a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    glShadeModel(GL_FLAT);
349b2cf954cb47a73065aa4b7fed753877615614f41Mathias Agopian    glDisable(GL_DITHER);
350b2cf954cb47a73065aa4b7fed753877615614f41Mathias Agopian    glDisable(GL_SCISSOR_TEST);
35159f19e48c1c043bb9debdc35d166e397e2125d33Mathias Agopian    glClearColor(0,0,0,1);
3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    glClear(GL_COLOR_BUFFER_BIT);
3539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    eglSwapBuffers(mDisplay, mSurface);
3549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
355a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    glEnable(GL_TEXTURE_2D);
356a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
357a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
358b2cf954cb47a73065aa4b7fed753877615614f41Mathias Agopian    const GLint xc = (mWidth  - mAndroid[0].w) / 2;
359b2cf954cb47a73065aa4b7fed753877615614f41Mathias Agopian    const GLint yc = (mHeight - mAndroid[0].h) / 2;
360b2cf954cb47a73065aa4b7fed753877615614f41Mathias Agopian    const Rect updateRect(xc, yc, xc + mAndroid[0].w, yc + mAndroid[0].h);
3619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    glScissor(updateRect.left, mHeight - updateRect.bottom, updateRect.width(),
3639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            updateRect.height());
3649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
365b2cf954cb47a73065aa4b7fed753877615614f41Mathias Agopian    // Blend state
366b2cf954cb47a73065aa4b7fed753877615614f41Mathias Agopian    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
367b2cf954cb47a73065aa4b7fed753877615614f41Mathias Agopian    glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
368b2cf954cb47a73065aa4b7fed753877615614f41Mathias Agopian
3699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    const nsecs_t startTime = systemTime();
3709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    do {
3711379665abdb8330caf813fb77902914d1545bcd9Mathias Agopian        nsecs_t now = systemTime();
3721379665abdb8330caf813fb77902914d1545bcd9Mathias Agopian        double time = now - startTime;
373b2cf954cb47a73065aa4b7fed753877615614f41Mathias Agopian        float t = 4.0f * float(time / us2ns(16667)) / mAndroid[1].w;
374b2cf954cb47a73065aa4b7fed753877615614f41Mathias Agopian        GLint offset = (1 - (t - floorf(t))) * mAndroid[1].w;
375b2cf954cb47a73065aa4b7fed753877615614f41Mathias Agopian        GLint x = xc - offset;
3769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3778166864e42bc20c1544b2028e8dd65b90f29a0eaMathias Agopian        glDisable(GL_SCISSOR_TEST);
3788166864e42bc20c1544b2028e8dd65b90f29a0eaMathias Agopian        glClear(GL_COLOR_BUFFER_BIT);
3798166864e42bc20c1544b2028e8dd65b90f29a0eaMathias Agopian
3808166864e42bc20c1544b2028e8dd65b90f29a0eaMathias Agopian        glEnable(GL_SCISSOR_TEST);
3819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        glDisable(GL_BLEND);
3829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        glBindTexture(GL_TEXTURE_2D, mAndroid[1].name);
383b2cf954cb47a73065aa4b7fed753877615614f41Mathias Agopian        glDrawTexiOES(x,                 yc, 0, mAndroid[1].w, mAndroid[1].h);
384b2cf954cb47a73065aa4b7fed753877615614f41Mathias Agopian        glDrawTexiOES(x + mAndroid[1].w, yc, 0, mAndroid[1].w, mAndroid[1].h);
3859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
386b2cf954cb47a73065aa4b7fed753877615614f41Mathias Agopian        glEnable(GL_BLEND);
387b2cf954cb47a73065aa4b7fed753877615614f41Mathias Agopian        glBindTexture(GL_TEXTURE_2D, mAndroid[0].name);
388b2cf954cb47a73065aa4b7fed753877615614f41Mathias Agopian        glDrawTexiOES(xc, yc, 0, mAndroid[0].w, mAndroid[0].h);
3899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
390627e7b50be41e4fdee758a1bfad3a55de56b4e27Mathias Agopian        EGLBoolean res = eglSwapBuffers(mDisplay, mSurface);
391627e7b50be41e4fdee758a1bfad3a55de56b4e27Mathias Agopian        if (res == EGL_FALSE)
392627e7b50be41e4fdee758a1bfad3a55de56b4e27Mathias Agopian            break;
393627e7b50be41e4fdee758a1bfad3a55de56b4e27Mathias Agopian
3941379665abdb8330caf813fb77902914d1545bcd9Mathias Agopian        // 12fps: don't animate too fast to preserve CPU
3951379665abdb8330caf813fb77902914d1545bcd9Mathias Agopian        const nsecs_t sleepTime = 83333 - ns2us(systemTime() - now);
3961379665abdb8330caf813fb77902914d1545bcd9Mathias Agopian        if (sleepTime > 0)
397a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian            usleep(sleepTime);
398d3782b26b2026e60a8e0d4b967a156369f2a46f8Kevin Hester
399d3782b26b2026e60a8e0d4b967a156369f2a46f8Kevin Hester        checkExit();
4009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    } while (!exitPending());
4019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    glDeleteTextures(1, &mAndroid[0].name);
4039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    glDeleteTextures(1, &mAndroid[1].name);
4049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return false;
4059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
4069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
407a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
408d3782b26b2026e60a8e0d4b967a156369f2a46f8Kevin Hestervoid BootAnimation::checkExit() {
409d3782b26b2026e60a8e0d4b967a156369f2a46f8Kevin Hester    // Allow surface flinger to gracefully request shutdown
410d3782b26b2026e60a8e0d4b967a156369f2a46f8Kevin Hester    char value[PROPERTY_VALUE_MAX];
411d3782b26b2026e60a8e0d4b967a156369f2a46f8Kevin Hester    property_get(EXIT_PROP_NAME, value, "0");
412d3782b26b2026e60a8e0d4b967a156369f2a46f8Kevin Hester    int exitnow = atoi(value);
413d3782b26b2026e60a8e0d4b967a156369f2a46f8Kevin Hester    if (exitnow) {
414d3782b26b2026e60a8e0d4b967a156369f2a46f8Kevin Hester        requestExit();
415d3782b26b2026e60a8e0d4b967a156369f2a46f8Kevin Hester    }
416d3782b26b2026e60a8e0d4b967a156369f2a46f8Kevin Hester}
417d3782b26b2026e60a8e0d4b967a156369f2a46f8Kevin Hester
418083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall// Parse a color represented as an HTML-style 'RRGGBB' string: each pair of
419083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall// characters in str is a hex number in [0, 255], which are converted to
420083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall// floating point values in the range [0.0, 1.0] and placed in the
421083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall// corresponding elements of color.
422083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall//
423083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall// If the input string isn't valid, parseColor returns false and color is
424083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall// left unchanged.
425083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hallstatic bool parseColor(const char str[7], float color[3]) {
426083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall    float tmpColor[3];
427083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall    for (int i = 0; i < 3; i++) {
428083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall        int val = 0;
429083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall        for (int j = 0; j < 2; j++) {
430083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall            val *= 16;
431083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall            char c = str[2*i + j];
432083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall            if      (c >= '0' && c <= '9') val += c - '0';
433083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall            else if (c >= 'A' && c <= 'F') val += (c - 'A') + 10;
434083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall            else if (c >= 'a' && c <= 'f') val += (c - 'a') + 10;
435083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall            else                           return false;
436083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall        }
437083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall        tmpColor[i] = static_cast<float>(val) / 255.0f;
438083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall    }
439083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall    memcpy(color, tmpColor, sizeof(tmpColor));
440083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall    return true;
441083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall}
442083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall
44339218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy
44439218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyystatic bool readFile(ZipFileRO* zip, const char* name, String8& outString)
445a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian{
44639218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    ZipEntryRO entry = zip->findEntryByName(name);
447ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood    ALOGE_IF(!entry, "couldn't find %s", name);
448ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood    if (!entry) {
449afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath        return false;
450afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath    }
451a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
45239218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    FileMap* entryMap = zip->createEntryFileMap(entry);
45339218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    zip->releaseEntry(entry);
454ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood    ALOGE_IF(!entryMap, "entryMap is null");
455ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood    if (!entryMap) {
456a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian        return false;
457a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    }
458a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
459ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood    outString.setTo((char const*)entryMap->getDataPtr(), entryMap->getDataLength());
460688ff4cf0f93d1a886437884f23874e5595d59a3Narayan Kamath    delete entryMap;
461ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood    return true;
462ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood}
463ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood
464a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi// The time glyphs are stored in a single image of height 64 pixels. Each digit is 40 pixels wide,
465a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi// and the colon character is half that at 20 pixels. The glyph order is '0123456789:'.
466a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi// We render 24 hour time.
467a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchivoid BootAnimation::drawTime(const Texture& clockTex, const int yPos) {
468a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi    static constexpr char TIME_FORMAT[] = "%H:%M";
469a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi    static constexpr int TIME_LENGTH = sizeof(TIME_FORMAT);
470a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi
471a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi    static constexpr int DIGIT_HEIGHT = 64;
472a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi    static constexpr int DIGIT_WIDTH = 40;
473a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi    static constexpr int COLON_WIDTH = DIGIT_WIDTH / 2;
474a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi    static constexpr int TIME_WIDTH = (DIGIT_WIDTH * 4) + COLON_WIDTH;
475a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi
476a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi    if (clockTex.h < DIGIT_HEIGHT || clockTex.w < (10 * DIGIT_WIDTH + COLON_WIDTH)) {
477a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi        ALOGE("Clock texture is too small; abandoning boot animation clock");
478a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi        mClockEnabled = false;
479a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi        return;
480a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi    }
481a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi
482a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi    time_t rawtime;
483a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi    time(&rawtime);
484a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi    struct tm* timeInfo = localtime(&rawtime);
485a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi
486a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi    char timeBuff[TIME_LENGTH];
487a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi    size_t length = strftime(timeBuff, TIME_LENGTH, TIME_FORMAT, timeInfo);
488a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi
489a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi    if (length != TIME_LENGTH - 1) {
490a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi        ALOGE("Couldn't format time; abandoning boot animation clock");
491a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi        mClockEnabled = false;
492a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi        return;
493a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi    }
494a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi
495a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi    glEnable(GL_BLEND);  // Allow us to draw on top of the animation
496a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi    glBindTexture(GL_TEXTURE_2D, clockTex.name);
497a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi
498a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi    int xPos = (mWidth - TIME_WIDTH) / 2;
499a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi    int cropRect[4] = { 0, DIGIT_HEIGHT, DIGIT_WIDTH, -DIGIT_HEIGHT };
500a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi
501a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi    for (int i = 0; i < TIME_LENGTH - 1; i++) {
502a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi        char c = timeBuff[i];
503a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi        int width = DIGIT_WIDTH;
504a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi        int pos = c - '0';  // Position in the character list
505a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi        if (pos < 0 || pos > 10) {
506a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi            continue;
507a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi        }
508a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi        if (c == ':') {
509a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi            width = COLON_WIDTH;
510a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi        }
511a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi
512a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi        // Crop the texture to only the pixels in the current glyph
513a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi        int left = pos * DIGIT_WIDTH;
514a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi        cropRect[0] = left;
515a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi        cropRect[2] = width;
516a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi        glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, cropRect);
517a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi
518a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi        glDrawTexiOES(xPos, yPos, 0, width, DIGIT_HEIGHT);
519a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi
520a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi        xPos += width;
521a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi    }
522a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi
523a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi    glDisable(GL_BLEND);  // Return to the animation's default behaviour
524a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi    glBindTexture(GL_TEXTURE_2D, 0);
525a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi}
526a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi
52739218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyybool BootAnimation::parseAnimationDesc(Animation& animation)
528ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood{
529ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood    String8 desString;
530ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood
53139218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    if (!readFile(animation.zip, "desc.txt", desString)) {
532ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood        return false;
533ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood    }
534a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    char const* s = desString.string();
535a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
536a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    // Parse the description file
537a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    for (;;) {
538a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian        const char* endl = strstr(s, "\n");
539cfedceb8c180a2e176154d461659e0c3569dc931Andreas Gampe        if (endl == NULL) break;
540a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian        String8 line(s, endl - s);
541a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian        const char* l = line.string();
542a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi        int fps = 0;
543a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi        int width = 0;
544a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi        int height = 0;
545a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi        int count = 0;
546a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi        int pause = 0;
547a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi        int clockPosY = -1;
548afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath        char path[ANIM_ENTRY_NAME_MAX];
549083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall        char color[7] = "000000"; // default to black if unspecified
550083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall
551d3782b26b2026e60a8e0d4b967a156369f2a46f8Kevin Hester        char pathType;
552a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian        if (sscanf(l, "%d %d %d", &width, &height, &fps) == 3) {
553083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall            // ALOGD("> w=%d, h=%d, fps=%d", width, height, fps);
554a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian            animation.width = width;
555a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian            animation.height = height;
556a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian            animation.fps = fps;
557a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi        } else if (sscanf(l, " %c %d %d %s #%6s %d",
558a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi                          &pathType, &count, &pause, path, color, &clockPosY) >= 4) {
559a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi            // ALOGD("> type=%c, count=%d, pause=%d, path=%s, color=%s, clockPosY=%d", pathType, count, pause, path, color, clockPosY);
560a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian            Animation::Part part;
561d3782b26b2026e60a8e0d4b967a156369f2a46f8Kevin Hester            part.playUntilComplete = pathType == 'c';
562a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian            part.count = count;
563a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian            part.pause = pause;
564a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian            part.path = path;
565a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi            part.clockPosY = clockPosY;
566d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch            part.audioData = NULL;
56739218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy            part.animation = NULL;
568083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall            if (!parseColor(color, part.backgroundColor)) {
569083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall                ALOGE("> invalid color '#%s'", color);
570083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall                part.backgroundColor[0] = 0.0f;
571083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall                part.backgroundColor[1] = 0.0f;
572083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall                part.backgroundColor[2] = 0.0f;
573083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall            }
574a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian            animation.parts.add(part);
575a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian        }
57639218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy        else if (strcmp(l, "$SYSTEM") == 0) {
57739218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy            // ALOGD("> SYSTEM");
57839218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy            Animation::Part part;
57939218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy            part.playUntilComplete = false;
58039218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy            part.count = 1;
58139218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy            part.pause = 0;
582d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch            part.audioData = NULL;
58339218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy            part.animation = loadAnimation(String8(SYSTEM_BOOTANIMATION_FILE));
58439218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy            if (part.animation != NULL)
58539218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy                animation.parts.add(part);
58639218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy        }
587a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian        s = ++endl;
588a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    }
589a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
59039218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    return true;
59139218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy}
59239218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy
59339218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyybool BootAnimation::preloadZip(Animation& animation)
59439218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy{
595a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    // read all the data structures
596a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    const size_t pcount = animation.parts.size();
597afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath    void *cookie = NULL;
598dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch    ZipFileRO* zip = animation.zip;
599dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch    if (!zip->startIteration(&cookie)) {
600afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath        return false;
601afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath    }
602afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath
603a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch    Animation::Part* partWithAudio = NULL;
604afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath    ZipEntryRO entry;
605afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath    char name[ANIM_ENTRY_NAME_MAX];
606dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch    while ((entry = zip->nextEntry(cookie)) != NULL) {
607dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch        const int foundEntryName = zip->getEntryFileName(entry, name, ANIM_ENTRY_NAME_MAX);
608afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath        if (foundEntryName > ANIM_ENTRY_NAME_MAX || foundEntryName == -1) {
609afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath            ALOGE("Error fetching entry file name");
610afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath            continue;
611afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath        }
612afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath
613afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath        const String8 entryName(name);
614afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath        const String8 path(entryName.getPathDir());
615afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath        const String8 leaf(entryName.getPathLeaf());
616afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath        if (leaf.size() > 0) {
617dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch            for (size_t j = 0; j < pcount; j++) {
618afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath                if (path == animation.parts[j].path) {
6194600dd053dbdbd4b95f3b11057a1cc55b99f9c77Narayan Kamath                    uint16_t method;
620afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath                    // supports only stored png files
621dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch                    if (zip->getEntryInfo(entry, &method, NULL, NULL, NULL, NULL, NULL)) {
622afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath                        if (method == ZipFileRO::kCompressStored) {
623dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch                            FileMap* map = zip->createEntryFileMap(entry);
624afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath                            if (map) {
625afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath                                Animation::Part& part(animation.parts.editItemAt(j));
626ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood                                if (leaf == "audio.wav") {
627ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood                                    // a part may have at most one audio file
628d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch                                    part.audioData = (uint8_t *)map->getDataPtr();
629d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch                                    part.audioLength = map->getDataLength();
630a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch                                    partWithAudio = &part;
631dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch                                } else if (leaf == "trim.txt") {
632dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch                                    part.trimData.setTo((char const*)map->getDataPtr(),
633dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch                                                        map->getDataLength());
634ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood                                } else {
635ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood                                    Animation::Frame frame;
636ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood                                    frame.name = leaf;
637ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood                                    frame.map = map;
638dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch                                    frame.trimWidth = animation.width;
639dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch                                    frame.trimHeight = animation.height;
640dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch                                    frame.trimX = 0;
641dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch                                    frame.trimY = 0;
642ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood                                    part.frames.add(frame);
643ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood                                }
644a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                            }
645d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch                        } else {
646d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch                            ALOGE("bootanimation.zip is compressed; must be only stored");
647a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                        }
648a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                    }
649a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                }
650a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian            }
651a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian        }
652a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    }
653a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
654dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch    // If there is trimData present, override the positioning defaults.
655dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch    for (Animation::Part& part : animation.parts) {
656dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch        const char* trimDataStr = part.trimData.string();
657dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch        for (size_t frameIdx = 0; frameIdx < part.frames.size(); frameIdx++) {
658dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch            const char* endl = strstr(trimDataStr, "\n");
659dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch            // No more trimData for this part.
660dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch            if (endl == NULL) {
661dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch                break;
662dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch            }
663dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch            String8 line(trimDataStr, endl - trimDataStr);
664dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch            const char* lineStr = line.string();
665dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch            trimDataStr = ++endl;
666dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch            int width = 0, height = 0, x = 0, y = 0;
667dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch            if (sscanf(lineStr, "%dx%d+%d+%d", &width, &height, &x, &y) == 4) {
668dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch                Animation::Frame& frame(part.frames.editItemAt(frameIdx));
669dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch                frame.trimWidth = width;
670dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch                frame.trimHeight = height;
671dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch                frame.trimX = x;
672dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch                frame.trimY = y;
673dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch            } else {
674dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch                ALOGE("Error parsing trim.txt, line: %s", lineStr);
675dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch                break;
676dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch            }
677dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch        }
678dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch    }
679dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch
680d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch    // Create and initialize audioplay if there is a wav file in any of the animations.
681a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch    if (partWithAudio != NULL) {
682d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch        ALOGD("found audio.wav, creating playback engine");
683a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch        if (!audioplay::create(partWithAudio->audioData, partWithAudio->audioLength)) {
684a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch            return false;
685a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch        }
686d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch    }
687d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch
688dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch    zip->endIteration(cookie);
689afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath
69039218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    return true;
69139218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy}
69239218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy
69339218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyybool BootAnimation::movie()
69439218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy{
69539218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    Animation* animation = loadAnimation(mZipFileName);
69639218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    if (animation == NULL)
69739218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy        return false;
69839218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy
6999748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    bool anyPartHasClock = false;
7009748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    for (size_t i=0; i < animation->parts.size(); i++) {
7019748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        if(animation->parts[i].clockPosY >= 0) {
7029748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi            anyPartHasClock = true;
7039748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi            break;
7049748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        }
7059748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    }
7069748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    if (!anyPartHasClock) {
7079748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        mClockEnabled = false;
7089748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    }
7099748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi
710271674930a1f9020a291827a8ecb6ab68782c4faSai Kiran Korwar    // Check if npot textures are supported
711271674930a1f9020a291827a8ecb6ab68782c4faSai Kiran Korwar    mUseNpotTextures = false;
712271674930a1f9020a291827a8ecb6ab68782c4faSai Kiran Korwar    String8 gl_extensions;
713271674930a1f9020a291827a8ecb6ab68782c4faSai Kiran Korwar    const char* exts = reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS));
714271674930a1f9020a291827a8ecb6ab68782c4faSai Kiran Korwar    if (!exts) {
715271674930a1f9020a291827a8ecb6ab68782c4faSai Kiran Korwar        glGetError();
716271674930a1f9020a291827a8ecb6ab68782c4faSai Kiran Korwar    } else {
717271674930a1f9020a291827a8ecb6ab68782c4faSai Kiran Korwar        gl_extensions.setTo(exts);
718271674930a1f9020a291827a8ecb6ab68782c4faSai Kiran Korwar        if ((gl_extensions.find("GL_ARB_texture_non_power_of_two") != -1) ||
719271674930a1f9020a291827a8ecb6ab68782c4faSai Kiran Korwar            (gl_extensions.find("GL_OES_texture_npot") != -1)) {
720271674930a1f9020a291827a8ecb6ab68782c4faSai Kiran Korwar            mUseNpotTextures = true;
721271674930a1f9020a291827a8ecb6ab68782c4faSai Kiran Korwar        }
722271674930a1f9020a291827a8ecb6ab68782c4faSai Kiran Korwar    }
723271674930a1f9020a291827a8ecb6ab68782c4faSai Kiran Korwar
724a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi    // Blend required to draw time on top of animation frames.
725a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
726a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    glShadeModel(GL_FLAT);
727a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    glDisable(GL_DITHER);
728a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    glDisable(GL_SCISSOR_TEST);
729a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    glDisable(GL_BLEND);
730a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
731a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    glBindTexture(GL_TEXTURE_2D, 0);
732a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    glEnable(GL_TEXTURE_2D);
733a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
734a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
735a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
736a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
737a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
738a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
739a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi    bool clockTextureInitialized = false;
740a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi    if (mClockEnabled) {
741a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi        clockTextureInitialized = (initTexture(&mClock, mAssets, "images/clock64.png") == NO_ERROR);
742a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi        mClockEnabled = clockTextureInitialized;
743a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi    }
744a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi
7459748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    if (mClockEnabled && !updateIsTimeAccurate()) {
7469748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        mTimeCheckThread = new TimeCheckThread(this);
7479748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        mTimeCheckThread->run("BootAnimation::TimeCheckThread", PRIORITY_NORMAL);
7489748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    }
7499748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi
75039218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    playAnimation(*animation);
7519748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi
7529748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    if (mTimeCheckThread != NULL) {
7539748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        mTimeCheckThread->requestExit();
7549748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        mTimeCheckThread = NULL;
7559748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    }
7569748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi
75739218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    releaseAnimation(animation);
75839218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy
759815e51d76cc284f3ca59534d9f9372d3dd50f574Andriy Naborskyy    if (clockTextureInitialized) {
760815e51d76cc284f3ca59534d9f9372d3dd50f574Andriy Naborskyy        glDeleteTextures(1, &mClock.name);
761815e51d76cc284f3ca59534d9f9372d3dd50f574Andriy Naborskyy    }
762815e51d76cc284f3ca59534d9f9372d3dd50f574Andriy Naborskyy
76339218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    return false;
76439218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy}
76539218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy
76639218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyybool BootAnimation::playAnimation(const Animation& animation)
76739218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy{
76839218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    const size_t pcount = animation.parts.size();
769a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    nsecs_t frameDuration = s2ns(1) / animation.fps;
770dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch    const int animationX = (mWidth - animation.width) / 2;
771dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch    const int animationY = (mHeight - animation.height) / 2;
7729f3020db15e50d07ee1ace42e47d90b076f2ce54Mathias Agopian
773afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath    for (size_t i=0 ; i<pcount ; i++) {
774a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian        const Animation::Part& part(animation.parts[i]);
775a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian        const size_t fcount = part.frames.size();
776a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian        glBindTexture(GL_TEXTURE_2D, 0);
777a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
77839218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy        // Handle animation package
77939218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy        if (part.animation != NULL) {
78039218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy            playAnimation(*part.animation);
78139218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy            if (exitPending())
78239218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy                break;
78339218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy            continue; //to next part
78439218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy        }
78539218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy
786a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian        for (int r=0 ; !part.count || r<part.count ; r++) {
787d3782b26b2026e60a8e0d4b967a156369f2a46f8Kevin Hester            // Exit any non playuntil complete parts immediately
788d3782b26b2026e60a8e0d4b967a156369f2a46f8Kevin Hester            if(exitPending() && !part.playUntilComplete)
789d3782b26b2026e60a8e0d4b967a156369f2a46f8Kevin Hester                break;
790d3782b26b2026e60a8e0d4b967a156369f2a46f8Kevin Hester
791ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood            // only play audio file the first time we animate the part
792290c4350edc66de5663e27c54e694c8ee8cf0e0eGeoffrey Pitsch            if (r == 0 && part.audioData && playSoundsAllowed()) {
793290c4350edc66de5663e27c54e694c8ee8cf0e0eGeoffrey Pitsch                ALOGD("playing clip for part%d, size=%d", (int) i, part.audioLength);
794290c4350edc66de5663e27c54e694c8ee8cf0e0eGeoffrey Pitsch                audioplay::playClip(part.audioData, part.audioLength);
795ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood            }
796ebf9a0d8a888042c16ec0cb6dd8419f18038663fMike Lockwood
797083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall            glClearColor(
798083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall                    part.backgroundColor[0],
799083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall                    part.backgroundColor[1],
800083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall                    part.backgroundColor[2],
801083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall                    1.0f);
802083b84cf8880bb7f0d2c2dc1b45c7d610656dbd1Jesse Hall
803afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath            for (size_t j=0 ; j<fcount && (!exitPending() || part.playUntilComplete) ; j++) {
804a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                const Animation::Frame& frame(part.frames[j]);
805db7dd2af93ae96e5749cfbe978c2695049d9d782Mathias Agopian                nsecs_t lastFrame = systemTime();
806a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
807a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                if (r > 0) {
808a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                    glBindTexture(GL_TEXTURE_2D, frame.tid);
809a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                } else {
810a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                    if (part.count != 1) {
811a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                        glGenTextures(1, &frame.tid);
812a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                        glBindTexture(GL_TEXTURE_2D, frame.tid);
813a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                        glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
814a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                        glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
815a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                    }
8160c1eeb3c8ab53954218d3b8f4be08ff21be3e985Mykola Kondratenko                    initTexture(frame);
817a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                }
818a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
819dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch                const int xc = animationX + frame.trimX;
820dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch                const int yc = animationY + frame.trimY;
821dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch                Region clearReg(Rect(mWidth, mHeight));
822dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch                clearReg.subtractSelf(Rect(xc, yc, xc+frame.trimWidth, yc+frame.trimHeight));
8239f3020db15e50d07ee1ace42e47d90b076f2ce54Mathias Agopian                if (!clearReg.isEmpty()) {
8249f3020db15e50d07ee1ace42e47d90b076f2ce54Mathias Agopian                    Region::const_iterator head(clearReg.begin());
8259f3020db15e50d07ee1ace42e47d90b076f2ce54Mathias Agopian                    Region::const_iterator tail(clearReg.end());
8269f3020db15e50d07ee1ace42e47d90b076f2ce54Mathias Agopian                    glEnable(GL_SCISSOR_TEST);
8279f3020db15e50d07ee1ace42e47d90b076f2ce54Mathias Agopian                    while (head != tail) {
828cfedceb8c180a2e176154d461659e0c3569dc931Andreas Gampe                        const Rect& r2(*head++);
829dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch                        glScissor(r2.left, mHeight - r2.bottom, r2.width(), r2.height());
8309f3020db15e50d07ee1ace42e47d90b076f2ce54Mathias Agopian                        glClear(GL_COLOR_BUFFER_BIT);
8319f3020db15e50d07ee1ace42e47d90b076f2ce54Mathias Agopian                    }
8329f3020db15e50d07ee1ace42e47d90b076f2ce54Mathias Agopian                    glDisable(GL_SCISSOR_TEST);
8339f3020db15e50d07ee1ace42e47d90b076f2ce54Mathias Agopian                }
834dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch                // specify the y center as ceiling((mHeight - frame.trimHeight) / 2)
835dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch                // which is equivalent to mHeight - (yc + frame.trimHeight)
836dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch                glDrawTexiOES(xc, mHeight - (yc + frame.trimHeight),
837dd214a796f8b97070645226d6a61f8651f9e13a0Geoffrey Pitsch                              0, frame.trimWidth, frame.trimHeight);
8389748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi                if (mClockEnabled && mTimeIsAccurate && part.clockPosY >= 0) {
839a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi                    drawTime(mClock, part.clockPosY);
840a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi                }
841a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi
842a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                eglSwapBuffers(mDisplay, mSurface);
843a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
844a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                nsecs_t now = systemTime();
845a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                nsecs_t delay = frameDuration - (now - lastFrame);
846db7dd2af93ae96e5749cfbe978c2695049d9d782Mathias Agopian                //ALOGD("%lld, %lld", ns2ms(now - lastFrame), ns2ms(delay));
847a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                lastFrame = now;
848db7dd2af93ae96e5749cfbe978c2695049d9d782Mathias Agopian
849db7dd2af93ae96e5749cfbe978c2695049d9d782Mathias Agopian                if (delay > 0) {
850db7dd2af93ae96e5749cfbe978c2695049d9d782Mathias Agopian                    struct timespec spec;
851db7dd2af93ae96e5749cfbe978c2695049d9d782Mathias Agopian                    spec.tv_sec  = (now + delay) / 1000000000;
852db7dd2af93ae96e5749cfbe978c2695049d9d782Mathias Agopian                    spec.tv_nsec = (now + delay) % 1000000000;
853db7dd2af93ae96e5749cfbe978c2695049d9d782Mathias Agopian                    int err;
854db7dd2af93ae96e5749cfbe978c2695049d9d782Mathias Agopian                    do {
855db7dd2af93ae96e5749cfbe978c2695049d9d782Mathias Agopian                        err = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &spec, NULL);
856db7dd2af93ae96e5749cfbe978c2695049d9d782Mathias Agopian                    } while (err<0 && errno == EINTR);
857db7dd2af93ae96e5749cfbe978c2695049d9d782Mathias Agopian                }
858d3782b26b2026e60a8e0d4b967a156369f2a46f8Kevin Hester
859d3782b26b2026e60a8e0d4b967a156369f2a46f8Kevin Hester                checkExit();
860a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian            }
861d3782b26b2026e60a8e0d4b967a156369f2a46f8Kevin Hester
862a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian            usleep(part.pause * ns2us(frameDuration));
863d3782b26b2026e60a8e0d4b967a156369f2a46f8Kevin Hester
864d3782b26b2026e60a8e0d4b967a156369f2a46f8Kevin Hester            // For infinite parts, we've now played them at least once, so perhaps exit
865d3782b26b2026e60a8e0d4b967a156369f2a46f8Kevin Hester            if(exitPending() && !part.count)
866d3782b26b2026e60a8e0d4b967a156369f2a46f8Kevin Hester                break;
867a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian        }
868a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
8692fb30fb68e9acb121a3e0dae0cd2790b3a7cc17dGeoffrey Pitsch    }
8702fb30fb68e9acb121a3e0dae0cd2790b3a7cc17dGeoffrey Pitsch
8712fb30fb68e9acb121a3e0dae0cd2790b3a7cc17dGeoffrey Pitsch    // Free textures created for looping parts now that the animation is done.
8722fb30fb68e9acb121a3e0dae0cd2790b3a7cc17dGeoffrey Pitsch    for (const Animation::Part& part : animation.parts) {
873a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian        if (part.count != 1) {
8742fb30fb68e9acb121a3e0dae0cd2790b3a7cc17dGeoffrey Pitsch            const size_t fcount = part.frames.size();
8752fb30fb68e9acb121a3e0dae0cd2790b3a7cc17dGeoffrey Pitsch            for (size_t j = 0; j < fcount; j++) {
876a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                const Animation::Frame& frame(part.frames[j]);
877a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian                glDeleteTextures(1, &frame.tid);
878a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian            }
879a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian        }
880a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian    }
881d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch
882d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch    // we've finally played everything we're going to play
883d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch    audioplay::setPlaying(false);
884d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch    audioplay::destroy();
885d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch
88639218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    return true;
88739218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy}
888a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
88939218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyyvoid BootAnimation::releaseAnimation(Animation* animation) const
89039218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy{
89139218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    for (Vector<Animation::Part>::iterator it = animation->parts.begin(),
89239218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy         e = animation->parts.end(); it != e; ++it) {
89339218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy        if (it->animation)
89439218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy            releaseAnimation(it->animation);
89539218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    }
89639218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    if (animation->zip)
89739218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy        delete animation->zip;
89839218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    delete animation;
899a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian}
900a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
90139218ba26d5bb8646f04273f2c3731598721c1daAndriy NaborskyyBootAnimation::Animation* BootAnimation::loadAnimation(const String8& fn)
90239218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy{
90339218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    if (mLoadedFiles.indexOf(fn) >= 0) {
90439218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy        ALOGE("File \"%s\" is already loaded. Cyclic ref is not allowed",
90539218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy            fn.string());
90639218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy        return NULL;
90739218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    }
90839218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    ZipFileRO *zip = ZipFileRO::open(fn);
90939218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    if (zip == NULL) {
91039218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy        ALOGE("Failed to open animation zip \"%s\": %s",
91139218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy            fn.string(), strerror(errno));
91239218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy        return NULL;
913a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi    }
914a704b7d3444d218fe3b3f977fd242d2cd626058eDamien Bargiacchi
91539218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    Animation *animation =  new Animation;
91639218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    animation->fileName = fn;
91739218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    animation->zip = zip;
91839218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    mLoadedFiles.add(animation->fileName);
91939218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy
92039218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    parseAnimationDesc(*animation);
921a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch    if (!preloadZip(*animation)) {
922a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch        return NULL;
923a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch    }
924a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch
925a8826d67097b12cf9d6b14a7e32c0862f17b189aMathias Agopian
92639218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    mLoadedFiles.remove(fn);
92739218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy    return animation;
92839218ba26d5bb8646f04273f2c3731598721c1daAndriy Naborskyy}
9299748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi
930290c4350edc66de5663e27c54e694c8ee8cf0e0eGeoffrey Pitschbool BootAnimation::playSoundsAllowed() const {
931290c4350edc66de5663e27c54e694c8ee8cf0e0eGeoffrey Pitsch    // Only play sounds for system boots, not runtime restarts.
932290c4350edc66de5663e27c54e694c8ee8cf0e0eGeoffrey Pitsch    if (!mSystemBoot) {
933290c4350edc66de5663e27c54e694c8ee8cf0e0eGeoffrey Pitsch        return false;
934290c4350edc66de5663e27c54e694c8ee8cf0e0eGeoffrey Pitsch    }
935290c4350edc66de5663e27c54e694c8ee8cf0e0eGeoffrey Pitsch
936290c4350edc66de5663e27c54e694c8ee8cf0e0eGeoffrey Pitsch    // Read the system property to see if we should play the sound.
937290c4350edc66de5663e27c54e694c8ee8cf0e0eGeoffrey Pitsch    // If it's not present, default to allowed.
938290c4350edc66de5663e27c54e694c8ee8cf0e0eGeoffrey Pitsch    if (!property_get_bool(PLAY_SOUND_PROP_NAME, 1)) {
939290c4350edc66de5663e27c54e694c8ee8cf0e0eGeoffrey Pitsch        return false;
940290c4350edc66de5663e27c54e694c8ee8cf0e0eGeoffrey Pitsch    }
941290c4350edc66de5663e27c54e694c8ee8cf0e0eGeoffrey Pitsch
942290c4350edc66de5663e27c54e694c8ee8cf0e0eGeoffrey Pitsch    // Don't play sounds if this is a reboot due to an error.
943290c4350edc66de5663e27c54e694c8ee8cf0e0eGeoffrey Pitsch    char bootreason[PROPERTY_VALUE_MAX];
944290c4350edc66de5663e27c54e694c8ee8cf0e0eGeoffrey Pitsch    if (property_get(BOOTREASON_PROP_NAME, bootreason, nullptr) > 0) {
945290c4350edc66de5663e27c54e694c8ee8cf0e0eGeoffrey Pitsch        for (const auto& str : PLAY_SOUND_BOOTREASON_BLACKLIST) {
946290c4350edc66de5663e27c54e694c8ee8cf0e0eGeoffrey Pitsch            if (strcasecmp(str.c_str(), bootreason) == 0) {
947290c4350edc66de5663e27c54e694c8ee8cf0e0eGeoffrey Pitsch                return false;
948290c4350edc66de5663e27c54e694c8ee8cf0e0eGeoffrey Pitsch            }
949290c4350edc66de5663e27c54e694c8ee8cf0e0eGeoffrey Pitsch        }
950290c4350edc66de5663e27c54e694c8ee8cf0e0eGeoffrey Pitsch    }
951290c4350edc66de5663e27c54e694c8ee8cf0e0eGeoffrey Pitsch    return true;
952290c4350edc66de5663e27c54e694c8ee8cf0e0eGeoffrey Pitsch}
953290c4350edc66de5663e27c54e694c8ee8cf0e0eGeoffrey Pitsch
9549748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchibool BootAnimation::updateIsTimeAccurate() {
9559748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    static constexpr long long MAX_TIME_IN_PAST =   60000LL * 60LL * 24LL * 30LL;  // 30 days
9569748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    static constexpr long long MAX_TIME_IN_FUTURE = 60000LL * 90LL;  // 90 minutes
9579748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi
9589748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    if (mTimeIsAccurate) {
9599748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        return true;
9609748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    }
9619748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi
9629748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    struct stat statResult;
9639748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    if(stat(ACCURATE_TIME_FLAG_FILE_PATH, &statResult) == 0) {
9649748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        mTimeIsAccurate = true;
9659748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        return true;
9669748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    }
9679748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi
9689748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    FILE* file = fopen(LAST_TIME_CHANGED_FILE_PATH, "r");
9699748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    if (file != NULL) {
9709748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi      long long lastChangedTime = 0;
9719748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi      fscanf(file, "%lld", &lastChangedTime);
9729748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi      fclose(file);
9739748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi      if (lastChangedTime > 0) {
9749748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        struct timespec now;
9759748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        clock_gettime(CLOCK_REALTIME, &now);
9769748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        // Match the Java timestamp format
9779748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        long long rtcNow = (now.tv_sec * 1000LL) + (now.tv_nsec / 1000000LL);
9789676281c4f0b34707e34cf9d2f5a866f1979c405Damien Bargiacchi        if (ACCURATE_TIME_EPOCH < rtcNow
9799676281c4f0b34707e34cf9d2f5a866f1979c405Damien Bargiacchi            && lastChangedTime > (rtcNow - MAX_TIME_IN_PAST)
9809676281c4f0b34707e34cf9d2f5a866f1979c405Damien Bargiacchi            && lastChangedTime < (rtcNow + MAX_TIME_IN_FUTURE)) {
9819748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi            mTimeIsAccurate = true;
9829748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        }
9839748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi      }
9849748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    }
9859748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi
9869748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    return mTimeIsAccurate;
9879748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi}
9889748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi
9899748086fe267e21d243a49df1775905094a28dd9Damien BargiacchiBootAnimation::TimeCheckThread::TimeCheckThread(BootAnimation* bootAnimation) : Thread(false),
9909748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    mInotifyFd(-1), mSystemWd(-1), mTimeWd(-1), mBootAnimation(bootAnimation) {}
9919748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi
9929748086fe267e21d243a49df1775905094a28dd9Damien BargiacchiBootAnimation::TimeCheckThread::~TimeCheckThread() {
9939748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    // mInotifyFd may be -1 but that's ok since we're not at risk of attempting to close a valid FD.
9949748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    close(mInotifyFd);
9959748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi}
9969748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi
9979748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchibool BootAnimation::TimeCheckThread::threadLoop() {
9989748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    bool shouldLoop = doThreadLoop() && !mBootAnimation->mTimeIsAccurate
9999748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        && mBootAnimation->mClockEnabled;
10009748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    if (!shouldLoop) {
10019748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        close(mInotifyFd);
10029748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        mInotifyFd = -1;
10039748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    }
10049748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    return shouldLoop;
10059748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi}
10069748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi
10079748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchibool BootAnimation::TimeCheckThread::doThreadLoop() {
10089748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    static constexpr int BUFF_LEN (10 * (sizeof(struct inotify_event) + NAME_MAX + 1));
10099748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi
10109748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    // Poll instead of doing a blocking read so the Thread can exit if requested.
10119748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    struct pollfd pfd = { mInotifyFd, POLLIN, 0 };
10129748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    ssize_t pollResult = poll(&pfd, 1, 1000);
10139748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi
10149748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    if (pollResult == 0) {
10159748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        return true;
10169748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    } else if (pollResult < 0) {
10179748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        ALOGE("Could not poll inotify events");
10189748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        return false;
10199748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    }
10209748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi
10219748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    char buff[BUFF_LEN] __attribute__ ((aligned(__alignof__(struct inotify_event))));;
10229748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    ssize_t length = read(mInotifyFd, buff, BUFF_LEN);
10239748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    if (length == 0) {
10249748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        return true;
10259748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    } else if (length < 0) {
10269748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        ALOGE("Could not read inotify events");
10279748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        return false;
10289748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    }
10299748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi
10309748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    const struct inotify_event *event;
10319748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    for (char* ptr = buff; ptr < buff + length; ptr += sizeof(struct inotify_event) + event->len) {
10329748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        event = (const struct inotify_event *) ptr;
10339748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        if (event->wd == mSystemWd && strcmp(SYSTEM_TIME_DIR_NAME, event->name) == 0) {
10349748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi            addTimeDirWatch();
10359748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        } else if (event->wd == mTimeWd && (strcmp(LAST_TIME_CHANGED_FILE_NAME, event->name) == 0
10369748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi                || strcmp(ACCURATE_TIME_FLAG_FILE_NAME, event->name) == 0)) {
10379748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi            return !mBootAnimation->updateIsTimeAccurate();
10389748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        }
10399748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    }
10409748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi
10419748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    return true;
10429748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi}
10439748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi
10449748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchivoid BootAnimation::TimeCheckThread::addTimeDirWatch() {
10459748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        mTimeWd = inotify_add_watch(mInotifyFd, SYSTEM_TIME_DIR_PATH,
10469748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi                IN_CLOSE_WRITE | IN_MOVED_TO | IN_ATTRIB);
10479748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        if (mTimeWd > 0) {
10489748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi            // No need to watch for the time directory to be created if it already exists
10499748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi            inotify_rm_watch(mInotifyFd, mSystemWd);
10509748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi            mSystemWd = -1;
10519748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        }
10529748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi}
10539748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi
10549748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchistatus_t BootAnimation::TimeCheckThread::readyToRun() {
10559748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    mInotifyFd = inotify_init();
10569748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    if (mInotifyFd < 0) {
10579748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        ALOGE("Could not initialize inotify fd");
10589748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        return NO_INIT;
10599748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    }
10609748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi
10619748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    mSystemWd = inotify_add_watch(mInotifyFd, SYSTEM_DATA_DIR_PATH, IN_CREATE | IN_ATTRIB);
10629748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    if (mSystemWd < 0) {
10639748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        close(mInotifyFd);
10649748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        mInotifyFd = -1;
10659748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        ALOGE("Could not add watch for %s", SYSTEM_DATA_DIR_PATH);
10669748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        return NO_INIT;
10679748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    }
10689748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi
10699748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    addTimeDirWatch();
10709748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi
10719748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    if (mBootAnimation->updateIsTimeAccurate()) {
10729748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        close(mInotifyFd);
10739748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        mInotifyFd = -1;
10749748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi        return ALREADY_EXISTS;
10759748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    }
10769748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi
10779748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi    return NO_ERROR;
10789748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi}
10799748086fe267e21d243a49df1775905094a28dd9Damien Bargiacchi
10809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// ---------------------------------------------------------------------------
10819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
10839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project; // namespace android
1084