Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 66d7617d authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Automerger Merge Worker
Browse files

Merge "Resize boot animation on display changes" into rvc-dev am: 569b3fbf

Change-Id: I5750da0f9831902b4f0b7e76c2618f606663eab5
parents f89b5579 569b3fbf
Loading
Loading
Loading
Loading
+150 −56
Original line number Diff line number Diff line
@@ -48,6 +48,7 @@
#include <ui/Region.h>

#include <gui/ISurfaceComposer.h>
#include <gui/DisplayEventReceiver.h>
#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>

@@ -113,8 +114,8 @@ static constexpr size_t TEXT_POS_LEN_MAX = 16;
// ---------------------------------------------------------------------------

BootAnimation::BootAnimation(sp<Callbacks> callbacks)
        : Thread(false), mClockEnabled(true), mTimeIsAccurate(false),
        mTimeFormat12Hour(false), mTimeCheckThread(nullptr), mCallbacks(callbacks) {
        : Thread(false), mClockEnabled(true), mTimeIsAccurate(false), mTimeFormat12Hour(false),
        mTimeCheckThread(nullptr), mCallbacks(callbacks), mLooper(new Looper(false)) {
    mSession = new SurfaceComposerClient();

    std::string powerCtl = android::base::GetProperty("sys.powerctl", "");
@@ -154,8 +155,7 @@ sp<SurfaceComposerClient> BootAnimation::session() const {
    return mSession;
}

void BootAnimation::binderDied(const wp<IBinder>&)
{
void BootAnimation::binderDied(const wp<IBinder>&) {
    // woah, surfaceflinger died!
    SLOGD("SurfaceFlinger died, exiting...");

@@ -219,8 +219,7 @@ status_t BootAnimation::initTexture(Texture* texture, AssetManager& assets,
    return NO_ERROR;
}

status_t BootAnimation::initTexture(FileMap* map, int* width, int* height)
{
status_t BootAnimation::initTexture(FileMap* map, int* width, int* height) {
    SkBitmap bitmap;
    sk_sp<SkData> data = SkData::MakeWithoutCopy(map->getDataPtr(),
            map->getDataLength());
@@ -278,6 +277,78 @@ status_t BootAnimation::initTexture(FileMap* map, int* width, int* height)
    return NO_ERROR;
}

class BootAnimation::DisplayEventCallback : public LooperCallback {
    BootAnimation* mBootAnimation;

public:
    DisplayEventCallback(BootAnimation* bootAnimation) {
        mBootAnimation = bootAnimation;
    }

    int handleEvent(int /* fd */, int events, void* /* data */) {
        if (events & (Looper::EVENT_ERROR | Looper::EVENT_HANGUP)) {
            ALOGE("Display event receiver pipe was closed or an error occurred. events=0x%x",
                    events);
            return 0; // remove the callback
        }

        if (!(events & Looper::EVENT_INPUT)) {
            ALOGW("Received spurious callback for unhandled poll event.  events=0x%x", events);
            return 1; // keep the callback
        }

        constexpr int kBufferSize = 100;
        DisplayEventReceiver::Event buffer[kBufferSize];
        ssize_t numEvents;
        do {
            numEvents = mBootAnimation->mDisplayEventReceiver->getEvents(buffer, kBufferSize);
            for (size_t i = 0; i < static_cast<size_t>(numEvents); i++) {
                const auto& event = buffer[i];
                if (event.header.type == DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG) {
                    SLOGV("Hotplug received");

                    if (!event.hotplug.connected) {
                        // ignore hotplug disconnect
                        continue;
                    }
                    auto token = SurfaceComposerClient::getPhysicalDisplayToken(
                        event.header.displayId);

                    if (token != mBootAnimation->mDisplayToken) {
                        // ignore hotplug of a secondary display
                        continue;
                    }

                    DisplayConfig displayConfig;
                    const status_t error = SurfaceComposerClient::getActiveDisplayConfig(
                        mBootAnimation->mDisplayToken, &displayConfig);
                    if (error != NO_ERROR) {
                        SLOGE("Can't get active display configuration.");
                    }
                    mBootAnimation->resizeSurface(displayConfig.resolution.getWidth(),
                        displayConfig.resolution.getHeight());
                }
            }
        } while (numEvents > 0);

        return 1;  // keep the callback
    }
};

EGLConfig BootAnimation::getEglConfig(const EGLDisplay& display) {
    const EGLint attribs[] = {
        EGL_RED_SIZE,   8,
        EGL_GREEN_SIZE, 8,
        EGL_BLUE_SIZE,  8,
        EGL_DEPTH_SIZE, 0,
        EGL_NONE
    };
    EGLint numConfigs;
    EGLConfig config;
    eglChooseConfig(display, attribs, &config, 1, &numConfigs);
    return config;
}

status_t BootAnimation::readyToRun() {
    mAssets.addDefaultAssets();

@@ -346,25 +417,12 @@ status_t BootAnimation::readyToRun() {
    sp<Surface> s = control->getSurface();

    // initialize opengl and egl
    const EGLint attribs[] = {
            EGL_RED_SIZE,   8,
            EGL_GREEN_SIZE, 8,
            EGL_BLUE_SIZE,  8,
            EGL_DEPTH_SIZE, 0,
            EGL_NONE
    };
    EGLint w, h;
    EGLint numConfigs;
    EGLConfig config;
    EGLSurface surface;
    EGLContext context;

    EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);

    eglInitialize(display, nullptr, nullptr);
    eglChooseConfig(display, attribs, &config, 1, &numConfigs);
    surface = eglCreateWindowSurface(display, config, s.get(), nullptr);
    context = eglCreateContext(display, config, nullptr, nullptr);
    EGLConfig config = getEglConfig(display);
    EGLSurface surface = eglCreateWindowSurface(display, config, s.get(), nullptr);
    EGLContext context = eglCreateContext(display, config, nullptr, nullptr);
    EGLint w, h;
    eglQuerySurface(display, surface, EGL_WIDTH, &w);
    eglQuerySurface(display, surface, EGL_HEIGHT, &h);

@@ -380,9 +438,46 @@ status_t BootAnimation::readyToRun() {
    mFlingerSurface = s;
    mTargetInset = -1;

    // Register a display event receiver
    mDisplayEventReceiver = std::make_unique<DisplayEventReceiver>();
    status_t status = mDisplayEventReceiver->initCheck();
    SLOGE_IF(status != NO_ERROR, "Initialization of DisplayEventReceiver failed with status: %d",
            status);
    mLooper->addFd(mDisplayEventReceiver->getFd(), 0, Looper::EVENT_INPUT,
            new DisplayEventCallback(this), nullptr);

    return NO_ERROR;
}

void BootAnimation::resizeSurface(int newWidth, int newHeight) {
    // We assume this function is called on the animation thread.
    if (newWidth == mWidth && newHeight == mHeight) {
        return;
    }
    SLOGV("Resizing the boot animation surface to %d %d", newWidth, newHeight);

    eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
    eglDestroySurface(mDisplay, mSurface);

    mWidth = newWidth;
    mHeight = newHeight;

    SurfaceComposerClient::Transaction t;
    t.setSize(mFlingerSurfaceControl, mWidth, mHeight);
    t.apply();

    EGLConfig config = getEglConfig(mDisplay);
    EGLSurface surface = eglCreateWindowSurface(mDisplay, config, mFlingerSurface.get(), nullptr);
    if (eglMakeCurrent(mDisplay, surface, surface, mContext) == EGL_FALSE) {
        SLOGE("Can't make the new surface current. Error %d", eglGetError());
        return;
    }
    glViewport(0, 0, mWidth, mHeight);
    glScissor(0, 0, mWidth, mHeight);

    mSurface = surface;
}

bool BootAnimation::preloadAnimation() {
    findBootAnimationFile();
    if (!mZipFileName.isEmpty()) {
@@ -443,15 +538,14 @@ void BootAnimation::findBootAnimationFile() {
    }
}

bool BootAnimation::threadLoop()
{
    bool r;
bool BootAnimation::threadLoop() {
    bool result;
    // We have no bootanimation file, so we use the stock android logo
    // animation.
    if (mZipFileName.isEmpty()) {
        r = android();
        result = android();
    } else {
        r = movie();
        result = movie();
    }

    eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
@@ -462,11 +556,10 @@ bool BootAnimation::threadLoop()
    eglTerminate(mDisplay);
    eglReleaseThread();
    IPCThreadState::self()->stopProcess();
    return r;
    return result;
}

bool BootAnimation::android()
{
bool BootAnimation::android() {
    SLOGD("%sAnimationShownTiming start time: %" PRId64 "ms", mShuttingDown ? "Shutdown" : "Boot",
            elapsedRealtime());
    initTexture(&mAndroid[0], mAssets, "images/android-logo-mask.png");
@@ -485,19 +578,19 @@ bool BootAnimation::android()
    glEnable(GL_TEXTURE_2D);
    glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);

    const GLint xc = (mWidth  - mAndroid[0].w) / 2;
    const GLint yc = (mHeight - mAndroid[0].h) / 2;
    const Rect updateRect(xc, yc, xc + mAndroid[0].w, yc + mAndroid[0].h);

    glScissor(updateRect.left, mHeight - updateRect.bottom, updateRect.width(),
            updateRect.height());

    // Blend state
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);

    const nsecs_t startTime = systemTime();
    do {
        processDisplayEvents();
        const GLint xc = (mWidth  - mAndroid[0].w) / 2;
        const GLint yc = (mHeight - mAndroid[0].h) / 2;
        const Rect updateRect(xc, yc, xc + mAndroid[0].w, yc + mAndroid[0].h);
        glScissor(updateRect.left, mHeight - updateRect.bottom, updateRect.width(),
                updateRect.height());

        nsecs_t now = systemTime();
        double time = now - startTime;
        float t = 4.0f * float(time / us2ns(16667)) / mAndroid[1].w;
@@ -612,8 +705,7 @@ static bool parseColor(const char str[7], float color[3]) {
}


static bool readFile(ZipFileRO* zip, const char* name, String8& outString)
{
static bool readFile(ZipFileRO* zip, const char* name, String8& outString) {
    ZipEntryRO entry = zip->findEntryByName(name);
    SLOGE_IF(!entry, "couldn't find %s", name);
    if (!entry) {
@@ -734,8 +826,7 @@ void BootAnimation::drawClock(const Font& font, const int xPos, const int yPos)
    drawText(out, font, false, &x, &y);
}

bool BootAnimation::parseAnimationDesc(Animation& animation)
{
bool BootAnimation::parseAnimationDesc(Animation& animation)  {
    String8 desString;

    if (!readFile(animation.zip, "desc.txt", desString)) {
@@ -802,8 +893,7 @@ bool BootAnimation::parseAnimationDesc(Animation& animation)
    return true;
}

bool BootAnimation::preloadZip(Animation& animation)
{
bool BootAnimation::preloadZip(Animation& animation) {
    // read all the data structures
    const size_t pcount = animation.parts.size();
    void *cookie = nullptr;
@@ -900,8 +990,7 @@ bool BootAnimation::preloadZip(Animation& animation)
    return true;
}

bool BootAnimation::movie()
{
bool BootAnimation::movie() {
    if (mAnimation == nullptr) {
        mAnimation = loadAnimation(mZipFileName);
    }
@@ -987,12 +1076,9 @@ bool BootAnimation::movie()
    return false;
}

bool BootAnimation::playAnimation(const Animation& animation)
{
bool BootAnimation::playAnimation(const Animation& animation) {
    const size_t pcount = animation.parts.size();
    nsecs_t frameDuration = s2ns(1) / animation.fps;
    const int animationX = (mWidth - animation.width) / 2;
    const int animationY = (mHeight - animation.height) / 2;

    SLOGD("%sAnimationShownTiming start time: %" PRId64 "ms", mShuttingDown ? "Shutdown" : "Boot",
            elapsedRealtime());
@@ -1023,6 +1109,11 @@ bool BootAnimation::playAnimation(const Animation& animation)
                    1.0f);

            for (size_t j=0 ; j<fcount && (!exitPending() || part.playUntilComplete) ; j++) {
                processDisplayEvents();

                const int animationX = (mWidth - animation.width) / 2;
                const int animationY = (mHeight - animation.height) / 2;

                const Animation::Frame& frame(part.frames[j]);
                nsecs_t lastFrame = systemTime();

@@ -1106,6 +1197,12 @@ bool BootAnimation::playAnimation(const Animation& animation)
    return true;
}

void BootAnimation::processDisplayEvents() {
    // This will poll mDisplayEventReceiver and if there are new events it'll call
    // displayEventCallback synchronously.
    mLooper->pollOnce(0);
}

void BootAnimation::handleViewport(nsecs_t timestep) {
    if (mShuttingDown || !mFlingerSurfaceControl || mTargetInset == 0) {
        return;
@@ -1148,8 +1245,7 @@ void BootAnimation::handleViewport(nsecs_t timestep) {
    mCurrentInset += delta;
}

void BootAnimation::releaseAnimation(Animation* animation) const
{
void BootAnimation::releaseAnimation(Animation* animation) const {
    for (Vector<Animation::Part>::iterator it = animation->parts.begin(),
         e = animation->parts.end(); it != e; ++it) {
        if (it->animation)
@@ -1160,8 +1256,7 @@ void BootAnimation::releaseAnimation(Animation* animation) const
    delete animation;
}

BootAnimation::Animation* BootAnimation::loadAnimation(const String8& fn)
{
BootAnimation::Animation* BootAnimation::loadAnimation(const String8& fn) {
    if (mLoadedFiles.indexOf(fn) >= 0) {
        SLOGE("File \"%s\" is already loaded. Cyclic ref is not allowed",
            fn.string());
@@ -1323,5 +1418,4 @@ status_t BootAnimation::TimeCheckThread::readyToRun() {

// ---------------------------------------------------------------------------

}
; // namespace android
} // namespace android
+12 −0
Original line number Diff line number Diff line
@@ -18,11 +18,14 @@
#define ANDROID_BOOTANIMATION_H

#include <vector>
#include <queue>

#include <stdint.h>
#include <sys/types.h>

#include <androidfw/AssetManager.h>
#include <gui/DisplayEventReceiver.h>
#include <utils/Looper.h>
#include <utils/Thread.h>
#include <binder/IBinder.h>

@@ -145,6 +148,11 @@ private:
        BootAnimation* mBootAnimation;
    };

    // Display event handling
    class DisplayEventCallback;
    int displayEventCallback(int fd, int events, void* data);
    void processDisplayEvents();

    status_t initTexture(Texture* texture, AssetManager& asset, const char* name);
    status_t initTexture(FileMap* map, int* width, int* height);
    status_t initFont(Font* font, const char* fallback);
@@ -161,6 +169,8 @@ private:
    void findBootAnimationFile();
    bool findBootAnimationFileInternal(const std::vector<std::string>& files);
    bool preloadAnimation();
    EGLConfig getEglConfig(const EGLDisplay&);
    void resizeSurface(int newWidth, int newHeight);

    void checkExit();

@@ -189,6 +199,8 @@ private:
    sp<TimeCheckThread> mTimeCheckThread = nullptr;
    sp<Callbacks> mCallbacks;
    Animation* mAnimation = nullptr;
    std::unique_ptr<DisplayEventReceiver> mDisplayEventReceiver;
    sp<Looper> mLooper;
};

// ---------------------------------------------------------------------------