Merge "[gui] Add {add,remove}RegionSamplingListener"
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index f40eb6c..0510492 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -104,6 +104,7 @@
         "IGraphicBufferConsumer.cpp",
         "IGraphicBufferProducer.cpp",
         "IProducerListener.cpp",
+        "IRegionSamplingListener.cpp",
         "ISurfaceComposer.cpp",
         "ISurfaceComposerClient.cpp",
         "ITransactionCompletedListener.cpp",
diff --git a/libs/gui/IRegionSamplingListener.cpp b/libs/gui/IRegionSamplingListener.cpp
new file mode 100644
index 0000000..40cbfce
--- /dev/null
+++ b/libs/gui/IRegionSamplingListener.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "IRegionSamplingListener"
+//#define LOG_NDEBUG 0
+
+#include <gui/IRegionSamplingListener.h>
+
+namespace android {
+
+namespace { // Anonymous
+
+enum class Tag : uint32_t {
+    ON_SAMPLE_COLLECTED = IBinder::FIRST_CALL_TRANSACTION,
+    LAST = ON_SAMPLE_COLLECTED,
+};
+
+} // Anonymous namespace
+
+class BpRegionSamplingListener : public SafeBpInterface<IRegionSamplingListener> {
+public:
+    explicit BpRegionSamplingListener(const sp<IBinder>& impl)
+          : SafeBpInterface<IRegionSamplingListener>(impl, "BpRegionSamplingListener") {}
+
+    ~BpRegionSamplingListener() override;
+
+    void onSampleCollected(float medianLuma) override {
+        callRemoteAsync<decltype(
+                &IRegionSamplingListener::onSampleCollected)>(Tag::ON_SAMPLE_COLLECTED, medianLuma);
+    }
+};
+
+// Out-of-line virtual method definitions to trigger vtable emission in this translation unit (see
+// clang warning -Wweak-vtables)
+BpRegionSamplingListener::~BpRegionSamplingListener() = default;
+
+IMPLEMENT_META_INTERFACE(RegionSamplingListener, "android.gui.IRegionSamplingListener");
+
+status_t BnRegionSamplingListener::onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+                                              uint32_t flags) {
+    if (code < IBinder::FIRST_CALL_TRANSACTION || code > static_cast<uint32_t>(Tag::LAST)) {
+        return BBinder::onTransact(code, data, reply, flags);
+    }
+    auto tag = static_cast<Tag>(code);
+    switch (tag) {
+        case Tag::ON_SAMPLE_COLLECTED:
+            return callLocalAsync(data, reply, &IRegionSamplingListener::onSampleCollected);
+    }
+}
+
+} // namespace android
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index fc9185d..f77eeb2 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -26,6 +26,7 @@
 
 #include <gui/IDisplayEventConnection.h>
 #include <gui/IGraphicBufferProducer.h>
+#include <gui/IRegionSamplingListener.h>
 #include <gui/ISurfaceComposer.h>
 #include <gui/ISurfaceComposerClient.h>
 #include <gui/LayerDebugInfo.h>
@@ -754,6 +755,57 @@
         error = reply.readBool(outIsWideColorDisplay);
         return error;
     }
+
+    virtual status_t addRegionSamplingListener(const Rect& samplingArea,
+                                               const sp<IBinder>& stopLayerHandle,
+                                               const sp<IRegionSamplingListener>& listener) {
+        Parcel data, reply;
+        status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+        if (error != NO_ERROR) {
+            ALOGE("addRegionSamplingListener: Failed to write interface token");
+            return error;
+        }
+        error = data.write(samplingArea);
+        if (error != NO_ERROR) {
+            ALOGE("addRegionSamplingListener: Failed to write sampling area");
+            return error;
+        }
+        error = data.writeStrongBinder(stopLayerHandle);
+        if (error != NO_ERROR) {
+            ALOGE("addRegionSamplingListener: Failed to write stop layer handle");
+            return error;
+        }
+        error = data.writeStrongBinder(IInterface::asBinder(listener));
+        if (error != NO_ERROR) {
+            ALOGE("addRegionSamplingListener: Failed to write listener");
+            return error;
+        }
+        error = remote()->transact(BnSurfaceComposer::ADD_REGION_SAMPLING_LISTENER, data, &reply);
+        if (error != NO_ERROR) {
+            ALOGE("addRegionSamplingListener: Failed to transact");
+        }
+        return error;
+    }
+
+    virtual status_t removeRegionSamplingListener(const sp<IRegionSamplingListener>& listener) {
+        Parcel data, reply;
+        status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+        if (error != NO_ERROR) {
+            ALOGE("addRegionSamplingListener: Failed to write interface token");
+            return error;
+        }
+        error = data.writeStrongBinder(IInterface::asBinder(listener));
+        if (error != NO_ERROR) {
+            ALOGE("addRegionSamplingListener: Failed to write listener");
+            return error;
+        }
+        error = remote()->transact(BnSurfaceComposer::REMOVE_REGION_SAMPLING_LISTENER, data,
+                                   &reply);
+        if (error != NO_ERROR) {
+            ALOGE("addRegionSamplingListener: Failed to transact");
+        }
+        return error;
+    }
 };
 
 // Out-of-line virtual method definition to trigger vtable emission in this
@@ -1233,6 +1285,38 @@
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
             return reply->writeUint64Vector(getPhysicalDisplayIds());
         }
+        case ADD_REGION_SAMPLING_LISTENER: {
+            CHECK_INTERFACE(ISurfaceComposer, data, reply);
+            Rect samplingArea;
+            status_t result = data.read(samplingArea);
+            if (result != NO_ERROR) {
+                ALOGE("addRegionSamplingListener: Failed to read sampling area");
+                return result;
+            }
+            sp<IBinder> stopLayerHandle;
+            result = data.readNullableStrongBinder(&stopLayerHandle);
+            if (result != NO_ERROR) {
+                ALOGE("addRegionSamplingListener: Failed to read stop layer handle");
+                return result;
+            }
+            sp<IRegionSamplingListener> listener;
+            result = data.readNullableStrongBinder(&listener);
+            if (result != NO_ERROR) {
+                ALOGE("addRegionSamplingListener: Failed to read listener");
+                return result;
+            }
+            return addRegionSamplingListener(samplingArea, stopLayerHandle, listener);
+        }
+        case REMOVE_REGION_SAMPLING_LISTENER: {
+            CHECK_INTERFACE(ISurfaceComposer, data, reply);
+            sp<IRegionSamplingListener> listener;
+            status_t result = data.readNullableStrongBinder(&listener);
+            if (result != NO_ERROR) {
+                ALOGE("removeRegionSamplingListener: Failed to read listener");
+                return result;
+            }
+            return removeRegionSamplingListener(listener);
+        }
         default: {
             return BBinder::onTransact(code, data, reply, flags);
         }
diff --git a/libs/gui/include/gui/IRegionSamplingListener.h b/libs/gui/include/gui/IRegionSamplingListener.h
new file mode 100644
index 0000000..1803d9a
--- /dev/null
+++ b/libs/gui/include/gui/IRegionSamplingListener.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <cstdint>
+#include <vector>
+
+#include <binder/IInterface.h>
+#include <binder/SafeInterface.h>
+
+namespace android {
+
+class IRegionSamplingListener : public IInterface {
+public:
+    DECLARE_META_INTERFACE(RegionSamplingListener)
+
+    virtual void onSampleCollected(float medianLuma) = 0;
+};
+
+class BnRegionSamplingListener : public SafeBnInterface<IRegionSamplingListener> {
+public:
+    BnRegionSamplingListener()
+          : SafeBnInterface<IRegionSamplingListener>("BnRegionSamplingListener") {}
+
+    status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+                        uint32_t flags = 0) override;
+};
+
+} // namespace android
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index a2db7bc..1a0b6bb 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -50,6 +50,7 @@
 class IDisplayEventConnection;
 class IGraphicBufferProducer;
 class ISurfaceComposerClient;
+class IRegionSamplingListener;
 class Rect;
 enum class FrameEvent;
 
@@ -338,6 +339,26 @@
      */
     virtual status_t isWideColorDisplay(const sp<IBinder>& token,
                                         bool* outIsWideColorDisplay) const = 0;
+
+    /* Registers a listener to stream median luma updates from SurfaceFlinger.
+     *
+     * The sampling area is bounded by both samplingArea and the given stopLayerHandle
+     * (i.e., only layers behind the stop layer will be captured and sampled).
+     *
+     * Multiple listeners may be provided so long as they have independent listeners.
+     * If multiple listeners are provided, the effective sampling region for each listener will
+     * be bounded by whichever stop layer has a lower Z value.
+     *
+     * Requires the same permissions as captureLayers and captureScreen.
+     */
+    virtual status_t addRegionSamplingListener(const Rect& samplingArea,
+                                               const sp<IBinder>& stopLayerHandle,
+                                               const sp<IRegionSamplingListener>& listener) = 0;
+
+    /*
+     * Removes a listener that was streaming median luma updates from SurfaceFlinger.
+     */
+    virtual status_t removeRegionSamplingListener(const sp<IRegionSamplingListener>& listener) = 0;
 };
 
 // ----------------------------------------------------------------------------
@@ -383,6 +404,8 @@
         IS_WIDE_COLOR_DISPLAY,
         GET_DISPLAY_NATIVE_PRIMARIES,
         GET_PHYSICAL_DISPLAY_IDS,
+        ADD_REGION_SAMPLING_LISTENER,
+        REMOVE_REGION_SAMPLING_LISTENER,
         // Always append new enum to the end.
     };
 
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index bec9299..f127853 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -669,6 +669,16 @@
 
     status_t isWideColorDisplay(const sp<IBinder>&, bool*) const override { return NO_ERROR; }
 
+    status_t addRegionSamplingListener(const Rect& /*samplingArea*/,
+                                       const sp<IBinder>& /*stopLayerHandle*/,
+                                       const sp<IRegionSamplingListener>& /*listener*/) override {
+        return NO_ERROR;
+    }
+    status_t removeRegionSamplingListener(
+            const sp<IRegionSamplingListener>& /*listener*/) override {
+        return NO_ERROR;
+    }
+
 protected:
     IBinder* onAsBinder() override { return nullptr; }
 
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index f9000b5..48b1a77 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1324,6 +1324,17 @@
     return NO_ERROR;
 }
 
+status_t SurfaceFlinger::addRegionSamplingListener(
+        const Rect& /*samplingArea*/, const sp<IBinder>& /*stopLayerHandle*/,
+        const sp<IRegionSamplingListener>& /*listener*/) {
+    return NO_ERROR;
+}
+
+status_t SurfaceFlinger::removeRegionSamplingListener(
+        const sp<IRegionSamplingListener>& /*listener*/) {
+    return NO_ERROR;
+}
+
 // ----------------------------------------------------------------------------
 
 sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection(
@@ -5121,7 +5132,9 @@
             return OK;
         }
         case CAPTURE_LAYERS:
-        case CAPTURE_SCREEN: {
+        case CAPTURE_SCREEN:
+        case ADD_REGION_SAMPLING_LISTENER:
+        case REMOVE_REGION_SAMPLING_LISTENER: {
             // codes that require permission check
             IPCThreadState* ipc = IPCThreadState::self();
             const int pid = ipc->getCallingPid();
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 060fc7a..669d3a1 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -476,7 +476,9 @@
     status_t getProtectedContentSupport(bool* outSupported) const override;
     status_t isWideColorDisplay(const sp<IBinder>& displayToken,
                                 bool* outIsWideColorDisplay) const override;
-
+    status_t addRegionSamplingListener(const Rect& samplingArea, const sp<IBinder>& stopLayerHandle,
+                                       const sp<IRegionSamplingListener>& listener) override;
+    status_t removeRegionSamplingListener(const sp<IRegionSamplingListener>& listener) override;
     /* ------------------------------------------------------------------------
      * DeathRecipient interface
      */