Merge "CameraHardwareInterface: Reconnect preview in HAL set_buffer_count" into nyc-dev
diff --git a/services/camera/libcameraservice/api1/CameraClient.cpp b/services/camera/libcameraservice/api1/CameraClient.cpp
index 6aeab98..8ab9a65 100644
--- a/services/camera/libcameraservice/api1/CameraClient.cpp
+++ b/services/camera/libcameraservice/api1/CameraClient.cpp
@@ -295,9 +295,8 @@
     // If preview has been already started, register preview buffers now.
     if (mHardware->previewEnabled()) {
         if (window != 0) {
-            native_window_set_scaling_mode(window.get(),
-                    NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
-            native_window_set_buffers_transform(window.get(), mOrientation);
+            mHardware->setPreviewScalingMode(NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
+            mHardware->setPreviewTransform(mOrientation);
             result = mHardware->setPreviewWindow(window);
         }
     }
@@ -404,10 +403,9 @@
     }
 
     if (mPreviewWindow != 0) {
-        native_window_set_scaling_mode(mPreviewWindow.get(),
-                NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
-        native_window_set_buffers_transform(mPreviewWindow.get(),
-                mOrientation);
+        mHardware->setPreviewScalingMode(
+            NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
+        mHardware->setPreviewTransform(mOrientation);
     }
     mHardware->setPreviewWindow(mPreviewWindow);
     result = mHardware->startPreview();
@@ -641,8 +639,7 @@
         if (mOrientation != orientation) {
             mOrientation = orientation;
             if (mPreviewWindow != 0) {
-                native_window_set_buffers_transform(mPreviewWindow.get(),
-                        mOrientation);
+                mHardware->setPreviewTransform(mOrientation);
             }
         }
         return OK;
diff --git a/services/camera/libcameraservice/device1/CameraHardwareInterface.h b/services/camera/libcameraservice/device1/CameraHardwareInterface.h
index 7f14cd4..0fe76e5 100644
--- a/services/camera/libcameraservice/device1/CameraHardwareInterface.h
+++ b/services/camera/libcameraservice/device1/CameraHardwareInterface.h
@@ -73,10 +73,18 @@
 
 class CameraHardwareInterface : public virtual RefBase {
 public:
-    CameraHardwareInterface(const char *name)
+    CameraHardwareInterface(const char *name):
+            mDevice(nullptr),
+            mName(name),
+            mPreviewScalingMode(NOT_SET),
+            mPreviewTransform(NOT_SET),
+            mPreviewWidth(NOT_SET),
+            mPreviewHeight(NOT_SET),
+            mPreviewFormat(NOT_SET),
+            mPreviewUsage(0),
+            mPreviewSwapInterval(NOT_SET),
+            mPreviewCrop{NOT_SET,NOT_SET,NOT_SET,NOT_SET}
     {
-        mDevice = 0;
-        mName = name;
     }
 
     ~CameraHardwareInterface()
@@ -118,9 +126,16 @@
     status_t setPreviewWindow(const sp<ANativeWindow>& buf)
     {
         ALOGV("%s(%s) buf %p", __FUNCTION__, mName.string(), buf.get());
-
         if (mDevice->ops->set_preview_window) {
             mPreviewWindow = buf;
+            if (buf != nullptr) {
+                if (mPreviewScalingMode != NOT_SET) {
+                    setPreviewScalingMode(mPreviewScalingMode);
+                }
+                if (mPreviewTransform != NOT_SET) {
+                    setPreviewTransform(mPreviewTransform);
+                }
+            }
             mHalPreviewWindow.user = this;
             ALOGV("%s &mHalPreviewWindow %p mHalPreviewWindow.user %p", __FUNCTION__,
                     &mHalPreviewWindow, mHalPreviewWindow.user);
@@ -130,6 +145,27 @@
         return INVALID_OPERATION;
     }
 
+    status_t setPreviewScalingMode(int scalingMode)
+    {
+        int rc = OK;
+        mPreviewScalingMode = scalingMode;
+        if (mPreviewWindow != nullptr) {
+            rc = native_window_set_scaling_mode(mPreviewWindow.get(),
+                    scalingMode);
+        }
+        return rc;
+    }
+
+    status_t setPreviewTransform(int transform) {
+        int rc = OK;
+        mPreviewTransform = transform;
+        if (mPreviewWindow != nullptr) {
+            rc = native_window_set_buffers_transform(mPreviewWindow.get(),
+                    mPreviewTransform);
+        }
+        return rc;
+    }
+
     /** Set the notification and data callbacks */
     void setCallbacks(notify_callback notify_cb,
                       data_callback data_cb,
@@ -569,6 +605,8 @@
         return __this->mPreviewWindow.get();
     }
 #define anw(n) __to_anw(((struct camera_preview_window *)n)->user)
+#define hwi(n) reinterpret_cast<CameraHardwareInterface *>(\
+        ((struct camera_preview_window *)n)->user)
 
     static int __dequeue_buffer(struct preview_stream_ops* w,
                                 buffer_handle_t** buffer, int *stride)
@@ -617,6 +655,44 @@
     static int __set_buffer_count(struct preview_stream_ops* w, int count)
     {
         ANativeWindow *a = anw(w);
+
+        if (a != nullptr) {
+            // Workaround for b/27039775
+            // Previously, setting the buffer count would reset the buffer
+            // queue's flag that allows for all buffers to be dequeued on the
+            // producer side, instead of just the producer's declared max count,
+            // if no filled buffers have yet been queued by the producer.  This
+            // reset no longer happens, but some HALs depend on this behavior,
+            // so it needs to be maintained for HAL backwards compatibility.
+            // Simulate the prior behavior by disconnecting/reconnecting to the
+            // window and setting the values again.  This has the drawback of
+            // actually causing memory reallocation, which may not have happened
+            // in the past.
+            CameraHardwareInterface *hw = hwi(w);
+            native_window_api_disconnect(a, NATIVE_WINDOW_API_CAMERA);
+            native_window_api_connect(a, NATIVE_WINDOW_API_CAMERA);
+            if (hw->mPreviewScalingMode != NOT_SET) {
+                native_window_set_scaling_mode(a, hw->mPreviewScalingMode);
+            }
+            if (hw->mPreviewTransform != NOT_SET) {
+                native_window_set_buffers_transform(a, hw->mPreviewTransform);
+            }
+            if (hw->mPreviewWidth != NOT_SET) {
+                native_window_set_buffers_dimensions(a,
+                        hw->mPreviewWidth, hw->mPreviewHeight);
+                native_window_set_buffers_format(a, hw->mPreviewFormat);
+            }
+            if (hw->mPreviewUsage != 0) {
+                native_window_set_usage(a, hw->mPreviewUsage);
+            }
+            if (hw->mPreviewSwapInterval != NOT_SET) {
+                a->setSwapInterval(a, hw->mPreviewSwapInterval);
+            }
+            if (hw->mPreviewCrop.left != NOT_SET) {
+                native_window_set_crop(a, &(hw->mPreviewCrop));
+            }
+        }
+
         return native_window_set_buffer_count(a, count);
     }
 
@@ -625,7 +701,10 @@
     {
         int rc;
         ANativeWindow *a = anw(w);
-
+        CameraHardwareInterface *hw = hwi(w);
+        hw->mPreviewWidth = width;
+        hw->mPreviewHeight = height;
+        hw->mPreviewFormat = format;
         rc = native_window_set_buffers_dimensions(a, width, height);
         if (!rc) {
             rc = native_window_set_buffers_format(a, format);
@@ -637,12 +716,12 @@
                       int left, int top, int right, int bottom)
     {
         ANativeWindow *a = anw(w);
-        android_native_rect_t crop;
-        crop.left = left;
-        crop.top = top;
-        crop.right = right;
-        crop.bottom = bottom;
-        return native_window_set_crop(a, &crop);
+        CameraHardwareInterface *hw = hwi(w);
+        hw->mPreviewCrop.left = left;
+        hw->mPreviewCrop.top = top;
+        hw->mPreviewCrop.right = right;
+        hw->mPreviewCrop.bottom = bottom;
+        return native_window_set_crop(a, &(hw->mPreviewCrop));
     }
 
     static int __set_timestamp(struct preview_stream_ops *w,
@@ -654,12 +733,16 @@
     static int __set_usage(struct preview_stream_ops* w, int usage)
     {
         ANativeWindow *a = anw(w);
+        CameraHardwareInterface *hw = hwi(w);
+        hw->mPreviewUsage = usage;
         return native_window_set_usage(a, usage);
     }
 
     static int __set_swap_interval(struct preview_stream_ops *w, int interval)
     {
         ANativeWindow *a = anw(w);
+        CameraHardwareInterface *hw = hwi(w);
+        hw->mPreviewSwapInterval = interval;
         return a->setSwapInterval(a, interval);
     }
 
@@ -701,6 +784,17 @@
     data_callback           mDataCb;
     data_callback_timestamp mDataCbTimestamp;
     void *mCbUser;
+
+    // Cached values for preview stream parameters
+    static const int NOT_SET = -1;
+    int mPreviewScalingMode;
+    int mPreviewTransform;
+    int mPreviewWidth;
+    int mPreviewHeight;
+    int mPreviewFormat;
+    int mPreviewUsage;
+    int mPreviewSwapInterval;
+    android_native_rect_t mPreviewCrop;
 };
 
 };  // namespace android