Merge "Update the documentation for content provider security." into gingerbread
diff --git a/include/surfaceflinger/ISurfaceComposer.h b/include/surfaceflinger/ISurfaceComposer.h
index 6533600..da4d56f 100644
--- a/include/surfaceflinger/ISurfaceComposer.h
+++ b/include/surfaceflinger/ISurfaceComposer.h
@@ -77,6 +77,11 @@
         eOrientationSwapMask    = 0x01
     };
     
+    enum {
+        eElectronBeamAnimationOn  = 0x01,
+        eElectronBeamAnimationOff = 0x10
+    };
+
     // flags for setOrientation
     enum {
         eOrientationAnimationDisable = 0x00000001
@@ -118,6 +123,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 +150,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/ui/Input.h b/include/ui/Input.h
index 66061fd..8c6018b 100644
--- a/include/ui/Input.h
+++ b/include/ui/Input.h
@@ -95,6 +95,10 @@
     // Indicates that the input event was injected.
     POLICY_FLAG_INJECTED = 0x01000000,
 
+    // Indicates that the input event is from a trusted source such as a directly attached
+    // input device or an application with system-wide event injection permission.
+    POLICY_FLAG_TRUSTED = 0x02000000,
+
     /* These flags are set by the input reader policy as it intercepts each event. */
 
     // Indicates that the screen was off when the event was received and the event
diff --git a/include/ui/InputDispatcher.h b/include/ui/InputDispatcher.h
index 0834e86..3599163 100644
--- a/include/ui/InputDispatcher.h
+++ b/include/ui/InputDispatcher.h
@@ -913,7 +913,6 @@
     void drainInboundQueueLocked();
     void releasePendingEventLocked();
     void releaseInboundEventLocked(EventEntry* entry);
-    bool isEventFromTrustedSourceLocked(EventEntry* entry);
 
     // Dispatch state.
     bool mDispatchEnabled;
@@ -960,10 +959,10 @@
             nsecs_t currentTime, ConfigurationChangedEntry* entry);
     bool dispatchKeyLocked(
             nsecs_t currentTime, KeyEntry* entry, nsecs_t keyRepeatTimeout,
-            bool dropEvent, nsecs_t* nextWakeupTime);
+            DropReason* dropReason, nsecs_t* nextWakeupTime);
     bool dispatchMotionLocked(
             nsecs_t currentTime, MotionEntry* entry,
-            bool dropEvent, nsecs_t* nextWakeupTime);
+            DropReason* dropReason, nsecs_t* nextWakeupTime);
     void dispatchEventToCurrentInputTargetsLocked(
             nsecs_t currentTime, EventEntry* entry, bool resumeWithAppendedMotionSample);
 
diff --git a/include/ui/InputReader.h b/include/ui/InputReader.h
index c15e382..923cdbf 100644
--- a/include/ui/InputReader.h
+++ b/include/ui/InputReader.h
@@ -571,31 +571,36 @@
 
     // Immutable calibration parameters in parsed form.
     struct Calibration {
-        // Touch Area
-        enum TouchAreaCalibration {
-            TOUCH_AREA_CALIBRATION_DEFAULT,
-            TOUCH_AREA_CALIBRATION_NONE,
-            TOUCH_AREA_CALIBRATION_GEOMETRIC,
-            TOUCH_AREA_CALIBRATION_PRESSURE,
+        // Touch Size
+        enum TouchSizeCalibration {
+            TOUCH_SIZE_CALIBRATION_DEFAULT,
+            TOUCH_SIZE_CALIBRATION_NONE,
+            TOUCH_SIZE_CALIBRATION_GEOMETRIC,
+            TOUCH_SIZE_CALIBRATION_PRESSURE,
         };
 
-        TouchAreaCalibration touchAreaCalibration;
+        TouchSizeCalibration touchSizeCalibration;
 
-        // Tool Area
-        enum ToolAreaCalibration {
-            TOOL_AREA_CALIBRATION_DEFAULT,
-            TOOL_AREA_CALIBRATION_NONE,
-            TOOL_AREA_CALIBRATION_GEOMETRIC,
-            TOOL_AREA_CALIBRATION_LINEAR,
+        // Tool Size
+        enum ToolSizeCalibration {
+            TOOL_SIZE_CALIBRATION_DEFAULT,
+            TOOL_SIZE_CALIBRATION_NONE,
+            TOOL_SIZE_CALIBRATION_GEOMETRIC,
+            TOOL_SIZE_CALIBRATION_LINEAR,
+            TOOL_SIZE_CALIBRATION_AREA,
         };
 
-        ToolAreaCalibration toolAreaCalibration;
-        bool haveToolAreaLinearScale;
-        float toolAreaLinearScale;
-        bool haveToolAreaLinearBias;
-        float toolAreaLinearBias;
-        bool haveToolAreaIsSummed;
-        int32_t toolAreaIsSummed;
+        ToolSizeCalibration toolSizeCalibration;
+        bool haveToolSizeLinearScale;
+        float toolSizeLinearScale;
+        bool haveToolSizeLinearBias;
+        float toolSizeLinearBias;
+        bool haveToolSizeAreaScale;
+        float toolSizeAreaScale;
+        bool haveToolSizeAreaBias;
+        float toolSizeAreaBias;
+        bool haveToolSizeIsSummed;
+        int32_t toolSizeIsSummed;
 
         // Pressure
         enum PressureCalibration {
@@ -671,8 +676,10 @@
 
         float geometricScale;
 
-        float toolAreaLinearScale;
-        float toolAreaLinearBias;
+        float toolSizeLinearScale;
+        float toolSizeLinearBias;
+        float toolSizeAreaScale;
+        float toolSizeAreaBias;
 
         float pressureScale;
 
@@ -691,11 +698,11 @@
             bool haveSize;
             InputDeviceInfo::MotionRange size;
 
-            bool haveTouchArea;
+            bool haveTouchSize;
             InputDeviceInfo::MotionRange touchMajor;
             InputDeviceInfo::MotionRange touchMinor;
 
-            bool haveToolArea;
+            bool haveToolSize;
             InputDeviceInfo::MotionRange toolMajor;
             InputDeviceInfo::MotionRange toolMinor;
 
diff --git a/include/utils/Looper.h b/include/utils/Looper.h
index cc51490..eefff31 100644
--- a/include/utils/Looper.h
+++ b/include/utils/Looper.h
@@ -24,10 +24,10 @@
 
 #include <android/looper.h>
 
-// Currently using poll() instead of epoll_wait() since it does a better job of meeting a
-// timeout deadline.  epoll_wait() typically causes additional delays of up to 10ms
-// beyond the requested timeout.
-//#define LOOPER_USES_EPOLL
+// When defined, uses epoll_wait() for polling, otherwise uses poll().
+#define LOOPER_USES_EPOLL
+
+// When defined, logs performance statistics for tuning and debugging purposes.
 //#define LOOPER_STATISTICS
 
 #ifdef LOOPER_USES_EPOLL
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/ui/InputDispatcher.cpp b/libs/ui/InputDispatcher.cpp
index 58c2cdf..6ba19d7 100644
--- a/libs/ui/InputDispatcher.cpp
+++ b/libs/ui/InputDispatcher.cpp
@@ -370,7 +370,7 @@
             }
         }
         done = dispatchKeyLocked(currentTime, typedEntry, keyRepeatTimeout,
-                dropReason != DROP_REASON_NOT_DROPPED, nextWakeupTime);
+                &dropReason, nextWakeupTime);
         break;
     }
 
@@ -380,7 +380,7 @@
             dropReason = DROP_REASON_APP_SWITCH;
         }
         done = dispatchMotionLocked(currentTime, typedEntry,
-                dropReason != DROP_REASON_NOT_DROPPED, nextWakeupTime);
+                &dropReason, nextWakeupTime);
         break;
     }
 
@@ -431,8 +431,10 @@
     const char* reason;
     switch (dropReason) {
     case DROP_REASON_POLICY:
-        reason = "inbound event was dropped because the policy requested that it not be "
-                "delivered to the application";
+#if DEBUG_INBOUND_EVENT_DETAILS
+        LOGD("Dropped event because policy consumed it.");
+#endif
+        reason = "inbound event was dropped because the policy consumed it";
         break;
     case DROP_REASON_DISABLED:
         LOGI("Dropped event because input dispatch is disabled.");
@@ -473,7 +475,7 @@
 bool InputDispatcher::isAppSwitchKeyEventLocked(KeyEntry* keyEntry) {
     return ! (keyEntry->flags & AKEY_EVENT_FLAG_CANCELED)
             && isAppSwitchKeyCode(keyEntry->keyCode)
-            && isEventFromTrustedSourceLocked(keyEntry)
+            && (keyEntry->policyFlags & POLICY_FLAG_TRUSTED)
             && (keyEntry->policyFlags & POLICY_FLAG_PASS_TO_USER);
 }
 
@@ -541,12 +543,6 @@
     mAllocator.releaseEventEntry(entry);
 }
 
-bool InputDispatcher::isEventFromTrustedSourceLocked(EventEntry* entry) {
-    InjectionState* injectionState = entry->injectionState;
-    return ! injectionState
-            || hasInjectionPermission(injectionState->injectorPid, injectionState->injectorUid);
-}
-
 void InputDispatcher::resetKeyRepeatLocked() {
     if (mKeyRepeatState.lastKeyEntry) {
         mAllocator.releaseKeyEntry(mKeyRepeatState.lastKeyEntry);
@@ -559,7 +555,8 @@
     KeyEntry* entry = mKeyRepeatState.lastKeyEntry;
 
     // Reuse the repeated key entry if it is otherwise unreferenced.
-    uint32_t policyFlags = entry->policyFlags & (POLICY_FLAG_RAW_MASK | POLICY_FLAG_PASS_TO_USER);
+    uint32_t policyFlags = (entry->policyFlags & POLICY_FLAG_RAW_MASK)
+            | POLICY_FLAG_PASS_TO_USER | POLICY_FLAG_TRUSTED;
     if (entry->refCount == 1) {
         mAllocator.recycleKeyEntry(entry);
         entry->eventTime = currentTime;
@@ -608,19 +605,13 @@
 
 bool InputDispatcher::dispatchKeyLocked(
         nsecs_t currentTime, KeyEntry* entry, nsecs_t keyRepeatTimeout,
-        bool dropEvent, nsecs_t* nextWakeupTime) {
+        DropReason* dropReason, nsecs_t* nextWakeupTime) {
     // Give the policy a chance to intercept the key.
     if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN) {
-        bool trusted;
-        if (! dropEvent && mFocusedWindow) {
-            trusted = checkInjectionPermission(mFocusedWindow, entry->injectionState);
-        } else {
-            trusted = isEventFromTrustedSourceLocked(entry);
-        }
-        if (trusted) {
+        if (entry->policyFlags & POLICY_FLAG_PASS_TO_USER) {
             CommandEntry* commandEntry = postCommandLocked(
                     & InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible);
-            if (! dropEvent && mFocusedWindow) {
+            if (mFocusedWindow) {
                 commandEntry->inputChannel = mFocusedWindow->inputChannel;
             }
             commandEntry->keyEntry = entry;
@@ -630,15 +621,16 @@
             entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_CONTINUE;
         }
     } else if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_SKIP) {
-        resetTargetsLocked();
-        setInjectionResultLocked(entry, INPUT_EVENT_INJECTION_SUCCEEDED);
-        return true;
+        if (*dropReason == DROP_REASON_NOT_DROPPED) {
+            *dropReason = DROP_REASON_POLICY;
+        }
     }
 
     // Clean up if dropping the event.
-    if (dropEvent) {
+    if (*dropReason != DROP_REASON_NOT_DROPPED) {
         resetTargetsLocked();
-        setInjectionResultLocked(entry, INPUT_EVENT_INJECTION_FAILED);
+        setInjectionResultLocked(entry, *dropReason == DROP_REASON_POLICY
+                ? INPUT_EVENT_INJECTION_SUCCEEDED : INPUT_EVENT_INJECTION_FAILED);
         return true;
     }
 
@@ -648,7 +640,8 @@
 
         if (entry->repeatCount == 0
                 && entry->action == AKEY_EVENT_ACTION_DOWN
-                && ! entry->isInjected()) {
+                && (entry->policyFlags & POLICY_FLAG_TRUSTED)
+                && !entry->isInjected()) {
             if (mKeyRepeatState.lastKeyEntry
                     && mKeyRepeatState.lastKeyEntry->keyCode == entry->keyCode) {
                 // We have seen two identical key downs in a row which indicates that the device
@@ -713,11 +706,12 @@
 }
 
 bool InputDispatcher::dispatchMotionLocked(
-        nsecs_t currentTime, MotionEntry* entry, bool dropEvent, nsecs_t* nextWakeupTime) {
+        nsecs_t currentTime, MotionEntry* entry, DropReason* dropReason, nsecs_t* nextWakeupTime) {
     // Clean up if dropping the event.
-    if (dropEvent) {
+    if (*dropReason != DROP_REASON_NOT_DROPPED) {
         resetTargetsLocked();
-        setInjectionResultLocked(entry, INPUT_EVENT_INJECTION_FAILED);
+        setInjectionResultLocked(entry, *dropReason == DROP_REASON_POLICY
+                ? INPUT_EVENT_INJECTION_SUCCEEDED : INPUT_EVENT_INJECTION_FAILED);
         return true;
     }
 
@@ -2085,6 +2079,7 @@
         return;
     }
 
+    policyFlags |= POLICY_FLAG_TRUSTED;
     mPolicy->interceptKeyBeforeQueueing(eventTime, deviceId, action, /*byref*/ flags,
             keyCode, scanCode, /*byref*/ policyFlags);
 
@@ -2130,6 +2125,7 @@
         return;
     }
 
+    policyFlags |= POLICY_FLAG_TRUSTED;
     mPolicy->interceptGenericBeforeQueueing(eventTime, /*byref*/ policyFlags);
 
     bool needWake;
@@ -2263,6 +2259,7 @@
             switchCode, switchValue, policyFlags);
 #endif
 
+    policyFlags |= POLICY_FLAG_TRUSTED;
     mPolicy->notifySwitch(when, switchCode, switchValue, policyFlags);
 }
 
@@ -2275,7 +2272,11 @@
 #endif
 
     nsecs_t endTime = now() + milliseconds_to_nanoseconds(timeoutMillis);
-    bool trusted = hasInjectionPermission(injectorPid, injectorUid);
+
+    uint32_t policyFlags = POLICY_FLAG_INJECTED;
+    if (hasInjectionPermission(injectorPid, injectorUid)) {
+        policyFlags |= POLICY_FLAG_TRUSTED;
+    }
 
     EventEntry* injectedEntry;
     switch (event->getType()) {
@@ -2291,11 +2292,8 @@
         int32_t flags = keyEvent->getFlags();
         int32_t keyCode = keyEvent->getKeyCode();
         int32_t scanCode = keyEvent->getScanCode();
-        uint32_t policyFlags = POLICY_FLAG_INJECTED;
-        if (trusted) {
-            mPolicy->interceptKeyBeforeQueueing(eventTime, deviceId, action, /*byref*/ flags,
-                    keyCode, scanCode, /*byref*/ policyFlags);
-        }
+        mPolicy->interceptKeyBeforeQueueing(eventTime, deviceId, action, /*byref*/ flags,
+                keyCode, scanCode, /*byref*/ policyFlags);
 
         mLock.lock();
         injectedEntry = mAllocator.obtainKeyEntry(eventTime, deviceId, keyEvent->getSource(),
@@ -2314,10 +2312,7 @@
         }
 
         nsecs_t eventTime = motionEvent->getEventTime();
-        uint32_t policyFlags = POLICY_FLAG_INJECTED;
-        if (trusted) {
-            mPolicy->interceptGenericBeforeQueueing(eventTime, /*byref*/ policyFlags);
-        }
+        mPolicy->interceptGenericBeforeQueueing(eventTime, /*byref*/ policyFlags);
 
         mLock.lock();
         const nsecs_t* sampleEventTimes = motionEvent->getSampleEventTimes();
@@ -3323,7 +3318,7 @@
         }
     }
 
-    for (size_t i = 0; i < mMotionMementos.size(); i++) {
+    for (size_t i = 0; i < mMotionMementos.size(); ) {
         const MotionMemento& memento = mMotionMementos.itemAt(i);
         if (shouldCancelEvent(memento.source, options)) {
             outEvents.push(allocator->obtainMotionEntry(currentTime,
diff --git a/libs/ui/InputReader.cpp b/libs/ui/InputReader.cpp
index 0560bb8..ce0d880 100644
--- a/libs/ui/InputReader.cpp
+++ b/libs/ui/InputReader.cpp
@@ -1246,14 +1246,14 @@
                     mLocked.orientedRanges.size);
         }
 
-        if (mLocked.orientedRanges.haveTouchArea) {
+        if (mLocked.orientedRanges.haveTouchSize) {
             info->addMotionRange(AINPUT_MOTION_RANGE_TOUCH_MAJOR,
                     mLocked.orientedRanges.touchMajor);
             info->addMotionRange(AINPUT_MOTION_RANGE_TOUCH_MINOR,
                     mLocked.orientedRanges.touchMinor);
         }
 
-        if (mLocked.orientedRanges.haveToolArea) {
+        if (mLocked.orientedRanges.haveToolSize) {
             info->addMotionRange(AINPUT_MOTION_RANGE_TOOL_MAJOR,
                     mLocked.orientedRanges.toolMajor);
             info->addMotionRange(AINPUT_MOTION_RANGE_TOOL_MINOR,
@@ -1277,8 +1277,21 @@
         dumpRawAxes(dump);
         dumpCalibration(dump);
         dumpSurfaceLocked(dump);
-        dump.appendFormat(INDENT3 "XPrecision: %0.3f\n", mLocked.xPrecision);
-        dump.appendFormat(INDENT3 "YPrecision: %0.3f\n", mLocked.yPrecision);
+        dump.appendFormat(INDENT3 "Translation and Scaling Factors:");
+        dump.appendFormat(INDENT4 "XOrigin: %d\n", mLocked.xOrigin);
+        dump.appendFormat(INDENT4 "YOrigin: %d\n", mLocked.yOrigin);
+        dump.appendFormat(INDENT4 "XScale: %0.3f\n", mLocked.xScale);
+        dump.appendFormat(INDENT4 "YScale: %0.3f\n", mLocked.yScale);
+        dump.appendFormat(INDENT4 "XPrecision: %0.3f\n", mLocked.xPrecision);
+        dump.appendFormat(INDENT4 "YPrecision: %0.3f\n", mLocked.yPrecision);
+        dump.appendFormat(INDENT4 "GeometricScale: %0.3f\n", mLocked.geometricScale);
+        dump.appendFormat(INDENT4 "ToolSizeLinearScale: %0.3f\n", mLocked.toolSizeLinearScale);
+        dump.appendFormat(INDENT4 "ToolSizeLinearBias: %0.3f\n", mLocked.toolSizeLinearBias);
+        dump.appendFormat(INDENT4 "ToolSizeAreaScale: %0.3f\n", mLocked.toolSizeAreaScale);
+        dump.appendFormat(INDENT4 "ToolSizeAreaBias: %0.3f\n", mLocked.toolSizeAreaBias);
+        dump.appendFormat(INDENT4 "PressureScale: %0.3f\n", mLocked.pressureScale);
+        dump.appendFormat(INDENT4 "SizeScale: %0.3f\n", mLocked.sizeScale);
+        dump.appendFormat(INDENT4 "OrientationSCale: %0.3f\n", mLocked.orientationScale);
     } // release lock
 }
 
@@ -1298,8 +1311,8 @@
 
     mLocked.orientedRanges.havePressure = false;
     mLocked.orientedRanges.haveSize = false;
-    mLocked.orientedRanges.haveTouchArea = false;
-    mLocked.orientedRanges.haveToolArea = false;
+    mLocked.orientedRanges.haveTouchSize = false;
+    mLocked.orientedRanges.haveToolSize = false;
     mLocked.orientedRanges.haveOrientation = false;
 }
 
@@ -1428,8 +1441,8 @@
         float diagonalSize = pythag(width, height);
 
         // TouchMajor and TouchMinor factors.
-        if (mCalibration.touchAreaCalibration != Calibration::TOUCH_AREA_CALIBRATION_NONE) {
-            mLocked.orientedRanges.haveTouchArea = true;
+        if (mCalibration.touchSizeCalibration != Calibration::TOUCH_SIZE_CALIBRATION_NONE) {
+            mLocked.orientedRanges.haveTouchSize = true;
             mLocked.orientedRanges.touchMajor.min = 0;
             mLocked.orientedRanges.touchMajor.max = diagonalSize;
             mLocked.orientedRanges.touchMajor.flat = 0;
@@ -1438,23 +1451,46 @@
         }
 
         // ToolMajor and ToolMinor factors.
-        if (mCalibration.toolAreaCalibration != Calibration::TOOL_AREA_CALIBRATION_NONE) {
-            mLocked.toolAreaLinearScale = 0;
-            mLocked.toolAreaLinearBias = 0;
-            if (mCalibration.toolAreaCalibration == Calibration::TOOL_AREA_CALIBRATION_LINEAR) {
-                if (mCalibration.haveToolAreaLinearScale) {
-                    mLocked.toolAreaLinearScale = mCalibration.toolAreaLinearScale;
+        mLocked.toolSizeLinearScale = 0;
+        mLocked.toolSizeLinearBias = 0;
+        mLocked.toolSizeAreaScale = 0;
+        mLocked.toolSizeAreaBias = 0;
+        if (mCalibration.toolSizeCalibration != Calibration::TOOL_SIZE_CALIBRATION_NONE) {
+            if (mCalibration.toolSizeCalibration == Calibration::TOOL_SIZE_CALIBRATION_LINEAR) {
+                if (mCalibration.haveToolSizeLinearScale) {
+                    mLocked.toolSizeLinearScale = mCalibration.toolSizeLinearScale;
                 } else if (mRawAxes.toolMajor.valid && mRawAxes.toolMajor.maxValue != 0) {
-                    mLocked.toolAreaLinearScale = float(min(width, height))
+                    mLocked.toolSizeLinearScale = float(min(width, height))
                             / mRawAxes.toolMajor.maxValue;
                 }
 
-                if (mCalibration.haveToolAreaLinearBias) {
-                    mLocked.toolAreaLinearBias = mCalibration.toolAreaLinearBias;
+                if (mCalibration.haveToolSizeLinearBias) {
+                    mLocked.toolSizeLinearBias = mCalibration.toolSizeLinearBias;
+                }
+            } else if (mCalibration.toolSizeCalibration ==
+                    Calibration::TOOL_SIZE_CALIBRATION_AREA) {
+                if (mCalibration.haveToolSizeLinearScale) {
+                    mLocked.toolSizeLinearScale = mCalibration.toolSizeLinearScale;
+                } else {
+                    mLocked.toolSizeLinearScale = min(width, height);
+                }
+
+                if (mCalibration.haveToolSizeLinearBias) {
+                    mLocked.toolSizeLinearBias = mCalibration.toolSizeLinearBias;
+                }
+
+                if (mCalibration.haveToolSizeAreaScale) {
+                    mLocked.toolSizeAreaScale = mCalibration.toolSizeAreaScale;
+                } else if (mRawAxes.toolMajor.valid && mRawAxes.toolMajor.maxValue != 0) {
+                    mLocked.toolSizeAreaScale = 1.0f / mRawAxes.toolMajor.maxValue;
+                }
+
+                if (mCalibration.haveToolSizeAreaBias) {
+                    mLocked.toolSizeAreaBias = mCalibration.toolSizeAreaBias;
                 }
             }
 
-            mLocked.orientedRanges.haveToolArea = true;
+            mLocked.orientedRanges.haveToolSize = true;
             mLocked.orientedRanges.toolMajor.min = 0;
             mLocked.orientedRanges.toolMajor.max = diagonalSize;
             mLocked.orientedRanges.toolMajor.flat = 0;
@@ -1463,6 +1499,7 @@
         }
 
         // Pressure factors.
+        mLocked.pressureScale = 0;
         if (mCalibration.pressureCalibration != Calibration::PRESSURE_CALIBRATION_NONE) {
             RawAbsoluteAxisInfo rawPressureAxis;
             switch (mCalibration.pressureSource) {
@@ -1476,7 +1513,6 @@
                 rawPressureAxis.clear();
             }
 
-            mLocked.pressureScale = 0;
             if (mCalibration.pressureCalibration == Calibration::PRESSURE_CALIBRATION_PHYSICAL
                     || mCalibration.pressureCalibration
                             == Calibration::PRESSURE_CALIBRATION_AMPLITUDE) {
@@ -1495,8 +1531,8 @@
         }
 
         // Size factors.
+        mLocked.sizeScale = 0;
         if (mCalibration.sizeCalibration != Calibration::SIZE_CALIBRATION_NONE) {
-            mLocked.sizeScale = 0;
             if (mCalibration.sizeCalibration == Calibration::SIZE_CALIBRATION_NORMALIZED) {
                 if (mRawAxes.toolMajor.valid && mRawAxes.toolMajor.maxValue != 0) {
                     mLocked.sizeScale = 1.0f / mRawAxes.toolMajor.maxValue;
@@ -1511,8 +1547,8 @@
         }
 
         // Orientation
+        mLocked.orientationScale = 0;
         if (mCalibration.orientationCalibration != Calibration::ORIENTATION_CALIBRATION_NONE) {
-            mLocked.orientationScale = 0;
             if (mCalibration.orientationCalibration
                     == Calibration::ORIENTATION_CALIBRATION_INTERPOLATED) {
                 if (mRawAxes.orientation.valid && mRawAxes.orientation.maxValue != 0) {
@@ -1647,49 +1683,55 @@
     const InputDeviceCalibration& in = getDevice()->getCalibration();
     Calibration& out = mCalibration;
 
-    // Touch Area
-    out.touchAreaCalibration = Calibration::TOUCH_AREA_CALIBRATION_DEFAULT;
-    String8 touchAreaCalibrationString;
-    if (in.tryGetProperty(String8("touch.touchArea.calibration"), touchAreaCalibrationString)) {
-        if (touchAreaCalibrationString == "none") {
-            out.touchAreaCalibration = Calibration::TOUCH_AREA_CALIBRATION_NONE;
-        } else if (touchAreaCalibrationString == "geometric") {
-            out.touchAreaCalibration = Calibration::TOUCH_AREA_CALIBRATION_GEOMETRIC;
-        } else if (touchAreaCalibrationString == "pressure") {
-            out.touchAreaCalibration = Calibration::TOUCH_AREA_CALIBRATION_PRESSURE;
-        } else if (touchAreaCalibrationString != "default") {
-            LOGW("Invalid value for touch.touchArea.calibration: '%s'",
-                    touchAreaCalibrationString.string());
+    // Touch Size
+    out.touchSizeCalibration = Calibration::TOUCH_SIZE_CALIBRATION_DEFAULT;
+    String8 touchSizeCalibrationString;
+    if (in.tryGetProperty(String8("touch.touchSize.calibration"), touchSizeCalibrationString)) {
+        if (touchSizeCalibrationString == "none") {
+            out.touchSizeCalibration = Calibration::TOUCH_SIZE_CALIBRATION_NONE;
+        } else if (touchSizeCalibrationString == "geometric") {
+            out.touchSizeCalibration = Calibration::TOUCH_SIZE_CALIBRATION_GEOMETRIC;
+        } else if (touchSizeCalibrationString == "pressure") {
+            out.touchSizeCalibration = Calibration::TOUCH_SIZE_CALIBRATION_PRESSURE;
+        } else if (touchSizeCalibrationString != "default") {
+            LOGW("Invalid value for touch.touchSize.calibration: '%s'",
+                    touchSizeCalibrationString.string());
         }
     }
 
-    // Tool Area
-    out.toolAreaCalibration = Calibration::TOOL_AREA_CALIBRATION_DEFAULT;
-    String8 toolAreaCalibrationString;
-    if (in.tryGetProperty(String8("tool.toolArea.calibration"), toolAreaCalibrationString)) {
-        if (toolAreaCalibrationString == "none") {
-            out.toolAreaCalibration = Calibration::TOOL_AREA_CALIBRATION_NONE;
-        } else if (toolAreaCalibrationString == "geometric") {
-            out.toolAreaCalibration = Calibration::TOOL_AREA_CALIBRATION_GEOMETRIC;
-        } else if (toolAreaCalibrationString == "linear") {
-            out.toolAreaCalibration = Calibration::TOOL_AREA_CALIBRATION_LINEAR;
-        } else if (toolAreaCalibrationString != "default") {
-            LOGW("Invalid value for tool.toolArea.calibration: '%s'",
-                    toolAreaCalibrationString.string());
+    // Tool Size
+    out.toolSizeCalibration = Calibration::TOOL_SIZE_CALIBRATION_DEFAULT;
+    String8 toolSizeCalibrationString;
+    if (in.tryGetProperty(String8("touch.toolSize.calibration"), toolSizeCalibrationString)) {
+        if (toolSizeCalibrationString == "none") {
+            out.toolSizeCalibration = Calibration::TOOL_SIZE_CALIBRATION_NONE;
+        } else if (toolSizeCalibrationString == "geometric") {
+            out.toolSizeCalibration = Calibration::TOOL_SIZE_CALIBRATION_GEOMETRIC;
+        } else if (toolSizeCalibrationString == "linear") {
+            out.toolSizeCalibration = Calibration::TOOL_SIZE_CALIBRATION_LINEAR;
+        } else if (toolSizeCalibrationString == "area") {
+            out.toolSizeCalibration = Calibration::TOOL_SIZE_CALIBRATION_AREA;
+        } else if (toolSizeCalibrationString != "default") {
+            LOGW("Invalid value for touch.toolSize.calibration: '%s'",
+                    toolSizeCalibrationString.string());
         }
     }
 
-    out.haveToolAreaLinearScale = in.tryGetProperty(String8("touch.toolArea.linearScale"),
-            out.toolAreaLinearScale);
-    out.haveToolAreaLinearBias = in.tryGetProperty(String8("touch.toolArea.linearBias"),
-            out.toolAreaLinearBias);
-    out.haveToolAreaIsSummed = in.tryGetProperty(String8("touch.toolArea.isSummed"),
-            out.toolAreaIsSummed);
+    out.haveToolSizeLinearScale = in.tryGetProperty(String8("touch.toolSize.linearScale"),
+            out.toolSizeLinearScale);
+    out.haveToolSizeLinearBias = in.tryGetProperty(String8("touch.toolSize.linearBias"),
+            out.toolSizeLinearBias);
+    out.haveToolSizeAreaScale = in.tryGetProperty(String8("touch.toolSize.areaScale"),
+            out.toolSizeAreaScale);
+    out.haveToolSizeAreaBias = in.tryGetProperty(String8("touch.toolSize.areaBias"),
+            out.toolSizeAreaBias);
+    out.haveToolSizeIsSummed = in.tryGetProperty(String8("touch.toolSize.isSummed"),
+            out.toolSizeIsSummed);
 
     // Pressure
     out.pressureCalibration = Calibration::PRESSURE_CALIBRATION_DEFAULT;
     String8 pressureCalibrationString;
-    if (in.tryGetProperty(String8("tool.pressure.calibration"), pressureCalibrationString)) {
+    if (in.tryGetProperty(String8("touch.pressure.calibration"), pressureCalibrationString)) {
         if (pressureCalibrationString == "none") {
             out.pressureCalibration = Calibration::PRESSURE_CALIBRATION_NONE;
         } else if (pressureCalibrationString == "physical") {
@@ -1697,7 +1739,7 @@
         } else if (pressureCalibrationString == "amplitude") {
             out.pressureCalibration = Calibration::PRESSURE_CALIBRATION_AMPLITUDE;
         } else if (pressureCalibrationString != "default") {
-            LOGW("Invalid value for tool.pressure.calibration: '%s'",
+            LOGW("Invalid value for touch.pressure.calibration: '%s'",
                     pressureCalibrationString.string());
         }
     }
@@ -1721,13 +1763,13 @@
     // Size
     out.sizeCalibration = Calibration::SIZE_CALIBRATION_DEFAULT;
     String8 sizeCalibrationString;
-    if (in.tryGetProperty(String8("tool.size.calibration"), sizeCalibrationString)) {
+    if (in.tryGetProperty(String8("touch.size.calibration"), sizeCalibrationString)) {
         if (sizeCalibrationString == "none") {
             out.sizeCalibration = Calibration::SIZE_CALIBRATION_NONE;
         } else if (sizeCalibrationString == "normalized") {
             out.sizeCalibration = Calibration::SIZE_CALIBRATION_NORMALIZED;
         } else if (sizeCalibrationString != "default") {
-            LOGW("Invalid value for tool.size.calibration: '%s'",
+            LOGW("Invalid value for touch.size.calibration: '%s'",
                     sizeCalibrationString.string());
         }
     }
@@ -1735,13 +1777,13 @@
     // Orientation
     out.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_DEFAULT;
     String8 orientationCalibrationString;
-    if (in.tryGetProperty(String8("tool.orientation.calibration"), orientationCalibrationString)) {
+    if (in.tryGetProperty(String8("touch.orientation.calibration"), orientationCalibrationString)) {
         if (orientationCalibrationString == "none") {
             out.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_NONE;
         } else if (orientationCalibrationString == "interpolated") {
             out.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_INTERPOLATED;
         } else if (orientationCalibrationString != "default") {
-            LOGW("Invalid value for tool.orientation.calibration: '%s'",
+            LOGW("Invalid value for touch.orientation.calibration: '%s'",
                     orientationCalibrationString.string());
         }
     }
@@ -1789,13 +1831,13 @@
         break;
     }
 
-    // Tool Area
-    switch (mCalibration.toolAreaCalibration) {
-    case Calibration::TOOL_AREA_CALIBRATION_DEFAULT:
+    // Tool Size
+    switch (mCalibration.toolSizeCalibration) {
+    case Calibration::TOOL_SIZE_CALIBRATION_DEFAULT:
         if (mRawAxes.toolMajor.valid) {
-            mCalibration.toolAreaCalibration = Calibration::TOOL_AREA_CALIBRATION_LINEAR;
+            mCalibration.toolSizeCalibration = Calibration::TOOL_SIZE_CALIBRATION_LINEAR;
         } else {
-            mCalibration.toolAreaCalibration = Calibration::TOOL_AREA_CALIBRATION_NONE;
+            mCalibration.toolSizeCalibration = Calibration::TOOL_SIZE_CALIBRATION_NONE;
         }
         break;
 
@@ -1803,14 +1845,14 @@
         break;
     }
 
-    // Touch Area
-    switch (mCalibration.touchAreaCalibration) {
-    case Calibration::TOUCH_AREA_CALIBRATION_DEFAULT:
+    // Touch Size
+    switch (mCalibration.touchSizeCalibration) {
+    case Calibration::TOUCH_SIZE_CALIBRATION_DEFAULT:
         if (mCalibration.pressureCalibration != Calibration::PRESSURE_CALIBRATION_NONE
-                && mCalibration.toolAreaCalibration != Calibration::TOOL_AREA_CALIBRATION_NONE) {
-            mCalibration.touchAreaCalibration = Calibration::TOUCH_AREA_CALIBRATION_PRESSURE;
+                && mCalibration.toolSizeCalibration != Calibration::TOOL_SIZE_CALIBRATION_NONE) {
+            mCalibration.touchSizeCalibration = Calibration::TOUCH_SIZE_CALIBRATION_PRESSURE;
         } else {
-            mCalibration.touchAreaCalibration = Calibration::TOUCH_AREA_CALIBRATION_NONE;
+            mCalibration.touchSizeCalibration = Calibration::TOUCH_SIZE_CALIBRATION_NONE;
         }
         break;
 
@@ -1850,49 +1892,62 @@
 void TouchInputMapper::dumpCalibration(String8& dump) {
     dump.append(INDENT3 "Calibration:\n");
 
-    // Touch Area
-    switch (mCalibration.touchAreaCalibration) {
-    case Calibration::TOUCH_AREA_CALIBRATION_NONE:
-        dump.append(INDENT4 "touch.touchArea.calibration: none\n");
+    // Touch Size
+    switch (mCalibration.touchSizeCalibration) {
+    case Calibration::TOUCH_SIZE_CALIBRATION_NONE:
+        dump.append(INDENT4 "touch.touchSize.calibration: none\n");
         break;
-    case Calibration::TOUCH_AREA_CALIBRATION_GEOMETRIC:
-        dump.append(INDENT4 "touch.touchArea.calibration: geometric\n");
+    case Calibration::TOUCH_SIZE_CALIBRATION_GEOMETRIC:
+        dump.append(INDENT4 "touch.touchSize.calibration: geometric\n");
         break;
-    case Calibration::TOUCH_AREA_CALIBRATION_PRESSURE:
-        dump.append(INDENT4 "touch.touchArea.calibration: pressure\n");
+    case Calibration::TOUCH_SIZE_CALIBRATION_PRESSURE:
+        dump.append(INDENT4 "touch.touchSize.calibration: pressure\n");
         break;
     default:
         assert(false);
     }
 
-    // Tool Area
-    switch (mCalibration.toolAreaCalibration) {
-    case Calibration::TOOL_AREA_CALIBRATION_NONE:
-        dump.append(INDENT4 "touch.toolArea.calibration: none\n");
+    // Tool Size
+    switch (mCalibration.toolSizeCalibration) {
+    case Calibration::TOOL_SIZE_CALIBRATION_NONE:
+        dump.append(INDENT4 "touch.toolSize.calibration: none\n");
         break;
-    case Calibration::TOOL_AREA_CALIBRATION_GEOMETRIC:
-        dump.append(INDENT4 "touch.toolArea.calibration: geometric\n");
+    case Calibration::TOOL_SIZE_CALIBRATION_GEOMETRIC:
+        dump.append(INDENT4 "touch.toolSize.calibration: geometric\n");
         break;
-    case Calibration::TOOL_AREA_CALIBRATION_LINEAR:
-        dump.append(INDENT4 "touch.toolArea.calibration: linear\n");
+    case Calibration::TOOL_SIZE_CALIBRATION_LINEAR:
+        dump.append(INDENT4 "touch.toolSize.calibration: linear\n");
+        break;
+    case Calibration::TOOL_SIZE_CALIBRATION_AREA:
+        dump.append(INDENT4 "touch.toolSize.calibration: area\n");
         break;
     default:
         assert(false);
     }
 
-    if (mCalibration.haveToolAreaLinearScale) {
-        dump.appendFormat(INDENT4 "touch.toolArea.linearScale: %0.3f\n",
-                mCalibration.toolAreaLinearScale);
+    if (mCalibration.haveToolSizeLinearScale) {
+        dump.appendFormat(INDENT4 "touch.toolSize.linearScale: %0.3f\n",
+                mCalibration.toolSizeLinearScale);
     }
 
-    if (mCalibration.haveToolAreaLinearBias) {
-        dump.appendFormat(INDENT4 "touch.toolArea.linearBias: %0.3f\n",
-                mCalibration.toolAreaLinearBias);
+    if (mCalibration.haveToolSizeLinearBias) {
+        dump.appendFormat(INDENT4 "touch.toolSize.linearBias: %0.3f\n",
+                mCalibration.toolSizeLinearBias);
     }
 
-    if (mCalibration.haveToolAreaIsSummed) {
-        dump.appendFormat(INDENT4 "touch.toolArea.isSummed: %d\n",
-                mCalibration.toolAreaIsSummed);
+    if (mCalibration.haveToolSizeAreaScale) {
+        dump.appendFormat(INDENT4 "touch.toolSize.areaScale: %0.3f\n",
+                mCalibration.toolSizeAreaScale);
+    }
+
+    if (mCalibration.haveToolSizeAreaBias) {
+        dump.appendFormat(INDENT4 "touch.toolSize.areaBias: %0.3f\n",
+                mCalibration.toolSizeAreaBias);
+    }
+
+    if (mCalibration.haveToolSizeIsSummed) {
+        dump.appendFormat(INDENT4 "touch.toolSize.isSummed: %d\n",
+                mCalibration.toolSizeIsSummed);
     }
 
     // Pressure
@@ -2207,8 +2262,8 @@
 
             // ToolMajor and ToolMinor
             float toolMajor, toolMinor;
-            switch (mCalibration.toolAreaCalibration) {
-            case Calibration::TOOL_AREA_CALIBRATION_GEOMETRIC:
+            switch (mCalibration.toolSizeCalibration) {
+            case Calibration::TOOL_SIZE_CALIBRATION_GEOMETRIC:
                 toolMajor = in.toolMajor * mLocked.geometricScale;
                 if (mRawAxes.toolMinor.valid) {
                     toolMinor = in.toolMinor * mLocked.geometricScale;
@@ -2216,26 +2271,36 @@
                     toolMinor = toolMajor;
                 }
                 break;
-            case Calibration::TOOL_AREA_CALIBRATION_LINEAR:
+            case Calibration::TOOL_SIZE_CALIBRATION_LINEAR:
                 toolMajor = in.toolMajor != 0
-                        ? in.toolMajor * mLocked.toolAreaLinearScale + mLocked.toolAreaLinearBias
+                        ? in.toolMajor * mLocked.toolSizeLinearScale + mLocked.toolSizeLinearBias
                         : 0;
                 if (mRawAxes.toolMinor.valid) {
                     toolMinor = in.toolMinor != 0
-                            ? in.toolMinor * mLocked.toolAreaLinearScale
-                                    + mLocked.toolAreaLinearBias
+                            ? in.toolMinor * mLocked.toolSizeLinearScale
+                                    + mLocked.toolSizeLinearBias
                             : 0;
                 } else {
                     toolMinor = toolMajor;
                 }
                 break;
+            case Calibration::TOOL_SIZE_CALIBRATION_AREA:
+                if (in.toolMajor != 0) {
+                    float diameter = sqrtf(in.toolMajor
+                            * mLocked.toolSizeAreaScale + mLocked.toolSizeAreaBias);
+                    toolMajor = diameter * mLocked.toolSizeLinearScale + mLocked.toolSizeLinearBias;
+                } else {
+                    toolMajor = 0;
+                }
+                toolMinor = toolMajor;
+                break;
             default:
                 toolMajor = 0;
                 toolMinor = 0;
                 break;
             }
 
-            if (mCalibration.haveToolAreaIsSummed && mCalibration.toolAreaIsSummed) {
+            if (mCalibration.haveToolSizeIsSummed && mCalibration.toolSizeIsSummed) {
                 toolMajor /= pointerCount;
                 toolMinor /= pointerCount;
             }
@@ -2266,8 +2331,8 @@
 
             // TouchMajor and TouchMinor
             float touchMajor, touchMinor;
-            switch (mCalibration.touchAreaCalibration) {
-            case Calibration::TOUCH_AREA_CALIBRATION_GEOMETRIC:
+            switch (mCalibration.touchSizeCalibration) {
+            case Calibration::TOUCH_SIZE_CALIBRATION_GEOMETRIC:
                 touchMajor = in.touchMajor * mLocked.geometricScale;
                 if (mRawAxes.touchMinor.valid) {
                     touchMinor = in.touchMinor * mLocked.geometricScale;
@@ -2275,7 +2340,7 @@
                     touchMinor = touchMajor;
                 }
                 break;
-            case Calibration::TOUCH_AREA_CALIBRATION_PRESSURE:
+            case Calibration::TOUCH_SIZE_CALIBRATION_PRESSURE:
                 touchMajor = toolMajor * pressure;
                 touchMinor = toolMinor * pressure;
                 break;
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/ZipFileRO.cpp b/libs/utils/ZipFileRO.cpp
index 9b1f82f..5ff1f8f 100644
--- a/libs/utils/ZipFileRO.cpp
+++ b/libs/utils/ZipFileRO.cpp
@@ -32,6 +32,22 @@
 #include <assert.h>
 #include <unistd.h>
 
+#if HAVE_PRINTF_ZD
+#  define ZD "%zd"
+#  define ZD_TYPE ssize_t
+#else
+#  define ZD "%ld"
+#  define ZD_TYPE long
+#endif
+
+/*
+ * We must open binary files using open(path, ... | O_BINARY) under Windows.
+ * Otherwise strange read errors will happen.
+ */
+#ifndef O_BINARY
+#  define O_BINARY  0
+#endif
+
 /*
  * TEMP_FAILURE_RETRY is defined by some, but not all, versions of
  * <unistd.h>. (Alas, it is not as standard as we'd hoped!) So, if it's
@@ -124,7 +140,7 @@
     /*
      * Open and map the specified file.
      */
-    fd = ::open(zipFileName, O_RDONLY);
+    fd = ::open(zipFileName, O_RDONLY | O_BINARY);
     if (fd < 0) {
         LOGW("Unable to open zip '%s': %s\n", zipFileName, strerror(errno));
         return NAME_NOT_FOUND;
@@ -172,8 +188,8 @@
  */
 bool ZipFileRO::mapCentralDirectory(void)
 {
-    size_t readAmount = kMaxEOCDSearch;
-    if (readAmount > (size_t) mFileLength)
+    ssize_t readAmount = kMaxEOCDSearch;
+    if (readAmount > (ssize_t) mFileLength)
         readAmount = mFileLength;
 
     unsigned char* scanBuf = (unsigned char*) malloc(readAmount);
@@ -233,7 +249,8 @@
     }
     actual = TEMP_FAILURE_RETRY(read(mFd, scanBuf, readAmount));
     if (actual != (ssize_t) readAmount) {
-        LOGW("Zip: read %zd failed: %s\n", readAmount, strerror(errno));
+        LOGW("Zip: read " ZD ", expected " ZD ". Failed: %s\n",
+            (ZD_TYPE) actual, (ZD_TYPE) readAmount, strerror(errno));
         free(scanBuf);
         return false;
     }
@@ -292,8 +309,8 @@
     }
 
     if (!mDirectoryMap->create(mFileName, mFd, dirOffset, dirSize, true)) {
-        LOGW("Unable to map '%s' (%zd to %zd): %s\n", mFileName,
-                dirOffset, dirOffset + dirSize, strerror(errno));
+        LOGW("Unable to map '%s' (" ZD " to " ZD "): %s\n", mFileName,
+                (ZD_TYPE) dirOffset, (ZD_TYPE) (dirOffset + dirSize), strerror(errno));
         return false;
     }
 
@@ -350,8 +367,8 @@
 
         ptr += kCDELen + fileNameLen + extraLen + commentLen;
         if ((size_t)(ptr - cdPtr) > cdLength) {
-            LOGW("bad CD advance (%d vs %zd) at entry %d\n",
-                (int) (ptr - cdPtr), cdLength, i);
+            LOGW("bad CD advance (%d vs " ZD ") at entry %d\n",
+                (int) (ptr - cdPtr), (ZD_TYPE) cdLength, i);
             goto bail;
         }
     }
@@ -556,8 +573,8 @@
             if (get4LE(lfhBuf) != kLFHSignature) {
                 off_t actualOffset = lseek(mFd, 0, SEEK_CUR);
                 LOGW("didn't find signature at start of lfh; wanted: offset=%ld data=0x%08x; "
-                        "got: offset=%zd data=0x%08lx\n",
-                        localHdrOffset, kLFHSignature, (size_t)actualOffset, get4LE(lfhBuf));
+                        "got: offset=" ZD " data=0x%08lx\n",
+                        localHdrOffset, kLFHSignature, (ZD_TYPE) actualOffset, get4LE(lfhBuf));
                 return false;
             }
         }
@@ -572,16 +589,16 @@
 
         /* check lengths */
         if ((off_t)(dataOffset + compLen) > cdOffset) {
-            LOGW("bad compressed length in zip (%ld + %zd > %ld)\n",
-                (long) dataOffset, compLen, (long) cdOffset);
+            LOGW("bad compressed length in zip (%ld + " ZD " > %ld)\n",
+                (long) dataOffset, (ZD_TYPE) compLen, (long) cdOffset);
             return false;
         }
 
         if (method == kCompressStored &&
             (off_t)(dataOffset + uncompLen) > cdOffset)
         {
-            LOGE("ERROR: bad uncompressed length in zip (%ld + %zd > %ld)\n",
-                (long) dataOffset, uncompLen, (long) cdOffset);
+            LOGE("ERROR: bad uncompressed length in zip (%ld + " ZD " > %ld)\n",
+                (long) dataOffset, (ZD_TYPE) uncompLen, (long) cdOffset);
             return false;
         }
 
@@ -732,8 +749,8 @@
             LOGE("Write failed: %s\n", strerror(errno));
             goto unmap;
         } else if ((size_t) actual != uncompLen) {
-            LOGE("Partial write during uncompress (%zd of %zd)\n",
-                (size_t)actual, (size_t)uncompLen);
+            LOGE("Partial write during uncompress (" ZD " of " ZD ")\n",
+                (ZD_TYPE) actual, (ZD_TYPE) uncompLen);
             goto unmap;
         } else {
             LOGI("+++ successful write\n");
@@ -802,8 +819,8 @@
 
     /* paranoia */
     if (zstream.total_out != uncompLen) {
-        LOGW("Size mismatch on inflated file (%ld vs %zd)\n",
-            zstream.total_out, uncompLen);
+        LOGW("Size mismatch on inflated file (%ld vs " ZD ")\n",
+            zstream.total_out, (ZD_TYPE) uncompLen);
         goto z_bail;
     }
 
@@ -891,8 +908,8 @@
 
     /* paranoia */
     if (zstream.total_out != uncompLen) {
-        LOGW("Size mismatch on inflated file (%ld vs %zd)\n",
-            zstream.total_out, uncompLen);
+        LOGW("Size mismatch on inflated file (%ld vs " ZD ")\n",
+            zstream.total_out, (ZD_TYPE) uncompLen);
         goto z_bail;
     }
 
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/LayerBase.cpp b/services/surfaceflinger/LayerBase.cpp
index 758b408..069b85a 100644
--- a/services/surfaceflinger/LayerBase.cpp
+++ b/services/surfaceflinger/LayerBase.cpp
@@ -444,11 +444,11 @@
     }
     if (transform & HAL_TRANSFORM_FLIP_V) {
         swap(vLT, vLB);
-        swap(vRB, vRT);
+        swap(vRT, vRB);
     }
     if (transform & HAL_TRANSFORM_FLIP_H) {
-        swap(vLT, vRB);
-        swap(vLB, vRT);
+        swap(vLT, vRT);
+        swap(vLB, vRB);
     }
 
     TexCoords texCoords[4];
diff --git a/services/surfaceflinger/MessageQueue.cpp b/services/surfaceflinger/MessageQueue.cpp
index d668e88..aebe1b8 100644
--- a/services/surfaceflinger/MessageQueue.cpp
+++ b/services/surfaceflinger/MessageQueue.cpp
@@ -72,14 +72,6 @@
             nsecs_t now = systemTime();
             nsecs_t nextEventTime = -1;
 
-            // invalidate messages are always handled first
-            if (mInvalidate) {
-                mInvalidate = false;
-                mInvalidateMessage->when = now;
-                result = mInvalidateMessage;
-                break;
-            }
-
             LIST::iterator cur(mMessages.begin());
             if (cur != mMessages.end()) {
                 result = *cur;
@@ -91,17 +83,29 @@
                     mMessages.remove(cur);
                     break;
                 }
-                if (timeout>=0 && timeoutTime < now) {
-                    // we timed-out, return a NULL message
-                    result = 0;
-                    break;
-                }
                 nextEventTime = result->when;
                 result = 0;
             }
 
-            if (timeout >= 0 && nextEventTime > 0) {
-                if (nextEventTime > timeoutTime) {
+            // see if we have an invalidate message
+            if (mInvalidate) {
+                mInvalidate = false;
+                mInvalidateMessage->when = now;
+                result = mInvalidateMessage;
+                break;
+            }
+
+            if (timeout >= 0) {
+                if (timeoutTime < now) {
+                    // we timed-out, return a NULL message
+                    result = 0;
+                    break;
+                }
+                if (nextEventTime > 0) {
+                    if (nextEventTime > timeoutTime) {
+                        nextEventTime = timeoutTime;
+                    }
+                } else {
                     nextEventTime = timeoutTime;
                 }
             }
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index e5e87c6..a9b3965 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -80,6 +80,7 @@
         mVisibleRegionsDirty(false),
         mDeferReleaseConsole(false),
         mFreezeDisplay(false),
+        mElectronBeamAnimationMode(0),
         mFreezeCount(0),
         mFreezeDisplayTime(0),
         mDebugRegion(0),
@@ -421,16 +422,19 @@
     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
+        SurfaceFlinger::turnElectronBeamOn(mElectronBeamAnimationMode);
     }
 
-    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 +1460,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 +1552,457 @@
 
 // ---------------------------------------------------------------------------
 
+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) {
+        while ( 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 12 frames
+    int nbFrames = 8;
+    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);
+    }
+
+    nbFrames = 4;
+    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(int32_t mode)
+{
+    DisplayHardware& hw(graphicPlane(0).editDisplayHardware());
+    if (!hw.canDraw()) {
+        // we're already off
+        return NO_ERROR;
+    }
+    if (mode & ISurfaceComposer::eElectronBeamAnimationOff) {
+        electronBeamOffAnimationImplLocked();
+    }
+
+    // always clear the whole screen at the end of the animation
+    glClearColor(0,0,0,1);
+    glDisable(GL_SCISSOR_TEST);
+    glClear(GL_COLOR_BUFFER_BIT);
+    glEnable(GL_SCISSOR_TEST);
+    hw.flip( Region(hw.bounds()) );
+
+    hw.setCanDraw(false);
+    return NO_ERROR;
+}
+
+status_t SurfaceFlinger::turnElectronBeamOff(int32_t mode)
+{
+    class MessageTurnElectronBeamOff : public MessageBase {
+        SurfaceFlinger* flinger;
+        int32_t mode;
+        status_t result;
+    public:
+        MessageTurnElectronBeamOff(SurfaceFlinger* flinger, int32_t mode)
+            : flinger(flinger), mode(mode), result(PERMISSION_DENIED) {
+        }
+        status_t getResult() const {
+            return result;
+        }
+        virtual bool handler() {
+            Mutex::Autolock _l(flinger->mStateLock);
+            result = flinger->turnElectronBeamOffImplLocked(mode);
+            return true;
+        }
+    };
+
+    sp<MessageBase> msg = new MessageTurnElectronBeamOff(this, mode);
+    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
+        mElectronBeamAnimationMode = mode;
+    }
+    return res;
+}
+
+// ---------------------------------------------------------------------------
+
+status_t SurfaceFlinger::turnElectronBeamOnImplLocked(int32_t mode)
+{
+    DisplayHardware& hw(graphicPlane(0).editDisplayHardware());
+    if (hw.canDraw()) {
+        // we're already on
+        return NO_ERROR;
+    }
+    if (mode & ISurfaceComposer::eElectronBeamAnimationOn) {
+        electronBeamOnAnimationImplLocked();
+    }
+    hw.setCanDraw(true);
+
+    // make sure to redraw the whole screen when the animation is done
+    mDirtyRegion.set(hw.bounds());
+    signalEvent();
+
+    return NO_ERROR;
+}
+
+status_t SurfaceFlinger::turnElectronBeamOn(int32_t mode)
+{
+    class MessageTurnElectronBeamOn : public MessageBase {
+        SurfaceFlinger* flinger;
+        int32_t mode;
+        status_t result;
+    public:
+        MessageTurnElectronBeamOn(SurfaceFlinger* flinger, int32_t mode)
+            : flinger(flinger), mode(mode), result(PERMISSION_DENIED) {
+        }
+        status_t getResult() const {
+            return result;
+        }
+        virtual bool handler() {
+            Mutex::Autolock _l(flinger->mStateLock);
+            result = flinger->turnElectronBeamOnImplLocked(mode);
+            return true;
+        }
+    };
+
+    postMessageAsync( new MessageTurnElectronBeamOn(this, mode) );
+    return NO_ERROR;
+}
+
+// ---------------------------------------------------------------------------
+
 status_t SurfaceFlinger::captureScreenImplLocked(DisplayID dpy,
         sp<IMemoryHeap>* heap,
         uint32_t* w, uint32_t* h, PixelFormat* f,
@@ -2005,6 +2462,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..4262175 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(int32_t mode);
+            status_t turnElectronBeamOnImplLocked(int32_t mode);
+            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;
+                int32_t                     mElectronBeamAnimationMode;
                 int32_t                     mFreezeCount;
                 nsecs_t                     mFreezeDisplayTime;
                 Vector< sp<LayerBase> >     mVisibleLayersSortedByZ;