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

Commit c814f965 authored by Mathias Agopian's avatar Mathias Agopian Committed by Android Git Automerger
Browse files

am beabe75a: Merge changes I1f7c4535,I741c68a2 into gingerbread

Merge commit 'beabe75a842d521b005999460d3a6361ab32108e' into gingerbread-plus-aosp

* commit 'beabe75a842d521b005999460d3a6361ab32108e':
  simple test app for screen capture API
  add support for [1974164] Be able to take a screen shot on the device
parents afb309d5 8405dff6
Loading
Loading
Loading
Loading
+9 −1
Original line number Diff line number Diff line
@@ -110,6 +110,13 @@ public:
     */
    virtual void bootFinished() = 0;

    /* Capture the specified screen. requires READ_FRAME_BUFFER permission
     * This function will fail if there is a secure window on screen.
     */
    virtual status_t captureScreen(DisplayID dpy,
            sp<IMemoryHeap>* heap,
            uint32_t* width, uint32_t* height, PixelFormat* format) = 0;

    /* Signal surfaceflinger that there might be some work to do
     * This is an ASYNCHRONOUS call.
     */
@@ -133,7 +140,8 @@ public:
        SET_ORIENTATION,
        FREEZE_DISPLAY,
        UNFREEZE_DISPLAY,
        SIGNAL
        SIGNAL,
        CAPTURE_SCREEN
    };

    virtual status_t    onTransact( uint32_t code,
+28 −0
Original line number Diff line number Diff line
@@ -124,6 +124,21 @@ public:
        remote()->transact(BnSurfaceComposer::BOOT_FINISHED, data, &reply);
    }

    virtual status_t captureScreen(DisplayID dpy,
            sp<IMemoryHeap>* heap,
            uint32_t* width, uint32_t* height, PixelFormat* format)
    {
        Parcel data, reply;
        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
        data.writeInt32(dpy);
        remote()->transact(BnSurfaceComposer::CAPTURE_SCREEN, data, &reply);
        *heap = interface_cast<IMemoryHeap>(reply.readStrongBinder());
        *width = reply.readInt32();
        *height = reply.readInt32();
        *format = reply.readInt32();
        return reply.readInt32();
    }

    virtual void signal() const
    {
        Parcel data, reply;
@@ -190,6 +205,19 @@ status_t BnSurfaceComposer::onTransact(
            sp<IBinder> b = getCblk()->asBinder();
            reply->writeStrongBinder(b);
        } break;
        case CAPTURE_SCREEN: {
            CHECK_INTERFACE(ISurfaceComposer, data, reply);
            DisplayID dpy = data.readInt32();
            sp<IMemoryHeap> heap;
            uint32_t w, h;
            PixelFormat f;
            status_t res = captureScreen(dpy, &heap, &w, &h, &f);
            reply->writeStrongBinder(heap->asBinder());
            reply->writeInt32(w);
            reply->writeInt32(h);
            reply->writeInt32(f);
            reply->writeInt32(res);
        } break;
        default:
            return BBinder::onTransact(code, data, reply, flags);
    }
+4 −0
Original line number Diff line number Diff line
@@ -92,6 +92,10 @@ void GLExtensions::initWithGLStrings(
        // hack for Adreno 200
        mHaveTextureExternal = true;
    }

    if (hasExtension("GL_OES_framebuffer_object")) {
        mHaveFramebufferObject = true;
    }
}

bool GLExtensions::hasExtension(char const* extension) const
+5 −0
Original line number Diff line number Diff line
@@ -39,6 +39,7 @@ class GLExtensions : public Singleton<GLExtensions>
    bool mHaveTextureExternal   : 1;
    bool mHaveNpot              : 1;
    bool mHaveDirectTexture     : 1;
    bool mHaveFramebufferObject : 1;

    String8 mVendor;
    String8 mRenderer;
@@ -66,6 +67,10 @@ public:
        return mHaveDirectTexture;
    }

    inline bool haveFramebufferObject() const {
        return mHaveFramebufferObject;
    }

    void initWithGLStrings(
            GLubyte const* vendor,
            GLubyte const* renderer,
+149 −0
Original line number Diff line number Diff line
@@ -75,6 +75,7 @@ SurfaceFlinger::SurfaceFlinger()
        mBootTime(systemTime()),
        mHardwareTest("android.permission.HARDWARE_TEST"),
        mAccessSurfaceFlinger("android.permission.ACCESS_SURFACE_FLINGER"),
        mReadFramebuffer("android.permission.READ_FRAME_BUFFER"),
        mDump("android.permission.DUMP"),
        mVisibleRegionsDirty(false),
        mDeferReleaseConsole(false),
@@ -1465,8 +1466,23 @@ status_t SurfaceFlinger::onTransact(
                        "can't access SurfaceFlinger pid=%d, uid=%d", pid, uid);
                return PERMISSION_DENIED;
            }
            break;
        }
        case CAPTURE_SCREEN:
        {
            // codes that require permission check
            IPCThreadState* ipc = IPCThreadState::self();
            const int pid = ipc->getCallingPid();
            const int uid = ipc->getCallingUid();
            if ((uid != AID_GRAPHICS) && !mReadFramebuffer.check(pid, uid)) {
                LOGE("Permission Denial: "
                        "can't read framebuffer pid=%d, uid=%d", pid, uid);
                return PERMISSION_DENIED;
            }
            break;
        }
    }

    status_t err = BnSurfaceComposer::onTransact(code, data, reply, flags);
    if (err == UNKNOWN_TRANSACTION || err == PERMISSION_DENIED) {
        CHECK_INTERFACE(ISurfaceComposer, data, reply);
@@ -1530,6 +1546,139 @@ status_t SurfaceFlinger::onTransact(

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

status_t SurfaceFlinger::captureScreen(DisplayID dpy,
        sp<IMemoryHeap>* heap,
        uint32_t* width, uint32_t* height, PixelFormat* format)
{
    // only one display supported for now
    if (UNLIKELY(uint32_t(dpy) >= DISPLAY_COUNT))
        return BAD_VALUE;

    if (!GLExtensions::getInstance().haveFramebufferObject())
        return INVALID_OPERATION;

    class MessageCaptureScreen : public MessageBase {
        SurfaceFlinger* flinger;
        DisplayID dpy;
        sp<IMemoryHeap>* heap;
        uint32_t* w;
        uint32_t* h;
        PixelFormat* f;
        status_t result;
    public:
        MessageCaptureScreen(SurfaceFlinger* flinger, DisplayID dpy,
                sp<IMemoryHeap>* heap, uint32_t* w, uint32_t* h, PixelFormat* f)
            : flinger(flinger), dpy(dpy),
              heap(heap), w(w), h(h), f(f), result(PERMISSION_DENIED)
        {
        }
        status_t getResult() const {
            return result;
        }
        virtual bool handler() {
            Mutex::Autolock _l(flinger->mStateLock);

            // if we have secure windows, never allow the screen capture
            if (flinger->mSecureFrameBuffer)
                return true;

            // make sure to clear all GL error flags
            while ( glGetError() != GL_NO_ERROR ) ;

            // get screen geometry
            const DisplayHardware& hw(flinger->graphicPlane(dpy).displayHardware());
            const uint32_t sw = hw.getWidth();
            const uint32_t sh = hw.getHeight();
            const Region screenBounds(hw.bounds());
            const size_t size = sw * sh * 4;

            // create a FBO
            GLuint name, tname;
            glGenRenderbuffersOES(1, &tname);
            glBindRenderbufferOES(GL_RENDERBUFFER_OES, tname);
            glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_RGBA8_OES, sw, sh);
            glGenFramebuffersOES(1, &name);
            glBindFramebufferOES(GL_FRAMEBUFFER_OES, name);
            glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES,
                    GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, tname);

            GLenum status = glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES);
            if (status == GL_FRAMEBUFFER_COMPLETE_OES) {

                // invert everything, b/c glReadPixel() below will invert the FB
                glMatrixMode(GL_PROJECTION);
                glPushMatrix();
                glLoadIdentity();
                glOrthof(0, sw, 0, sh, 0, 1);
                glMatrixMode(GL_MODELVIEW);

                // redraw the screen entirely...
                glClearColor(0,0,0,1);
                glClear(GL_COLOR_BUFFER_BIT);
                const Vector< sp<LayerBase> >& layers(
                        flinger->mVisibleLayersSortedByZ);
                const size_t count = layers.size();
                for (size_t i=0 ; i<count ; ++i) {
                    const sp<LayerBase>& layer(layers[i]);
                    if (!strcmp(layer->getTypeId(), "LayerBuffer")) {
                        // we cannot render LayerBuffer because it doens't
                        // use OpenGL, and won't show-up in the FBO.
                        continue;
                    }
                    layer->draw(screenBounds);
                }

                glMatrixMode(GL_PROJECTION);
                glPopMatrix();
                glMatrixMode(GL_MODELVIEW);

                // check for errors and return screen capture
                if (glGetError() != GL_NO_ERROR) {
                    // error while rendering
                    result = INVALID_OPERATION;
                } else {
                    // allocate shared memory large enough to hold the
                    // screen capture
                    sp<MemoryHeapBase> base(
                            new MemoryHeapBase(size, 0, "screen-capture") );
                    void* const ptr = base->getBase();
                    if (ptr) {
                        // capture the screen with glReadPixels()
                        glReadPixels(0, 0, sw, sh, GL_RGBA, GL_UNSIGNED_BYTE, ptr);
                        if (glGetError() == GL_NO_ERROR) {
                            *heap = base;
                            *w = sw;
                            *h = sh;
                            *f = PIXEL_FORMAT_RGBA_8888;
                            result = NO_ERROR;
                        }
                    } else {
                        result = NO_MEMORY;
                    }
                }
            } else {
                result = BAD_VALUE;
            }

            // release FBO resources
            glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0);
            glDeleteRenderbuffersOES(1, &tname);
            glDeleteFramebuffersOES(1, &name);
            return true;
        }
    };

    sp<MessageBase> msg = new MessageCaptureScreen(this,
            dpy, heap, width, height, format);
    status_t res = postMessageSync(msg);
    if (res == NO_ERROR) {
        res = static_cast<MessageCaptureScreen*>( msg.get() )->getResult();
    }
    return res;
}

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

sp<Layer> SurfaceFlinger::getLayer(const sp<ISurface>& sur) const
{
    sp<Layer> result;
Loading