Merge "Enable changing display configuration"
diff --git a/cmds/dumpstate/utils.c b/cmds/dumpstate/utils.c
index 577d31c..6b119c3 100644
--- a/cmds/dumpstate/utils.c
+++ b/cmds/dumpstate/utils.c
@@ -587,7 +587,7 @@
 
             /* wait for the writable-close notification from inotify */
             struct pollfd pfd = { ifd, POLLIN, 0 };
-            int ret = poll(&pfd, 1, 200);  /* 200 msec timeout */
+            int ret = poll(&pfd, 1, 5000);  /* 5 sec timeout */
             if (ret < 0) {
                 fprintf(stderr, "poll: %s\n", strerror(errno));
             } else if (ret == 0) {
diff --git a/data/etc/wearable_core_hardware.xml b/data/etc/wearable_core_hardware.xml
index 215665f..e256742 100644
--- a/data/etc/wearable_core_hardware.xml
+++ b/data/etc/wearable_core_hardware.xml
@@ -21,9 +21,7 @@
      Wearable devices include watches, glasses, backpacks, and sweaters.
 -->
 <permissions>
-    <feature name="android.hardware.camera" />
     <feature name="android.hardware.location" />
-    <feature name="android.hardware.location.network" />
     <feature name="android.hardware.sensor.compass" />
     <feature name="android.hardware.sensor.accelerometer" />
     <feature name="android.hardware.bluetooth" />
@@ -34,11 +32,9 @@
 
     <!-- basic system services -->
     <feature name="android.software.home_screen" />
-    <feature name="android.software.input_methods" />
 
-    <!-- Feature to specify if the device supports adding device admins. -->
-    <feature name="android.software.device_admin" />
-
+    <!-- devices that support a device administrator policy must include
+         android.software.device_admin.xml -->
     <!-- devices with GPS must include android.hardware.location.gps.xml -->
     <!-- devices with an autofocus camera and/or flash must include either
          android.hardware.camera.autofocus.xml or
diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h
index 609b679..8ffdfca 100644
--- a/include/input/InputTransport.h
+++ b/include/input/InputTransport.h
@@ -86,7 +86,7 @@
             float yOffset;
             float xPrecision;
             float yPrecision;
-            size_t pointerCount;
+            uint32_t pointerCount;
             struct Pointer {
                 PointerProperties properties;
                 PointerCoords coords;
@@ -234,7 +234,7 @@
             float yPrecision,
             nsecs_t downTime,
             nsecs_t eventTime,
-            size_t pointerCount,
+            uint32_t pointerCount,
             const PointerProperties* pointerProperties,
             const PointerCoords* pointerCoords);
 
@@ -360,7 +360,7 @@
         void initializeFrom(const InputMessage* msg) {
             eventTime = msg->body.motion.eventTime;
             idBits.clear();
-            for (size_t i = 0; i < msg->body.motion.pointerCount; i++) {
+            for (uint32_t i = 0; i < msg->body.motion.pointerCount; i++) {
                 uint32_t id = msg->body.motion.pointers[i].properties.id;
                 idBits.markBit(id);
                 idToIndex[id] = i;
diff --git a/include/media/openmax/OMX_IndexExt.h b/include/media/openmax/OMX_IndexExt.h
index c503dcf..7070809 100644
--- a/include/media/openmax/OMX_IndexExt.h
+++ b/include/media/openmax/OMX_IndexExt.h
@@ -72,6 +72,8 @@
     OMX_IndexConfigVideoVp8ReferenceFrame,          /**< reference: OMX_VIDEO_VP8REFERENCEFRAMETYPE */
     OMX_IndexConfigVideoVp8ReferenceFrameType,      /**< reference: OMX_VIDEO_VP8REFERENCEFRAMEINFOTYPE */
     OMX_IndexParamVideoAndroidVp8Encoder,           /**< reference: OMX_VIDEO_PARAM_ANDROID_VP8ENCODERTYPE */
+    OMX_IndexParamVideoHevc,                        /**< reference: OMX_VIDEO_PARAM_HEVCTYPE */
+    OMX_IndexParamSliceSegments,                    /**< reference: OMX_VIDEO_SLICESEGMENTSTYPE */
 
     /* Image & Video common configurations */
     OMX_IndexExtCommonStartUnused = OMX_IndexKhronosExtensions + 0x00700000,
diff --git a/include/media/openmax/OMX_Video.h b/include/media/openmax/OMX_Video.h
index 4441a7a..21dc5a6 100644
--- a/include/media/openmax/OMX_Video.h
+++ b/include/media/openmax/OMX_Video.h
@@ -87,6 +87,7 @@
     OMX_VIDEO_CodingMJPEG,      /**< Motion JPEG */
     OMX_VIDEO_CodingVP8,        /**< Google VP8, formerly known as On2 VP8 */
     OMX_VIDEO_CodingVP9,        /**< Google VP9 */
+    OMX_VIDEO_CodingHEVC,       /**< ITU H.265/HEVC */
     OMX_VIDEO_CodingKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ 
     OMX_VIDEO_CodingVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
     OMX_VIDEO_CodingMax = 0x7FFFFFFF
diff --git a/include/media/openmax/OMX_VideoExt.h b/include/media/openmax/OMX_VideoExt.h
index 3f18b43..fb10cbb 100644
--- a/include/media/openmax/OMX_VideoExt.h
+++ b/include/media/openmax/OMX_VideoExt.h
@@ -145,6 +145,63 @@
     OMX_U32 nMaxQuantizer;
 };
 
+/** HEVC Profile enum type */
+typedef enum OMX_VIDEO_HEVCPROFILETYPE {
+    OMX_VIDEO_HEVCProfileUnknown = 0x0,
+    OMX_VIDEO_HEVCProfileMain    = 0x1,
+    OMX_VIDEO_HEVCProfileMain10  = 0x2,
+    OMX_VIDEO_HEVCProfileMax     = 0x7FFFFFFF
+} OMX_VIDEO_HEVCPROFILETYPE;
+
+/** HEVC Level enum type */
+typedef enum OMX_VIDEO_HEVCLEVELTYPE {
+    OMX_VIDEO_HEVCLevelUnknown    = 0x0,
+    OMX_VIDEO_HEVCMainTierLevel1  = 0x1,
+    OMX_VIDEO_HEVCHighTierLevel1  = 0x2,
+    OMX_VIDEO_HEVCMainTierLevel2  = 0x4,
+    OMX_VIDEO_HEVCHighTierLevel2  = 0x8,
+    OMX_VIDEO_HEVCMainTierLevel21 = 0x10,
+    OMX_VIDEO_HEVCHighTierLevel21 = 0x20,
+    OMX_VIDEO_HEVCMainTierLevel3  = 0x40,
+    OMX_VIDEO_HEVCHighTierLevel3  = 0x80,
+    OMX_VIDEO_HEVCMainTierLevel31 = 0x100,
+    OMX_VIDEO_HEVCHighTierLevel31 = 0x200,
+    OMX_VIDEO_HEVCMainTierLevel4  = 0x400,
+    OMX_VIDEO_HEVCHighTierLevel4  = 0x800,
+    OMX_VIDEO_HEVCMainTierLevel41 = 0x1000,
+    OMX_VIDEO_HEVCHighTierLevel41 = 0x2000,
+    OMX_VIDEO_HEVCMainTierLevel5  = 0x4000,
+    OMX_VIDEO_HEVCHighTierLevel5  = 0x8000,
+    OMX_VIDEO_HEVCMainTierLevel51 = 0x10000,
+    OMX_VIDEO_HEVCHighTierLevel51 = 0x20000,
+    OMX_VIDEO_HEVCMainTierLevel52 = 0x40000,
+    OMX_VIDEO_HEVCHighTierLevel52 = 0x80000,
+    OMX_VIDEO_HEVCMainTierLevel6  = 0x100000,
+    OMX_VIDEO_HEVCHighTierLevel6  = 0x200000,
+    OMX_VIDEO_HEVCMainTierLevel61 = 0x400000,
+    OMX_VIDEO_HEVCHighTierLevel61 = 0x800000,
+    OMX_VIDEO_HEVCMainTierLevel62 = 0x1000000,
+    OMX_VIDEO_HEVCHighTierLevel62 = 0x2000000,
+    OMX_VIDEO_HEVCHighTiermax     = 0x7FFFFFFF
+} OMX_VIDEO_HEVCLEVELTYPE;
+
+/** Structure for controlling HEVC video encoding and decoding */
+typedef struct OMX_VIDEO_PARAM_HEVCTYPE {
+    OMX_U32 nSize;
+    OMX_VERSIONTYPE nVersion;
+    OMX_U32 nPortIndex;
+    OMX_VIDEO_HEVCPROFILETYPE eProfile;
+    OMX_VIDEO_HEVCLEVELTYPE eLevel;
+} OMX_VIDEO_PARAM_HEVCTYPE;
+
+/** Structure to define if dependent slice segments should be used */
+typedef struct OMX_VIDEO_SLICESEGMENTSTYPE {
+    OMX_U32 nSize;
+    OMX_VERSIONTYPE nVersion;
+    OMX_U32 nPortIndex;
+    OMX_BOOL bDepedentSegments;
+    OMX_BOOL bEnableLoopFilterAcrossSlices;
+} OMX_VIDEO_SLICESEGMENTSTYPE;
 
 #ifdef __cplusplus
 }
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 4298522..52fff82 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -25,6 +25,7 @@
 #include <binder/ProcessState.h>
 #include <binder/TextOutput.h>
 
+#include <errno.h>
 #include <utils/Debug.h>
 #include <utils/Log.h>
 #include <utils/String8.h>
@@ -1284,7 +1285,11 @@
     status_t err = NO_ERROR;
     for (size_t i=0 ; i<fd_count && err==NO_ERROR ; i++) {
         fds[i] = dup(this->readFileDescriptor());
-        if (fds[i] < 0) err = BAD_VALUE;
+        if (fds[i] < 0) {
+            err = BAD_VALUE;
+            ALOGE("dup() failed in Parcel::read, i is %d, fds[i] is %d, fd_count is %d, error: %s",
+                i, fds[i], fd_count, strerror(errno));
+        }
     }
 
     if (err == NO_ERROR) {
diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp
index a73780d..5bad2e6 100644
--- a/libs/input/InputTransport.cpp
+++ b/libs/input/InputTransport.cpp
@@ -292,7 +292,7 @@
         float yPrecision,
         nsecs_t downTime,
         nsecs_t eventTime,
-        size_t pointerCount,
+        uint32_t pointerCount,
         const PointerProperties* pointerProperties,
         const PointerCoords* pointerCoords) {
 #if DEBUG_TRANSPORT_ACTIONS
@@ -334,7 +334,7 @@
     msg.body.motion.downTime = downTime;
     msg.body.motion.eventTime = eventTime;
     msg.body.motion.pointerCount = pointerCount;
-    for (size_t i = 0; i < pointerCount; i++) {
+    for (uint32_t i = 0; i < pointerCount; i++) {
         msg.body.motion.pointers[i].properties.copyFrom(pointerProperties[i]);
         msg.body.motion.pointers[i].coords.copyFrom(pointerCoords[i]);
     }
@@ -654,7 +654,7 @@
 }
 
 void InputConsumer::rewriteMessage(const TouchState& state, InputMessage* msg) {
-    for (size_t i = 0; i < msg->body.motion.pointerCount; i++) {
+    for (uint32_t i = 0; i < msg->body.motion.pointerCount; i++) {
         uint32_t id = msg->body.motion.pointers[i].properties.id;
         if (state.lastResample.idBits.hasBit(id)) {
             PointerCoords& msgCoords = msg->body.motion.pointers[i].coords;
@@ -894,10 +894,10 @@
 }
 
 void InputConsumer::initializeMotionEvent(MotionEvent* event, const InputMessage* msg) {
-    size_t pointerCount = msg->body.motion.pointerCount;
+    uint32_t pointerCount = msg->body.motion.pointerCount;
     PointerProperties pointerProperties[pointerCount];
     PointerCoords pointerCoords[pointerCount];
-    for (size_t i = 0; i < pointerCount; i++) {
+    for (uint32_t i = 0; i < pointerCount; i++) {
         pointerProperties[i].copyFrom(msg->body.motion.pointers[i].properties);
         pointerCoords[i].copyFrom(msg->body.motion.pointers[i].coords);
     }
@@ -922,9 +922,9 @@
 }
 
 void InputConsumer::addSample(MotionEvent* event, const InputMessage* msg) {
-    size_t pointerCount = msg->body.motion.pointerCount;
+    uint32_t pointerCount = msg->body.motion.pointerCount;
     PointerCoords pointerCoords[pointerCount];
-    for (size_t i = 0; i < pointerCount; i++) {
+    for (uint32_t i = 0; i < pointerCount; i++) {
         pointerCoords[i].copyFrom(msg->body.motion.pointers[i].coords);
     }
 
@@ -934,7 +934,7 @@
 
 bool InputConsumer::canAddSample(const Batch& batch, const InputMessage *msg) {
     const InputMessage& head = batch.samples.itemAt(0);
-    size_t pointerCount = msg->body.motion.pointerCount;
+    uint32_t pointerCount = msg->body.motion.pointerCount;
     if (head.body.motion.pointerCount != pointerCount
             || head.body.motion.action != msg->body.motion.action) {
         return false;
diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp
index 0bae399..a750a3d 100644
--- a/services/inputflinger/InputDispatcher.cpp
+++ b/services/inputflinger/InputDispatcher.cpp
@@ -1965,7 +1965,7 @@
                 xOffset = dispatchEntry->xOffset * scaleFactor;
                 yOffset = dispatchEntry->yOffset * scaleFactor;
                 if (scaleFactor != 1.0f) {
-                    for (size_t i = 0; i < motionEntry->pointerCount; i++) {
+                    for (uint32_t i = 0; i < motionEntry->pointerCount; i++) {
                         scaledCoords[i] = motionEntry->pointerCoords[i];
                         scaledCoords[i].scale(scaleFactor);
                     }
@@ -1978,7 +1978,7 @@
 
                 // We don't want the dispatch target to know.
                 if (dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS) {
-                    for (size_t i = 0; i < motionEntry->pointerCount; i++) {
+                    for (uint32_t i = 0; i < motionEntry->pointerCount; i++) {
                         scaledCoords[i].clear();
                     }
                     usingCoords = scaledCoords;
diff --git a/services/surfaceflinger/DispSync.cpp b/services/surfaceflinger/DispSync.cpp
index 602f20a..fd46822 100644
--- a/services/surfaceflinger/DispSync.cpp
+++ b/services/surfaceflinger/DispSync.cpp
@@ -61,7 +61,10 @@
 public:
 
     DispSyncThread():
+            mLowPowerMode(false),
             mStop(false),
+            mLastVsyncSent(false),
+            mLastBufferFull(false),
             mPeriod(0),
             mPhase(0),
             mWakeupLatency(0) {
@@ -145,7 +148,18 @@
             }
 
             if (callbackInvocations.size() > 0) {
-                fireCallbackInvocations(callbackInvocations);
+                if (mLowPowerMode) {
+                    if (!mLastVsyncSent || !mLastBufferFull) {
+                        fireCallbackInvocations(callbackInvocations);
+                        mLastVsyncSent = true;
+                    } else
+                        mLastVsyncSent = false;
+                } else {
+                    fireCallbackInvocations(callbackInvocations);
+                }
+                mLastBufferFull = true;
+            } else {
+                mLastBufferFull = false;
             }
         }
 
@@ -200,6 +214,7 @@
         return !mEventListeners.empty();
     }
 
+    bool mLowPowerMode;
 private:
 
     struct EventListener {
@@ -272,6 +287,8 @@
     }
 
     bool mStop;
+    bool mLastVsyncSent;
+    bool mLastBufferFull;
 
     nsecs_t mPeriod;
     nsecs_t mPhase;
@@ -395,6 +412,10 @@
     return mThread->addEventListener(phase, callback);
 }
 
+void DispSync::setLowPowerMode(bool enabled) {
+    mThread->mLowPowerMode = enabled;
+}
+
 status_t DispSync::removeEventListener(const sp<Callback>& callback) {
     Mutex::Autolock lock(mMutex);
     return mThread->removeEventListener(callback);
@@ -487,4 +508,9 @@
     }
 }
 
+nsecs_t DispSync::computeNextRefresh(int periodOffset) const {
+    nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
+    return (((now - mPhase) / mPeriod) + periodOffset + 1) * mPeriod + mPhase;
+}
+
 } // namespace android
diff --git a/services/surfaceflinger/DispSync.h b/services/surfaceflinger/DispSync.h
index c4280aa..5826a78 100644
--- a/services/surfaceflinger/DispSync.h
+++ b/services/surfaceflinger/DispSync.h
@@ -83,11 +83,14 @@
     bool addResyncSample(nsecs_t timestamp);
     void endResync();
 
-    // The setPreiod method sets the vsync event model's period to a specific
+    // The setPeriod method sets the vsync event model's period to a specific
     // value.  This should be used to prime the model when a display is first
     // turned on.  It should NOT be used after that.
     void setPeriod(nsecs_t period);
 
+    // Setting the low power mode reduces the frame rate to half of the default
+    void setLowPowerMode(bool enabled);
+
     // addEventListener registers a callback to be called repeatedly at the
     // given phase offset from the hardware vsync events.  The callback is
     // called from a separate thread and it should return reasonably quickly
@@ -99,6 +102,12 @@
     // DispSync object.
     status_t removeEventListener(const sp<Callback>& callback);
 
+    // computeNextRefresh computes when the next refresh is expected to begin.
+    // The periodOffset value can be used to move forward or backward; an
+    // offset of zero is the next refresh, -1 is the previous refresh, 1 is
+    // the refresh after next. etc.
+    nsecs_t computeNextRefresh(int periodOffset) const;
+
 private:
 
     void updateModelLocked();
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 4dccc22..51c7059 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -848,7 +848,7 @@
     return NO_ERROR;
 }
 
-sp<Fence> HWComposer::getLastRetireFence(int32_t id) {
+sp<Fence> HWComposer::getLastRetireFence(int32_t id) const {
     if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id))
         return Fence::NO_FENCE;
     return mDisplayData[id].lastRetireFence;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 32d4a0c..2f92672 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -142,7 +142,7 @@
     // signal when the h/w composer is completely finished with the frame.
     // For physical displays, it is no longer being displayed. For virtual
     // displays, writes to the output buffer are complete.
-    sp<Fence> getLastRetireFence(int32_t id);
+    sp<Fence> getLastRetireFence(int32_t id) const;
 
     /*
      * Interface to hardware composer's layers functionality.
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
index 1362ae8..c415560 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
@@ -302,7 +302,12 @@
         }
     }
     if (result & BUFFER_NEEDS_REALLOCATION) {
-        mSource[source]->requestBuffer(*sslot, &mProducerBuffers[pslot]);
+        result = mSource[source]->requestBuffer(*sslot, &mProducerBuffers[pslot]);
+        if (result < 0) {
+            mProducerBuffers[pslot].clear();
+            mSource[source]->cancelBuffer(*sslot, *fence);
+            return result;
+        }
         VDS_LOGV("dequeueBuffer(%s): buffers[%d]=%p fmt=%d usage=%#x",
                 dbgSourceStr(source), pslot, mProducerBuffers[pslot].get(),
                 mProducerBuffers[pslot]->getPixelFormat(),
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 1b86204..63bc257 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -1095,7 +1095,8 @@
 
         Reject r(mDrawingState, getCurrentState(), recomputeVisibleRegions);
 
-        status_t updateResult = mSurfaceFlingerConsumer->updateTexImage(&r);
+        status_t updateResult = mSurfaceFlingerConsumer->updateTexImage(&r,
+                mFlinger->mPrimaryDispSync);
         if (updateResult == BufferQueue::PRESENT_LATER) {
             // Producer doesn't want buffer to be displayed yet.  Signal a
             // layer update so we check again at the next opportunity.
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 46e192e..32d173d 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -2394,6 +2394,15 @@
     result.append(SyncFeatures::getInstance().toString());
     result.append("\n");
 
+    colorizer.bold(result);
+    result.append("DispSync configuration: ");
+    colorizer.reset(result);
+    result.appendFormat("app phase %"PRId64" ns, sf phase %"PRId64" ns, "
+            "present offset %d ns (refresh %"PRId64" ns)",
+        vsyncPhaseOffsetNs, sfVsyncPhaseOffsetNs, PRESENT_TIME_OFFSET_FROM_VSYNC_NS,
+        mHwc->getRefreshPeriod(HWC_DISPLAY_PRIMARY));
+    result.append("\n");
+
     /*
      * Dump the visible layer list
      */
@@ -2666,6 +2675,16 @@
                 repaintEverything();
                 return NO_ERROR;
             }
+            // This is an experimental interface
+            // Needs to be shifted to proper binder interface when we productize
+            case 1016: {
+                mPrimaryDispSync.setLowPowerMode(true);
+                return NO_ERROR;
+            }
+            case 1017: {
+                mPrimaryDispSync.setLowPowerMode(false);
+                return NO_ERROR;
+            }
         }
     }
     return err;
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.cpp b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
index a412543..7de6ac4 100644
--- a/services/surfaceflinger/SurfaceFlingerConsumer.cpp
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
@@ -29,7 +29,8 @@
 
 // ---------------------------------------------------------------------------
 
-status_t SurfaceFlingerConsumer::updateTexImage(BufferRejecter* rejecter)
+status_t SurfaceFlingerConsumer::updateTexImage(BufferRejecter* rejecter,
+        const DispSync& dispSync)
 {
     ATRACE_CALL();
     ALOGV("updateTexImage");
@@ -51,7 +52,7 @@
     // Acquire the next buffer.
     // In asynchronous mode the list is guaranteed to be one buffer
     // deep, while in synchronous mode we use the oldest buffer.
-    err = acquireBufferLocked(&item, computeExpectedPresent());
+    err = acquireBufferLocked(&item, computeExpectedPresent(dispSync));
     if (err != NO_ERROR) {
         if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
             err = NO_ERROR;
@@ -128,35 +129,41 @@
 // will be slightly later then the actual-present timing.  If we get a
 // desired-present time that is unintentionally a hair after the next
 // vsync, we'll hold the frame when we really want to display it.  We
-// want to use an expected-presentation time that is slightly late to
-// avoid this sort of edge case.
-nsecs_t SurfaceFlingerConsumer::computeExpectedPresent()
+// need to take the offset between actual-present and reported-vsync
+// into account.
+//
+// If the system is configured without a DispSync phase offset for the app,
+// we also want to throw in a bit of padding to avoid edge cases where we
+// just barely miss.  We want to do it here, not in every app.  A major
+// source of trouble is the app's use of the display's ideal refresh time
+// (via Display.getRefreshRate()), which could be off of the actual refresh
+// by a few percent, with the error multiplied by the number of frames
+// between now and when the buffer should be displayed.
+//
+// If the refresh reported to the app has a phase offset, we shouldn't need
+// to tweak anything here.
+nsecs_t SurfaceFlingerConsumer::computeExpectedPresent(const DispSync& dispSync)
 {
-    // Don't yet have an easy way to get actual buffer flip time for
-    // the specific display, so use the current time.  This is typically
-    // 1.3ms past the vsync event time.
-    const nsecs_t prevVsync = systemTime(CLOCK_MONOTONIC);
-
-    // Given a SurfaceFlinger reference, and information about what display
-    // we're destined for, we could query the HWC for the refresh rate.  This
-    // could change over time, e.g. we could switch to 24fps for a movie.
-    // For now, assume 60fps.
-    //const nsecs_t vsyncPeriod =
-    //        getHwComposer().getRefreshPeriod(HWC_DISPLAY_PRIMARY);
-    const nsecs_t vsyncPeriod = 16700000;
-
     // The HWC doesn't currently have a way to report additional latency.
-    // Assume that whatever we submit now will appear on the next flip,
-    // i.e. 1 frame of latency w.r.t. the previous flip.
-    const uint32_t hwcLatency = 1;
+    // Assume that whatever we submit now will appear right after the flip.
+    // For a smart panel this might be 1.  This is expressed in frames,
+    // rather than time, because we expect to have a constant frame delay
+    // regardless of the refresh rate.
+    const uint32_t hwcLatency = 0;
 
-    // A little extra padding to compensate for slack between actual vsync
-    // time and vsync event receipt.  Currently not needed since we're
-    // using "now" instead of a vsync time.
-    const nsecs_t extraPadding = 0;
+    // Ask DispSync when the next refresh will be (CLOCK_MONOTONIC).
+    const nsecs_t nextRefresh = dispSync.computeNextRefresh(hwcLatency);
 
-    // Total it up.
-    return prevVsync + hwcLatency * vsyncPeriod + extraPadding;
+    // The DispSync time is already adjusted for the difference between
+    // vsync and reported-vsync (PRESENT_TIME_OFFSET_FROM_VSYNC_NS), so
+    // we don't need to factor that in here.  Pad a little to avoid
+    // weird effects if apps might be requesting times right on the edge.
+    nsecs_t extraPadding = 0;
+    if (VSYNC_EVENT_PHASE_OFFSET_NS == 0) {
+        extraPadding = 1000000;        // 1ms (6% of 60Hz)
+    }
+
+    return nextRefresh + extraPadding;
 }
 
 void SurfaceFlingerConsumer::setContentsChangedListener(
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.h b/services/surfaceflinger/SurfaceFlingerConsumer.h
index 0f1bf35..ed307c2 100644
--- a/services/surfaceflinger/SurfaceFlingerConsumer.h
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.h
@@ -17,6 +17,7 @@
 #ifndef ANDROID_SURFACEFLINGERCONSUMER_H
 #define ANDROID_SURFACEFLINGERCONSUMER_H
 
+#include "DispSync.h"
 #include <gui/GLConsumer.h>
 
 namespace android {
@@ -33,7 +34,8 @@
 
     SurfaceFlingerConsumer(const sp<IGraphicBufferConsumer>& consumer,
             uint32_t tex)
-        : GLConsumer(consumer, tex, GLConsumer::TEXTURE_EXTERNAL, false)
+        : GLConsumer(consumer, tex, GLConsumer::TEXTURE_EXTERNAL, false),
+          mTransformToDisplayInverse(false)
     {}
 
     class BufferRejecter {
@@ -51,7 +53,7 @@
     // reject the newly acquired buffer.  Unlike the GLConsumer version,
     // this does not guarantee that the buffer has been bound to the GL
     // texture.
-    status_t updateTexImage(BufferRejecter* rejecter);
+    status_t updateTexImage(BufferRejecter* rejecter, const DispSync& dispSync);
 
     // See GLConsumer::bindTextureImageLocked().
     status_t bindTextureImage();
@@ -66,7 +68,7 @@
     sp<NativeHandle> getSidebandStream() const;
 
 private:
-    nsecs_t computeExpectedPresent();
+    nsecs_t computeExpectedPresent(const DispSync& dispSync);
 
     virtual void onSidebandStreamChanged();