Merge "DOC CHANGE: Fix bug in Testing doc" into gingerbread
diff --git a/include/surfaceflinger/ISurfaceComposer.h b/include/surfaceflinger/ISurfaceComposer.h
index 6533600..de447be 100644
--- a/include/surfaceflinger/ISurfaceComposer.h
+++ b/include/surfaceflinger/ISurfaceComposer.h
@@ -118,6 +118,9 @@
uint32_t* width, uint32_t* height, PixelFormat* format,
uint32_t reqWidth, uint32_t reqHeight) = 0;
+ virtual status_t turnElectronBeamOff(int32_t mode) = 0;
+ virtual status_t turnElectronBeamOn(int32_t mode) = 0;
+
/* Signal surfaceflinger that there might be some work to do
* This is an ASYNCHRONOUS call.
*/
@@ -142,7 +145,9 @@
FREEZE_DISPLAY,
UNFREEZE_DISPLAY,
SIGNAL,
- CAPTURE_SCREEN
+ CAPTURE_SCREEN,
+ TURN_ELECTRON_BEAM_OFF,
+ TURN_ELECTRON_BEAM_ON
};
virtual status_t onTransact( uint32_t code,
diff --git a/include/utils/ObbFile.h b/include/utils/ObbFile.h
index 5243f50..47559cd 100644
--- a/include/utils/ObbFile.h
+++ b/include/utils/ObbFile.h
@@ -27,6 +27,7 @@
// OBB flags (bit 0)
#define OBB_OVERLAY (1 << 0)
+#define OBB_SALTED (1 << 1)
class ObbFile : public RefBase {
protected:
@@ -70,6 +71,26 @@
mFlags = flags;
}
+ const unsigned char* getSalt(size_t* length) const {
+ if ((mFlags & OBB_SALTED) == 0) {
+ *length = 0;
+ return NULL;
+ }
+
+ *length = sizeof(mSalt);
+ return mSalt;
+ }
+
+ bool setSalt(const unsigned char* salt, size_t length) {
+ if (length != sizeof(mSalt)) {
+ return false;
+ }
+
+ memcpy(mSalt, salt, sizeof(mSalt));
+ mFlags |= OBB_SALTED;
+ return true;
+ }
+
bool isOverlay() {
return (mFlags & OBB_OVERLAY) == OBB_OVERLAY;
}
@@ -103,6 +124,12 @@
/* Flags for this OBB type. */
int32_t mFlags;
+ /* Whether the file is salted. */
+ bool mSalted;
+
+ /* The encryption salt. */
+ unsigned char mSalt[8];
+
const char* mFileName;
size_t mFileSize;
diff --git a/libs/surfaceflinger_client/ISurfaceComposer.cpp b/libs/surfaceflinger_client/ISurfaceComposer.cpp
index d676f5e..969ee79 100644
--- a/libs/surfaceflinger_client/ISurfaceComposer.cpp
+++ b/libs/surfaceflinger_client/ISurfaceComposer.cpp
@@ -142,6 +142,24 @@
return reply.readInt32();
}
+ virtual status_t turnElectronBeamOff(int32_t mode)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ data.writeInt32(mode);
+ remote()->transact(BnSurfaceComposer::TURN_ELECTRON_BEAM_OFF, data, &reply);
+ return reply.readInt32();
+ }
+
+ virtual status_t turnElectronBeamOn(int32_t mode)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ data.writeInt32(mode);
+ remote()->transact(BnSurfaceComposer::TURN_ELECTRON_BEAM_ON, data, &reply);
+ return reply.readInt32();
+ }
+
virtual void signal() const
{
Parcel data, reply;
@@ -224,6 +242,18 @@
reply->writeInt32(f);
reply->writeInt32(res);
} break;
+ case TURN_ELECTRON_BEAM_OFF: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ int32_t mode = data.readInt32();
+ status_t res = turnElectronBeamOff(mode);
+ reply->writeInt32(res);
+ }
+ case TURN_ELECTRON_BEAM_ON: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ int32_t mode = data.readInt32();
+ status_t res = turnElectronBeamOn(mode);
+ reply->writeInt32(res);
+ }
default:
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/libs/ui/EventHub.cpp b/libs/ui/EventHub.cpp
index c0be3a0..944731d 100644
--- a/libs/ui/EventHub.cpp
+++ b/libs/ui/EventHub.cpp
@@ -439,11 +439,10 @@
// Since mFDs[0] is used for inotify, we process regular events starting at index 1.
mInputDeviceIndex += 1;
if (mInputDeviceIndex >= mFDCount) {
- mInputDeviceIndex = 0;
break;
}
- const struct pollfd &pfd = mFDs[mInputDeviceIndex];
+ const struct pollfd& pfd = mFDs[mInputDeviceIndex];
if (pfd.revents & POLLIN) {
int32_t readSize = read(pfd.fd, mInputBufferData,
sizeof(struct input_event) * INPUT_BUFFER_SIZE);
@@ -460,11 +459,17 @@
}
}
+#if HAVE_INOTIFY
// readNotify() will modify mFDs and mFDCount, so this must be done after
// processing all other events.
if(mFDs[0].revents & POLLIN) {
readNotify(mFDs[0].fd);
+ mFDs[0].revents = 0;
+ continue; // report added or removed devices immediately
}
+#endif
+
+ mInputDeviceIndex = 0;
// Poll for events. Mind the wake lock dance!
// We hold a wake lock at all times except during poll(). This works due to some
@@ -482,7 +487,7 @@
if (pollResult <= 0) {
if (errno != EINTR) {
- LOGW("select failed (errno=%d)\n", errno);
+ LOGW("poll failed (errno=%d)\n", errno);
usleep(100000);
}
}
diff --git a/libs/utils/ObbFile.cpp b/libs/utils/ObbFile.cpp
index e170ab8..2c3724c 100644
--- a/libs/utils/ObbFile.cpp
+++ b/libs/utils/ObbFile.cpp
@@ -29,10 +29,11 @@
#define kFooterTagSize 8 /* last two 32-bit integers */
-#define kFooterMinSize 25 /* 32-bit signature version (4 bytes)
+#define kFooterMinSize 33 /* 32-bit signature version (4 bytes)
* 32-bit package version (4 bytes)
* 32-bit flags (4 bytes)
- * 32-bit package name size (4-bytes)
+ * 64-bit salt (8 bytes)
+ * 32-bit package name size (4 bytes)
* >=1-character package name (1 byte)
* 32-bit footer size (4 bytes)
* 32-bit footer marker (4 bytes)
@@ -47,8 +48,9 @@
/* offsets in version 1 of the header */
#define kPackageVersionOffset 4
#define kFlagsOffset 8
-#define kPackageNameLenOffset 12
-#define kPackageNameOffset 16
+#define kSaltOffset 12
+#define kPackageNameLenOffset 20
+#define kPackageNameOffset 24
/*
* TEMP_FAILURE_RETRY is defined by some, but not all, versions of
@@ -79,11 +81,12 @@
namespace android {
-ObbFile::ObbFile() :
- mPackageName(""),
- mVersion(-1),
- mFlags(0)
+ObbFile::ObbFile()
+ : mPackageName("")
+ , mVersion(-1)
+ , mFlags(0)
{
+ memset(mSalt, 0, sizeof(mSalt));
}
ObbFile::~ObbFile() {
@@ -192,7 +195,7 @@
#ifdef DEBUG
for (int i = 0; i < footerSize; ++i) {
- LOGI("char: 0x%02x", scanBuf[i]);
+ LOGI("char: 0x%02x\n", scanBuf[i]);
}
#endif
@@ -206,6 +209,8 @@
mVersion = (int32_t) get4LE((unsigned char*)scanBuf + kPackageVersionOffset);
mFlags = (int32_t) get4LE((unsigned char*)scanBuf + kFlagsOffset);
+ memcpy(&mSalt, (unsigned char*)scanBuf + kSaltOffset, sizeof(mSalt));
+
uint32_t packageNameLen = get4LE((unsigned char*)scanBuf + kPackageNameLenOffset);
if (packageNameLen <= 0
|| packageNameLen > (footerSize - kPackageNameOffset)) {
@@ -255,7 +260,7 @@
my_lseek64(fd, 0, SEEK_END);
if (mPackageName.size() == 0 || mVersion == -1) {
- LOGW("tried to write uninitialized ObbFile data");
+ LOGW("tried to write uninitialized ObbFile data\n");
return false;
}
@@ -264,43 +269,48 @@
put4LE(intBuf, kSigVersion);
if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) {
- LOGW("couldn't write signature version: %s", strerror(errno));
+ LOGW("couldn't write signature version: %s\n", strerror(errno));
return false;
}
put4LE(intBuf, mVersion);
if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) {
- LOGW("couldn't write package version");
+ LOGW("couldn't write package version\n");
return false;
}
put4LE(intBuf, mFlags);
if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) {
- LOGW("couldn't write package version");
+ LOGW("couldn't write package version\n");
+ return false;
+ }
+
+ if (write(fd, mSalt, sizeof(mSalt)) != (ssize_t)sizeof(mSalt)) {
+ LOGW("couldn't write salt: %s\n", strerror(errno));
return false;
}
size_t packageNameLen = mPackageName.size();
put4LE(intBuf, packageNameLen);
if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) {
- LOGW("couldn't write package name length: %s", strerror(errno));
+ LOGW("couldn't write package name length: %s\n", strerror(errno));
return false;
}
if (write(fd, mPackageName.string(), packageNameLen) != (ssize_t)packageNameLen) {
- LOGW("couldn't write package name: %s", strerror(errno));
+ LOGW("couldn't write package name: %s\n", strerror(errno));
return false;
}
put4LE(intBuf, kPackageNameOffset + packageNameLen);
if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) {
- LOGW("couldn't write footer size: %s", strerror(errno));
+ LOGW("couldn't write footer size: %s\n", strerror(errno));
return false;
}
put4LE(intBuf, kSignature);
if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) {
- LOGW("couldn't write footer magic signature: %s", strerror(errno));
+ LOGW("couldn't write footer magic signature: %s\n", strerror(errno));
return false;
}
diff --git a/libs/utils/tests/ObbFile_test.cpp b/libs/utils/tests/ObbFile_test.cpp
index 29bb70a..46b30c2 100644
--- a/libs/utils/tests/ObbFile_test.cpp
+++ b/libs/utils/tests/ObbFile_test.cpp
@@ -23,6 +23,7 @@
#include <gtest/gtest.h>
#include <fcntl.h>
+#include <string.h>
namespace android {
@@ -63,6 +64,10 @@
mObbFile->setPackageName(String8(packageName));
mObbFile->setVersion(versionNum);
+#define SALT_SIZE 8
+ unsigned char salt[SALT_SIZE] = {0x01, 0x10, 0x55, 0xAA, 0xFF, 0x00, 0x5A, 0xA5};
+ EXPECT_TRUE(mObbFile->setSalt(salt, SALT_SIZE))
+ << "Salt should be successfully set";
EXPECT_TRUE(mObbFile->writeTo(mFileName))
<< "couldn't write to fake .obb file";
@@ -77,6 +82,19 @@
const char* currentPackageName = mObbFile->getPackageName().string();
EXPECT_STREQ(packageName, currentPackageName)
<< "package name didn't come out the same as it went in";
+
+ size_t saltLen;
+ const unsigned char* newSalt = mObbFile->getSalt(&saltLen);
+
+ EXPECT_EQ(sizeof(salt), saltLen)
+ << "salt sizes were not the same";
+
+ for (int i = 0; i < sizeof(salt); i++) {
+ EXPECT_EQ(salt[i], newSalt[i])
+ << "salt character " << i << " should be equal";
+ }
+ EXPECT_TRUE(memcmp(newSalt, salt, sizeof(salt)) == 0)
+ << "salts should be the same";
}
}
diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp b/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp
index 1d09f84..90865da 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp
+++ b/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp
@@ -359,7 +359,7 @@
DisplayHardwareBase::DisplayHardwareBase(const sp<SurfaceFlinger>& flinger,
uint32_t displayIndex)
- : mCanDraw(true)
+ : mCanDraw(true), mScreenAcquired(true)
{
mDisplayEventThread = new DisplayEventThread(flinger);
if (mDisplayEventThread->initCheck() != NO_ERROR) {
@@ -374,18 +374,21 @@
mDisplayEventThread->requestExitAndWait();
}
+void DisplayHardwareBase::setCanDraw(bool canDraw)
+{
+ mCanDraw = canDraw;
+}
bool DisplayHardwareBase::canDraw() const
{
- return mCanDraw;
+ return mCanDraw && mScreenAcquired;
}
void DisplayHardwareBase::releaseScreen() const
{
status_t err = mDisplayEventThread->releaseScreen();
if (err >= 0) {
- //LOGD("screen given-up");
- mCanDraw = false;
+ mScreenAcquired = false;
}
}
@@ -393,9 +396,13 @@
{
status_t err = mDisplayEventThread->acquireScreen();
if (err >= 0) {
- //LOGD("screen returned");
- mCanDraw = true;
+ mScreenAcquired = true;
}
}
+bool DisplayHardwareBase::isScreenAcquired() const
+{
+ return mScreenAcquired;
+}
+
}; // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h b/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h
index 8369bb8..fa6a0c4 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h
+++ b/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h
@@ -40,7 +40,11 @@
// console managment
void releaseScreen() const;
void acquireScreen() const;
+ bool isScreenAcquired() const;
+
bool canDraw() const;
+ void setCanDraw(bool canDraw);
+
private:
class DisplayEventThreadBase : public Thread {
@@ -89,6 +93,7 @@
sp<DisplayEventThreadBase> mDisplayEventThread;
mutable int mCanDraw;
+ mutable int mScreenAcquired;
};
}; // namespace android
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index e5e87c6..3734969 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -80,6 +80,7 @@
mVisibleRegionsDirty(false),
mDeferReleaseConsole(false),
mFreezeDisplay(false),
+ mElectronBeamAnimation(false),
mFreezeCount(0),
mFreezeDisplayTime(0),
mDebugRegion(0),
@@ -421,16 +422,20 @@
int what = android_atomic_and(0, &mConsoleSignals);
if (what & eConsoleAcquired) {
hw.acquireScreen();
+ // this is a temporary work-around, eventually this should be called
+ // by the power-manager
+ if (mElectronBeamAnimation)
+ SurfaceFlinger::turnElectronBeamOn(0);
}
- if (mDeferReleaseConsole && hw.canDraw()) {
+ if (mDeferReleaseConsole && hw.isScreenAcquired()) {
// We got the release signal before the acquire signal
mDeferReleaseConsole = false;
hw.releaseScreen();
}
if (what & eConsoleReleased) {
- if (hw.canDraw()) {
+ if (hw.isScreenAcquired()) {
hw.releaseScreen();
} else {
mDeferReleaseConsole = true;
@@ -1456,6 +1461,8 @@
case FREEZE_DISPLAY:
case UNFREEZE_DISPLAY:
case BOOT_FINISHED:
+ case TURN_ELECTRON_BEAM_OFF:
+ case TURN_ELECTRON_BEAM_ON:
{
// codes that require permission check
IPCThreadState* ipc = IPCThreadState::self();
@@ -1546,6 +1553,446 @@
// ---------------------------------------------------------------------------
+status_t SurfaceFlinger::renderScreenToTextureLocked(DisplayID dpy,
+ GLuint* textureName, GLfloat* uOut, GLfloat* vOut)
+{
+ if (!GLExtensions::getInstance().haveFramebufferObject())
+ return INVALID_OPERATION;
+
+ // get screen geometry
+ const DisplayHardware& hw(graphicPlane(dpy).displayHardware());
+ const uint32_t hw_w = hw.getWidth();
+ const uint32_t hw_h = hw.getHeight();
+ GLfloat u = 1;
+ GLfloat v = 1;
+
+ // make sure to clear all GL error flags
+ while ( glGetError() != GL_NO_ERROR ) ;
+
+ // create a FBO
+ GLuint name, tname;
+ glGenTextures(1, &tname);
+ glBindTexture(GL_TEXTURE_2D, tname);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,
+ hw_w, hw_h, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
+ if (glGetError() != GL_NO_ERROR) {
+ GLint tw = (2 << (31 - clz(hw_w)));
+ GLint th = (2 << (31 - clz(hw_h)));
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,
+ tw, th, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
+ u = GLfloat(hw_w) / tw;
+ v = GLfloat(hw_h) / th;
+ }
+ glGenFramebuffersOES(1, &name);
+ glBindFramebufferOES(GL_FRAMEBUFFER_OES, name);
+ glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES,
+ GL_COLOR_ATTACHMENT0_OES, GL_TEXTURE_2D, tname, 0);
+
+ // redraw the screen entirely...
+ glClearColor(0,0,0,1);
+ glClear(GL_COLOR_BUFFER_BIT);
+ const Vector< sp<LayerBase> >& layers(mVisibleLayersSortedByZ);
+ const size_t count = layers.size();
+ for (size_t i=0 ; i<count ; ++i) {
+ const sp<LayerBase>& layer(layers[i]);
+ layer->drawForSreenShot();
+ }
+
+ // back to main framebuffer
+ glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0);
+ glDisable(GL_SCISSOR_TEST);
+ glDeleteFramebuffersOES(1, &name);
+
+ *textureName = tname;
+ *uOut = u;
+ *vOut = v;
+ return NO_ERROR;
+}
+
+// ---------------------------------------------------------------------------
+
+status_t SurfaceFlinger::electronBeamOffAnimationImplLocked()
+{
+ status_t result = PERMISSION_DENIED;
+
+ if (!GLExtensions::getInstance().haveFramebufferObject())
+ return INVALID_OPERATION;
+
+ // get screen geometry
+ const DisplayHardware& hw(graphicPlane(0).displayHardware());
+ const uint32_t hw_w = hw.getWidth();
+ const uint32_t hw_h = hw.getHeight();
+ const Region screenBounds(hw.bounds());
+
+ GLfloat u, v;
+ GLuint tname;
+ result = renderScreenToTextureLocked(0, &tname, &u, &v);
+ if (result != NO_ERROR) {
+ return result;
+ }
+
+ GLfloat vtx[8];
+ const GLfloat texCoords[4][2] = { {0,v}, {0,0}, {u,0}, {u,v} };
+ glEnable(GL_TEXTURE_2D);
+ glBindTexture(GL_TEXTURE_2D, tname);
+ glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glVertexPointer(2, GL_FLOAT, 0, vtx);
+
+ class s_curve_interpolator {
+ const float nbFrames, s, v;
+ public:
+ s_curve_interpolator(int nbFrames, float s)
+ : nbFrames(1.0f / (nbFrames-1)), s(s),
+ v(1.0f + expf(-s + 0.5f*s)) {
+ }
+ float operator()(int f) {
+ const float x = f * nbFrames;
+ return ((1.0f/(1.0f + expf(-x*s + 0.5f*s))) - 0.5f) * v + 0.5f;
+ }
+ };
+
+ class v_stretch {
+ const GLfloat hw_w, hw_h;
+ public:
+ v_stretch(uint32_t hw_w, uint32_t hw_h)
+ : hw_w(hw_w), hw_h(hw_h) {
+ }
+ void operator()(GLfloat* vtx, float v) {
+ const GLfloat w = hw_w + (hw_w * v);
+ const GLfloat h = hw_h - (hw_h * v);
+ const GLfloat x = (hw_w - w) * 0.5f;
+ const GLfloat y = (hw_h - h) * 0.5f;
+ vtx[0] = x; vtx[1] = y;
+ vtx[2] = x; vtx[3] = y + h;
+ vtx[4] = x + w; vtx[5] = y + h;
+ vtx[6] = x + w; vtx[7] = y;
+ }
+ };
+
+ class h_stretch {
+ const GLfloat hw_w, hw_h;
+ public:
+ h_stretch(uint32_t hw_w, uint32_t hw_h)
+ : hw_w(hw_w), hw_h(hw_h) {
+ }
+ void operator()(GLfloat* vtx, float v) {
+ const GLfloat w = hw_w - (hw_w * v);
+ const GLfloat h = 1.0f;
+ const GLfloat x = (hw_w - w) * 0.5f;
+ const GLfloat y = (hw_h - h) * 0.5f;
+ vtx[0] = x; vtx[1] = y;
+ vtx[2] = x; vtx[3] = y + h;
+ vtx[4] = x + w; vtx[5] = y + h;
+ vtx[6] = x + w; vtx[7] = y;
+ }
+ };
+
+ // the full animation is 24 frames
+ const int nbFrames = 12;
+ s_curve_interpolator itr(nbFrames, 7.5f);
+ s_curve_interpolator itg(nbFrames, 8.0f);
+ s_curve_interpolator itb(nbFrames, 8.5f);
+
+ v_stretch vverts(hw_w, hw_h);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_ONE, GL_ONE);
+ for (int i=0 ; i<nbFrames ; i++) {
+ float x, y, w, h;
+ const float vr = itr(i);
+ const float vg = itg(i);
+ const float vb = itb(i);
+
+ // clear screen
+ glColorMask(1,1,1,1);
+ glClear(GL_COLOR_BUFFER_BIT);
+ glEnable(GL_TEXTURE_2D);
+
+ // draw the red plane
+ vverts(vtx, vr);
+ glColorMask(1,0,0,1);
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+
+ // draw the green plane
+ vverts(vtx, vg);
+ glColorMask(0,1,0,1);
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+
+ // draw the blue plane
+ vverts(vtx, vb);
+ glColorMask(0,0,1,1);
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+
+ // draw the white highlight (we use the last vertices)
+ glDisable(GL_TEXTURE_2D);
+ glColorMask(1,1,1,1);
+ glColor4f(vg, vg, vg, 1);
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+ hw.flip(screenBounds);
+ }
+
+ h_stretch hverts(hw_w, hw_h);
+ glDisable(GL_BLEND);
+ glDisable(GL_TEXTURE_2D);
+ glColorMask(1,1,1,1);
+ for (int i=0 ; i<nbFrames ; i++) {
+ const float v = itg(i);
+ hverts(vtx, v);
+ glClear(GL_COLOR_BUFFER_BIT);
+ glColor4f(1-v, 1-v, 1-v, 1);
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+ hw.flip(screenBounds);
+ }
+
+ glColorMask(1,1,1,1);
+ glEnable(GL_SCISSOR_TEST);
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ glDeleteTextures(1, &tname);
+ return NO_ERROR;
+}
+
+status_t SurfaceFlinger::electronBeamOnAnimationImplLocked()
+{
+ status_t result = PERMISSION_DENIED;
+
+ if (!GLExtensions::getInstance().haveFramebufferObject())
+ return INVALID_OPERATION;
+
+
+ // get screen geometry
+ const DisplayHardware& hw(graphicPlane(0).displayHardware());
+ const uint32_t hw_w = hw.getWidth();
+ const uint32_t hw_h = hw.getHeight();
+ const Region screenBounds(hw.bounds());
+
+ GLfloat u, v;
+ GLuint tname;
+ result = renderScreenToTextureLocked(0, &tname, &u, &v);
+ if (result != NO_ERROR) {
+ return result;
+ }
+
+ // back to main framebuffer
+ glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0);
+ glDisable(GL_SCISSOR_TEST);
+
+ GLfloat vtx[8];
+ const GLfloat texCoords[4][2] = { {0,v}, {0,0}, {u,0}, {u,v} };
+ glEnable(GL_TEXTURE_2D);
+ glBindTexture(GL_TEXTURE_2D, tname);
+ glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glVertexPointer(2, GL_FLOAT, 0, vtx);
+
+ class s_curve_interpolator {
+ const float nbFrames, s, v;
+ public:
+ s_curve_interpolator(int nbFrames, float s)
+ : nbFrames(1.0f / (nbFrames-1)), s(s),
+ v(1.0f + expf(-s + 0.5f*s)) {
+ }
+ float operator()(int f) {
+ const float x = f * nbFrames;
+ return ((1.0f/(1.0f + expf(-x*s + 0.5f*s))) - 0.5f) * v + 0.5f;
+ }
+ };
+
+ class v_stretch {
+ const GLfloat hw_w, hw_h;
+ public:
+ v_stretch(uint32_t hw_w, uint32_t hw_h)
+ : hw_w(hw_w), hw_h(hw_h) {
+ }
+ void operator()(GLfloat* vtx, float v) {
+ const GLfloat w = hw_w + (hw_w * v);
+ const GLfloat h = hw_h - (hw_h * v);
+ const GLfloat x = (hw_w - w) * 0.5f;
+ const GLfloat y = (hw_h - h) * 0.5f;
+ vtx[0] = x; vtx[1] = y;
+ vtx[2] = x; vtx[3] = y + h;
+ vtx[4] = x + w; vtx[5] = y + h;
+ vtx[6] = x + w; vtx[7] = y;
+ }
+ };
+
+ class h_stretch {
+ const GLfloat hw_w, hw_h;
+ public:
+ h_stretch(uint32_t hw_w, uint32_t hw_h)
+ : hw_w(hw_w), hw_h(hw_h) {
+ }
+ void operator()(GLfloat* vtx, float v) {
+ const GLfloat w = hw_w - (hw_w * v);
+ const GLfloat h = 1.0f;
+ const GLfloat x = (hw_w - w) * 0.5f;
+ const GLfloat y = (hw_h - h) * 0.5f;
+ vtx[0] = x; vtx[1] = y;
+ vtx[2] = x; vtx[3] = y + h;
+ vtx[4] = x + w; vtx[5] = y + h;
+ vtx[6] = x + w; vtx[7] = y;
+ }
+ };
+
+ // the full animation is 24 frames
+ const int nbFrames = 12;
+ s_curve_interpolator itr(nbFrames, 7.5f);
+ s_curve_interpolator itg(nbFrames, 8.0f);
+ s_curve_interpolator itb(nbFrames, 8.5f);
+
+ h_stretch hverts(hw_w, hw_h);
+ glDisable(GL_BLEND);
+ glDisable(GL_TEXTURE_2D);
+ glColorMask(1,1,1,1);
+ for (int i=nbFrames-1 ; i>=0 ; i--) {
+ const float v = itg(i);
+ hverts(vtx, v);
+ glClear(GL_COLOR_BUFFER_BIT);
+ glColor4f(1-v, 1-v, 1-v, 1);
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+ hw.flip(screenBounds);
+ }
+
+ v_stretch vverts(hw_w, hw_h);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_ONE, GL_ONE);
+ for (int i=nbFrames-1 ; i>=0 ; i--) {
+ float x, y, w, h;
+ const float vr = itr(i);
+ const float vg = itg(i);
+ const float vb = itb(i);
+
+ // clear screen
+ glColorMask(1,1,1,1);
+ glClear(GL_COLOR_BUFFER_BIT);
+ glEnable(GL_TEXTURE_2D);
+
+ // draw the red plane
+ vverts(vtx, vr);
+ glColorMask(1,0,0,1);
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+
+ // draw the green plane
+ vverts(vtx, vg);
+ glColorMask(0,1,0,1);
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+
+ // draw the blue plane
+ vverts(vtx, vb);
+ glColorMask(0,0,1,1);
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+
+ hw.flip(screenBounds);
+ }
+
+ glColorMask(1,1,1,1);
+ glEnable(GL_SCISSOR_TEST);
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ glDeleteTextures(1, &tname);
+
+ return NO_ERROR;
+}
+
+// ---------------------------------------------------------------------------
+
+status_t SurfaceFlinger::turnElectronBeamOffImplLocked()
+{
+ DisplayHardware& hw(graphicPlane(0).editDisplayHardware());
+ if (!hw.canDraw()) {
+ // we're already off
+ return NO_ERROR;
+ }
+ status_t result = electronBeamOffAnimationImplLocked();
+ if (result == NO_ERROR) {
+ hw.setCanDraw(false);
+ }
+ return result;
+}
+
+status_t SurfaceFlinger::turnElectronBeamOff(int32_t mode)
+{
+ if (!GLExtensions::getInstance().haveFramebufferObject())
+ return INVALID_OPERATION;
+
+ class MessageTurnElectronBeamOff : public MessageBase {
+ SurfaceFlinger* flinger;
+ status_t result;
+ public:
+ MessageTurnElectronBeamOff(SurfaceFlinger* flinger)
+ : flinger(flinger), result(PERMISSION_DENIED) {
+ }
+ status_t getResult() const {
+ return result;
+ }
+ virtual bool handler() {
+ Mutex::Autolock _l(flinger->mStateLock);
+ result = flinger->turnElectronBeamOffImplLocked();
+ return true;
+ }
+ };
+
+ sp<MessageBase> msg = new MessageTurnElectronBeamOff(this);
+ status_t res = postMessageSync(msg);
+ if (res == NO_ERROR) {
+ res = static_cast<MessageTurnElectronBeamOff*>( msg.get() )->getResult();
+
+ // work-around: when the power-manager calls us we activate the
+ // animation. eventually, the "on" animation will be called
+ // by the power-manager itself
+ mElectronBeamAnimation = true;
+ }
+ return res;
+}
+
+// ---------------------------------------------------------------------------
+
+status_t SurfaceFlinger::turnElectronBeamOnImplLocked()
+{
+ DisplayHardware& hw(graphicPlane(0).editDisplayHardware());
+ if (hw.canDraw()) {
+ // we're already on
+ return NO_ERROR;
+ }
+ status_t result = electronBeamOnAnimationImplLocked();
+ if (result == NO_ERROR) {
+ hw.setCanDraw(true);
+ }
+ return result;
+}
+
+status_t SurfaceFlinger::turnElectronBeamOn(int32_t mode)
+{
+ if (!GLExtensions::getInstance().haveFramebufferObject())
+ return INVALID_OPERATION;
+
+ class MessageTurnElectronBeamOn : public MessageBase {
+ SurfaceFlinger* flinger;
+ status_t result;
+ public:
+ MessageTurnElectronBeamOn(SurfaceFlinger* flinger)
+ : flinger(flinger), result(PERMISSION_DENIED) {
+ }
+ status_t getResult() const {
+ return result;
+ }
+ virtual bool handler() {
+ Mutex::Autolock _l(flinger->mStateLock);
+ result = flinger->turnElectronBeamOnImplLocked();
+ return true;
+ }
+ };
+
+ postMessageAsync( new MessageTurnElectronBeamOn(this) );
+ return NO_ERROR;
+}
+
+// ---------------------------------------------------------------------------
+
status_t SurfaceFlinger::captureScreenImplLocked(DisplayID dpy,
sp<IMemoryHeap>* heap,
uint32_t* w, uint32_t* h, PixelFormat* f,
@@ -2005,6 +2452,10 @@
return *mHw;
}
+DisplayHardware& GraphicPlane::editDisplayHardware() {
+ return *mHw;
+}
+
const Transform& GraphicPlane::transform() const {
return mGlobalTransform;
}
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index f0a167b..d07a3ad 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -141,6 +141,7 @@
int getHeight() const;
const DisplayHardware& displayHardware() const;
+ DisplayHardware& editDisplayHardware();
const Transform& transform() const;
EGLDisplay getEGLDisplay() const;
@@ -200,6 +201,8 @@
PixelFormat* format,
uint32_t reqWidth,
uint32_t reqHeight);
+ virtual status_t turnElectronBeamOff(int32_t mode);
+ virtual status_t turnElectronBeamOn(int32_t mode);
void screenReleased(DisplayID dpy);
void screenAcquired(DisplayID dpy);
@@ -325,6 +328,13 @@
uint32_t* width, uint32_t* height, PixelFormat* format,
uint32_t reqWidth = 0, uint32_t reqHeight = 0);
+ status_t turnElectronBeamOffImplLocked();
+ status_t turnElectronBeamOnImplLocked();
+ status_t electronBeamOffAnimationImplLocked();
+ status_t electronBeamOnAnimationImplLocked();
+ status_t renderScreenToTextureLocked(DisplayID dpy,
+ GLuint* textureName, GLfloat* uOut, GLfloat* vOut);
+
friend class FreezeLock;
sp<FreezeLock> getFreezeLock() const;
inline void incFreezeCount() {
@@ -385,6 +395,7 @@
bool mVisibleRegionsDirty;
bool mDeferReleaseConsole;
bool mFreezeDisplay;
+ bool mElectronBeamAnimation;
int32_t mFreezeCount;
nsecs_t mFreezeDisplayTime;
Vector< sp<LayerBase> > mVisibleLayersSortedByZ;