merge in lmp-mr1-release history after reset to lmp-mr1-dev
diff --git a/data/etc/android.software.voice_recognizers.xml b/data/etc/android.software.voice_recognizers.xml
index 7e72177..435eed4 100644
--- a/data/etc/android.software.voice_recognizers.xml
+++ b/data/etc/android.software.voice_recognizers.xml
@@ -15,5 +15,5 @@
 -->
 
 <permissions>
-    <feature name="android.software.voice_recognizers" />
+    <feature name="android.software.voice_recognizers" notLowRam="true" />
 </permissions>
diff --git a/data/etc/handheld_core_hardware.xml b/data/etc/handheld_core_hardware.xml
index eaf93fd..50cbe9e 100644
--- a/data/etc/handheld_core_hardware.xml
+++ b/data/etc/handheld_core_hardware.xml
@@ -38,7 +38,7 @@
     <!-- basic system services -->
     <feature name="android.software.app_widgets" />
     <feature name="android.software.connectionservice" />
-    <feature name="android.software.voice_recognizers" />
+    <feature name="android.software.voice_recognizers" notLowRam="true" />
     <feature name="android.software.backup" />
     <feature name="android.software.home_screen" />
     <feature name="android.software.input_methods" />
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index acc2775..c3e1a76 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -34,6 +34,7 @@
 #include <ui/GraphicBuffer.h>
 #include <ui/PixelFormat.h>
 
+#include <gui/BufferItem.h>
 #include <gui/Surface.h>
 
 #include "clz.h"
@@ -159,11 +160,26 @@
     }
 }
 
-void Layer::onFrameAvailable(const BufferItem& /* item */) {
+void Layer::onFrameAvailable(const BufferItem& item) {
+    // Add this buffer from our internal queue tracker
+    { // Autolock scope
+        Mutex::Autolock lock(mQueueItemLock);
+        mQueueItems.push_back(item);
+    }
+
     android_atomic_inc(&mQueuedFrames);
     mFlinger->signalLayerUpdate();
 }
 
+void Layer::onFrameReplaced(const BufferItem& item) {
+    Mutex::Autolock lock(mQueueItemLock);
+    if (mQueueItems.empty()) {
+        ALOGE("Can't replace a frame on an empty queue");
+        return;
+    }
+    mQueueItems.editItemAt(0) = item;
+}
+
 void Layer::onSidebandStreamChanged() {
     if (android_atomic_release_cas(false, true, &mSidebandStreamChanged) == 0) {
         // mSidebandStreamChanged was false
@@ -1014,6 +1030,14 @@
 // pageflip handling...
 // ----------------------------------------------------------------------------
 
+bool Layer::shouldPresentNow(const DispSync& dispSync) const {
+    Mutex::Autolock lock(mQueueItemLock);
+    nsecs_t expectedPresent =
+            mSurfaceFlingerConsumer->computeExpectedPresent(dispSync);
+    return mQueueItems.empty() ?
+            false : mQueueItems[0].mTimestamp < expectedPresent;
+}
+
 bool Layer::onPreComposition() {
     mRefreshPending = false;
     return mQueuedFrames > 0 || mSidebandStreamChanged;
@@ -1203,6 +1227,12 @@
             return outDirtyRegion;
         }
 
+        // Remove this buffer from our internal queue tracker
+        { // Autolock scope
+            Mutex::Autolock lock(mQueueItemLock);
+            mQueueItems.removeAt(0);
+        }
+
         // Decrement the queued-frames count.  Signal another event if we
         // have more frames pending.
         if (android_atomic_dec(&mQueuedFrames) > 1) {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index e2100fc..1d4eee7 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -210,6 +210,8 @@
     void onLayerDisplayed(const sp<const DisplayDevice>& hw,
             HWComposer::HWCLayerInterface* layer);
 
+    bool shouldPresentNow(const DispSync& dispSync) const;
+
     /*
      * called before composition.
      * returns true if the layer has pending updates.
@@ -331,6 +333,7 @@
 private:
     // Interface implementation for SurfaceFlingerConsumer::ContentsChangedListener
     virtual void onFrameAvailable(const BufferItem& item);
+    virtual void onFrameReplaced(const BufferItem& item);
     virtual void onSidebandStreamChanged();
 
     void commitTransaction();
@@ -404,6 +407,10 @@
 
     // This layer can be a cursor on some displays.
     bool mPotentialCursor;
+
+    // Local copy of the queued contents of the incoming BufferQueue
+    mutable Mutex mQueueItemLock;
+    Vector<BufferItem> mQueueItems;
 };
 
 // ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index c469627..b8b6472 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -829,30 +829,39 @@
 void SurfaceFlinger::onMessageReceived(int32_t what) {
     ATRACE_CALL();
     switch (what) {
-    case MessageQueue::TRANSACTION:
-        handleMessageTransaction();
-        break;
-    case MessageQueue::INVALIDATE:
-        handleMessageTransaction();
-        handleMessageInvalidate();
-        signalRefresh();
-        break;
-    case MessageQueue::REFRESH:
-        handleMessageRefresh();
-        break;
+        case MessageQueue::TRANSACTION: {
+            handleMessageTransaction();
+            break;
+        }
+        case MessageQueue::INVALIDATE: {
+            bool refreshNeeded = handleMessageTransaction();
+            refreshNeeded |= handleMessageInvalidate();
+            if (refreshNeeded) {
+                // Signal a refresh if a transaction modified the window state or if
+                // a new buffer was latched
+                signalRefresh();
+            }
+            break;
+        }
+        case MessageQueue::REFRESH: {
+            handleMessageRefresh();
+            break;
+        }
     }
 }
 
-void SurfaceFlinger::handleMessageTransaction() {
+bool SurfaceFlinger::handleMessageTransaction() {
     uint32_t transactionFlags = peekTransactionFlags(eTransactionMask);
     if (transactionFlags) {
         handleTransaction(transactionFlags);
+        return true;
     }
+    return false;
 }
 
-void SurfaceFlinger::handleMessageInvalidate() {
+bool SurfaceFlinger::handleMessageInvalidate() {
     ATRACE_CALL();
-    handlePageFlip();
+    return handlePageFlip();
 }
 
 void SurfaceFlinger::handleMessageRefresh() {
@@ -1685,12 +1694,13 @@
     }
 }
 
-void SurfaceFlinger::handlePageFlip()
+bool SurfaceFlinger::handlePageFlip()
 {
     Region dirtyRegion;
 
     bool visibleRegions = false;
     const LayerVector& layers(mDrawingState.layersSortedByZ);
+    bool frameQueued = false;
 
     // Store the set of layers that need updates. This set must not change as
     // buffers are being latched, as this could result in a deadlock.
@@ -1704,8 +1714,12 @@
     Vector<Layer*> layersWithQueuedFrames;
     for (size_t i = 0, count = layers.size(); i<count ; i++) {
         const sp<Layer>& layer(layers[i]);
-        if (layer->hasQueuedFrame())
-            layersWithQueuedFrames.push_back(layer.get());
+        if (layer->hasQueuedFrame()) {
+            frameQueued = true;
+            if (layer->shouldPresentNow(mPrimaryDispSync)) {
+                layersWithQueuedFrames.push_back(layer.get());
+            }
+        }
     }
     for (size_t i = 0, count = layersWithQueuedFrames.size() ; i<count ; i++) {
         Layer* layer = layersWithQueuedFrames[i];
@@ -1715,6 +1729,16 @@
     }
 
     mVisibleRegionsDirty |= visibleRegions;
+
+    // If we will need to wake up at some time in the future to deal with a
+    // queued frame that shouldn't be displayed during this vsync period, wake
+    // up during the next vsync period to check again.
+    if (frameQueued && layersWithQueuedFrames.empty()) {
+        signalLayerUpdate();
+    }
+
+    // Only continue with the refresh if there is actually new work to do
+    return !layersWithQueuedFrames.empty();
 }
 
 void SurfaceFlinger::invalidateHwcGeometry()
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 710dac7..4deb815 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -247,8 +247,12 @@
     // called on the main thread in response to setPowerMode()
     void setPowerModeInternal(const sp<DisplayDevice>& hw, int mode);
 
-    void handleMessageTransaction();
-    void handleMessageInvalidate();
+    // Returns whether the transaction actually modified any state
+    bool handleMessageTransaction();
+
+    // Returns whether a new buffer has been latched (see handlePageFlip())
+    bool handleMessageInvalidate();
+
     void handleMessageRefresh();
 
     void handleTransaction(uint32_t transactionFlags);
@@ -256,10 +260,11 @@
 
     void updateCursorAsync();
 
-    /* handlePageFilp: this is were we latch a new buffer
-     * if available and compute the dirty region.
+    /* handlePageFlip - latch a new buffer if available and compute the dirty
+     * region. Returns whether a new buffer has been latched, i.e., whether it
+     * is necessary to perform a refresh during this vsync.
      */
-    void handlePageFlip();
+    bool handlePageFlip();
 
     /* ------------------------------------------------------------------------
      * Transactions
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.h b/services/surfaceflinger/SurfaceFlingerConsumer.h
index 5633980..28f2f6a 100644
--- a/services/surfaceflinger/SurfaceFlingerConsumer.h
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.h
@@ -67,9 +67,9 @@
 
     sp<NativeHandle> getSidebandStream() const;
 
-private:
     nsecs_t computeExpectedPresent(const DispSync& dispSync);
 
+private:
     virtual void onSidebandStreamChanged();
 
     wp<ContentsChangedListener> mContentsChangedListener;