Add setOverrideScalingMode to SurfaceControl

Provide an interface for the window manager to override
the client specified scaling mode. This makes it possible
for the window manager to force windows to be scaleable
for animations, etc, even when a resize is pending.

Bug: 27891386
Change-Id: Ic4aae9917bd6869ee0dbb425979b4e21c68342a3
diff --git a/include/gui/SurfaceComposerClient.h b/include/gui/SurfaceComposerClient.h
index 9161dbb..73f923c 100644
--- a/include/gui/SurfaceComposerClient.h
+++ b/include/gui/SurfaceComposerClient.h
@@ -138,6 +138,8 @@
     status_t    setLayerStack(const sp<IBinder>& id, uint32_t layerStack);
     status_t    deferTransactionUntil(const sp<IBinder>& id,
             const sp<IBinder>& handle, uint64_t frameNumber);
+    status_t    setOverrideScalingMode(const sp<IBinder>& id,
+            int32_t overrideScalingMode);
     status_t    destroySurface(const sp<IBinder>& id);
 
     status_t clearLayerFrameStats(const sp<IBinder>& token) const;
diff --git a/include/gui/SurfaceControl.h b/include/gui/SurfaceControl.h
index 35644db..bedebb6 100644
--- a/include/gui/SurfaceControl.h
+++ b/include/gui/SurfaceControl.h
@@ -77,6 +77,11 @@
     // identified by handle reaches the given frameNumber
     status_t deferTransactionUntil(sp<IBinder> handle, uint64_t frameNumber);
 
+    // Set an override scaling mode as documented in <system/window.h>
+    // the override scaling mode will take precedence over any client
+    // specified scaling mode. -1 will clear the override scaling mode.
+    status_t setOverrideScalingMode(int32_t overrideScalingMode);
+
     static status_t writeSurfaceToParcel(
             const sp<SurfaceControl>& control, Parcel* parcel);
 
diff --git a/include/private/gui/LayerState.h b/include/private/gui/LayerState.h
index 078720a..92d31d1 100644
--- a/include/private/gui/LayerState.h
+++ b/include/private/gui/LayerState.h
@@ -53,7 +53,8 @@
         eLayerStackChanged          = 0x00000080,
         eCropChanged                = 0x00000100,
         eDeferTransaction           = 0x00000200,
-        eFinalCropChanged           = 0x00000400
+        eFinalCropChanged           = 0x00000400,
+        eOverrideScalingModeChanged = 0x00000800
     };
 
     layer_state_t()
@@ -61,7 +62,8 @@
             x(0), y(0), z(0), w(0), h(0), layerStack(0),
             alpha(0), flags(0), mask(0),
             reserved(0), crop(Rect::INVALID_RECT),
-            finalCrop(Rect::INVALID_RECT), frameNumber(0)
+            finalCrop(Rect::INVALID_RECT), frameNumber(0),
+            overrideScalingMode(-1)
     {
         matrix.dsdx = matrix.dtdy = 1.0f;
         matrix.dsdy = matrix.dtdx = 0.0f;
@@ -93,6 +95,7 @@
             Rect            finalCrop;
             sp<IBinder>     handle;
             uint64_t        frameNumber;
+            int32_t         overrideScalingMode;
             // non POD must be last. see write/read
             Region          transparentRegion;
 };
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index e43342e..d1c576e 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -41,6 +41,7 @@
     output.write(finalCrop);
     output.writeStrongBinder(handle);
     output.writeUint64(frameNumber);
+    output.writeInt32(overrideScalingMode);
     output.write(transparentRegion);
     return NO_ERROR;
 }
@@ -68,6 +69,7 @@
     input.read(finalCrop);
     handle = input.readStrongBinder();
     frameNumber = input.readUint64();
+    overrideScalingMode = input.readInt32();
     input.read(transparentRegion);
     return NO_ERROR;
 }
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 418892a..e33cc37 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -163,6 +163,8 @@
     status_t deferTransactionUntil(const sp<SurfaceComposerClient>& client,
             const sp<IBinder>& id, const sp<IBinder>& handle,
             uint64_t frameNumber);
+    status_t setOverrideScalingMode(const sp<SurfaceComposerClient>& client,
+            const sp<IBinder>& id, int32_t overrideScalingMode);
 
     void setDisplaySurface(const sp<IBinder>& token,
             const sp<IGraphicBufferProducer>& bufferProducer);
@@ -414,6 +416,33 @@
     return NO_ERROR;
 }
 
+status_t Composer::setOverrideScalingMode(
+        const sp<SurfaceComposerClient>& client,
+        const sp<IBinder>& id, int32_t overrideScalingMode) {
+    Mutex::Autolock lock(mLock);
+    layer_state_t* s = getLayerStateLocked(client, id);
+    if (!s) {
+        return BAD_INDEX;
+    }
+
+    switch (overrideScalingMode) {
+        case NATIVE_WINDOW_SCALING_MODE_FREEZE:
+        case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW:
+        case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP:
+        case NATIVE_WINDOW_SCALING_MODE_NO_SCALE_CROP:
+        case -1:
+            break;
+        default:
+            ALOGE("unknown scaling mode: %d",
+                    overrideScalingMode);
+            return BAD_VALUE;
+    }
+
+    s->what |= layer_state_t::eOverrideScalingModeChanged;
+    s->overrideScalingMode = overrideScalingMode;
+    return NO_ERROR;
+}
+
 // ---------------------------------------------------------------------------
 
 DisplayState& Composer::getDisplayStateLocked(const sp<IBinder>& token) {
@@ -650,6 +679,12 @@
     return getComposer().deferTransactionUntil(this, id, handle, frameNumber);
 }
 
+status_t SurfaceComposerClient::setOverrideScalingMode(
+        const sp<IBinder>& id, int32_t overrideScalingMode) {
+    return getComposer().setOverrideScalingMode(
+            this, id, overrideScalingMode);
+}
+
 // ----------------------------------------------------------------------------
 
 void SurfaceComposerClient::setDisplaySurface(const sp<IBinder>& token,
diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp
index 184de71..314d83a 100644
--- a/libs/gui/SurfaceControl.cpp
+++ b/libs/gui/SurfaceControl.cpp
@@ -165,6 +165,12 @@
     return mClient->deferTransactionUntil(mHandle, handle, frameNumber);
 }
 
+status_t SurfaceControl::setOverrideScalingMode(int32_t overrideScalingMode) {
+    status_t err = validate();
+    if (err < 0) return err;
+    return mClient->setOverrideScalingMode(mHandle, overrideScalingMode);
+}
+
 status_t SurfaceControl::clearLayerFrameStats() const {
     status_t err = validate();
     if (err < 0) return err;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 90ab70d..1803ee5 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -75,6 +75,7 @@
         mSidebandStreamChanged(false),
         mCurrentTransform(0),
         mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
+        mOverrideScalingMode(-1),
         mCurrentOpacity(true),
         mCurrentFrameNumber(0),
         mRefreshPending(false),
@@ -1244,7 +1245,7 @@
 }
 
 bool Layer::isFixedSize() const {
-    return mCurrentScalingMode != NATIVE_WINDOW_SCALING_MODE_FREEZE;
+    return getEffectiveScalingMode() != NATIVE_WINDOW_SCALING_MODE_FREEZE;
 }
 
 bool Layer::isCropped() const {
@@ -1403,7 +1404,8 @@
                 "            requested={ wh={%4u,%4u} }}\n"
                 "  drawing={ active   ={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) }\n"
                 "            requested={ wh={%4u,%4u} }}\n",
-                this, getName().string(), mCurrentTransform, mCurrentScalingMode,
+                this, getName().string(), mCurrentTransform,
+                getEffectiveScalingMode(),
                 c.active.w, c.active.h,
                 c.crop.left,
                 c.crop.top,
@@ -1580,6 +1582,20 @@
     return true;
 }
 
+bool Layer::setOverrideScalingMode(int32_t scalingMode) {
+    if (scalingMode == mOverrideScalingMode)
+        return false;
+    mOverrideScalingMode = scalingMode;
+    return true;
+}
+
+uint32_t Layer::getEffectiveScalingMode() const {
+    if (mOverrideScalingMode >= 0) {
+      return mOverrideScalingMode;
+    }
+    return mCurrentScalingMode;
+}
+
 bool Layer::setLayerStack(uint32_t layerStack) {
     if (mCurrentState.layerStack == layerStack)
         return false;
@@ -1738,14 +1754,17 @@
             bool& recomputeVisibleRegions;
             bool stickyTransformSet;
             const char* name;
+            int32_t overrideScalingMode;
 
             Reject(Layer::State& front, Layer::State& current,
                     bool& recomputeVisibleRegions, bool stickySet,
-                    const char* name)
+                    const char* name,
+                    int32_t overrideScalingMode)
                 : front(front), current(current),
                   recomputeVisibleRegions(recomputeVisibleRegions),
                   stickyTransformSet(stickySet),
-                  name(name) {
+                  name(name),
+                  overrideScalingMode(overrideScalingMode) {
             }
 
             virtual bool reject(const sp<GraphicBuffer>& buf,
@@ -1763,7 +1782,9 @@
                     swap(bufWidth, bufHeight);
                 }
 
-                bool isFixedSize = item.mScalingMode != NATIVE_WINDOW_SCALING_MODE_FREEZE;
+                int actualScalingMode = overrideScalingMode >= 0 ?
+                        overrideScalingMode : item.mScalingMode;
+                bool isFixedSize = actualScalingMode != NATIVE_WINDOW_SCALING_MODE_FREEZE;
                 if (front.active != front.requested) {
 
                     if (isFixedSize ||
@@ -1839,7 +1860,8 @@
         };
 
         Reject r(mDrawingState, getCurrentState(), recomputeVisibleRegions,
-                getProducerStickyTransform() != 0, mName.string());
+                getProducerStickyTransform() != 0, mName.string(),
+                mOverrideScalingMode);
 
 
         // Check all of our local sync points to ensure that all transactions
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index c623672..7d085a4 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -160,6 +160,7 @@
     bool setFinalCrop(const Rect& crop);
     bool setLayerStack(uint32_t layerStack);
     void deferTransactionUntil(const sp<IBinder>& handle, uint64_t frameNumber);
+    bool setOverrideScalingMode(int32_t overrideScalingMode);
 
     // If we have received a new buffer this frame, we will pass its surface
     // damage down to hardware composer. Otherwise, we must send a region with
@@ -502,6 +503,11 @@
     void pushPendingState();
     void popPendingState(State* stateToCommit);
     bool applyPendingStates(State* stateToCommit);
+
+    // Returns mCurrentScaling mode (originating from the
+    // Client) or mOverrideScalingMode mode (originating from
+    // the Surface Controller) if set.
+    uint32_t getEffectiveScalingMode() const;
 public:
     void notifyAvailableFrames();
 private:
@@ -536,6 +542,8 @@
     Rect mCurrentCrop;
     uint32_t mCurrentTransform;
     uint32_t mCurrentScalingMode;
+    // We encode unset as -1.
+    int32_t mOverrideScalingMode;
     bool mCurrentOpacity;
     std::atomic<uint64_t> mCurrentFrameNumber;
     bool mRefreshPending;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 1f85bee..efa32a7 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -2291,6 +2291,11 @@
             // We don't trigger a traversal here because if no other state is
             // changed, we don't want this to cause any more work
         }
+        if (what & layer_state_t::eOverrideScalingModeChanged) {
+            layer->setOverrideScalingMode(s.overrideScalingMode);
+            // We don't trigger a traversal here because if no other state is
+            // changed, we don't want this to cause any more work
+        }
     }
     return flags;
 }
diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
index e9b3d99..bc20bbc 100644
--- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
+++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
@@ -2316,6 +2316,11 @@
             // We don't trigger a traversal here because if no other state is
             // changed, we don't want this to cause any more work
         }
+        if (what & layer_state_t::eOverrideScalingModeChanged) {
+            layer->setOverrideScalingMode(s.overrideScalingMode);
+            // We don't trigger a traversal here because if no other state is
+            // changed, we don't want this to cause any more work
+        }
     }
     return flags;
 }