Merge "Create InputManager TEST_MAPPING with WindowInputTests"
diff --git a/cmds/surfacereplayer/OWNERS b/cmds/surfacereplayer/OWNERS
index cc4c842..32bcc83 100644
--- a/cmds/surfacereplayer/OWNERS
+++ b/cmds/surfacereplayer/OWNERS
@@ -1,2 +1 @@
-mathias@google.com
-racarr@google.com
+include platform/frameworks/native:/services/surfaceflinger/OWNERS
diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp
index 119b3e0..55c5de9 100644
--- a/libs/graphicsenv/GraphicsEnv.cpp
+++ b/libs/graphicsenv/GraphicsEnv.cpp
@@ -466,7 +466,8 @@
}
void GraphicsEnv::setAngleInfo(const std::string path, const std::string appName,
- const std::string developerOptIn, const int rulesFd,
+ const std::string developerOptIn,
+ const std::vector<std::string> eglFeatures, const int rulesFd,
const long rulesOffset, const long rulesLength) {
if (mUseAngle != UNKNOWN) {
// We've already figured out an answer for this app, so just return.
@@ -475,6 +476,8 @@
return;
}
+ mAngleEglFeatures = std::move(eglFeatures);
+
ALOGV("setting ANGLE path to '%s'", path.c_str());
mAnglePath = path;
ALOGV("setting ANGLE app name to '%s'", appName.c_str());
@@ -520,6 +523,10 @@
return mAngleAppName;
}
+const std::vector<std::string>& GraphicsEnv::getAngleEglFeatures() {
+ return mAngleEglFeatures;
+}
+
const std::string& GraphicsEnv::getLayerPaths() {
return mLayerPaths;
}
diff --git a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
index 22a2332..900fc49 100644
--- a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
+++ b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
@@ -97,12 +97,15 @@
// in the search path must have a '!' after the zip filename, e.g.
// /system/app/ANGLEPrebuilt/ANGLEPrebuilt.apk!/lib/arm64-v8a
void setAngleInfo(const std::string path, const std::string appName, std::string devOptIn,
- const int rulesFd, const long rulesOffset, const long rulesLength);
+ const std::vector<std::string> eglFeatures, const int rulesFd,
+ const long rulesOffset, const long rulesLength);
// Get the ANGLE driver namespace.
android_namespace_t* getAngleNamespace();
// Get the app name for ANGLE debug message.
std::string& getAngleAppName();
+ const std::vector<std::string>& getAngleEglFeatures();
+
/*
* Apis for debug layer
*/
@@ -154,6 +157,8 @@
std::string mAngleAppName;
// ANGLE developer opt in status.
std::string mAngleDeveloperOptIn;
+ // ANGLE EGL features;
+ std::vector<std::string> mAngleEglFeatures;
// ANGLE rules.
std::vector<char> mRulesBuffer;
// Use ANGLE flag.
diff --git a/libs/nativedisplay/surfacetexture/ImageConsumer.cpp b/libs/nativedisplay/surfacetexture/ImageConsumer.cpp
index 16afc68..365e788 100644
--- a/libs/nativedisplay/surfacetexture/ImageConsumer.cpp
+++ b/libs/nativedisplay/surfacetexture/ImageConsumer.cpp
@@ -51,7 +51,15 @@
}
int slot = item.mSlot;
+ *outQueueEmpty = false;
if (item.mFence->isValid()) {
+ // If fence is not signaled, that means frame is not ready and
+ // outQueueEmpty is set to true. By the time the fence is signaled,
+ // there may be a new buffer queued. This is a proper detection for an
+ // empty queue and it is needed to avoid infinite loop in
+ // ASurfaceTexture_dequeueBuffer (see b/159921224).
+ *outQueueEmpty = item.mFence->getStatus() == Fence::Status::Unsignaled;
+
// Wait on the producer fence for the buffer to be ready.
err = fenceWait(item.mFence->get(), fencePassThroughHandle);
if (err != OK) {
@@ -112,7 +120,6 @@
st.mCurrentFrameNumber = item.mFrameNumber;
st.computeCurrentTransformMatrixLocked();
- *outQueueEmpty = false;
*outDataspace = item.mDataSpace;
*outSlotid = slot;
return st.mSlots[slot].mGraphicBuffer;
diff --git a/libs/renderengine/Android.bp b/libs/renderengine/Android.bp
index 1ccbff1..eb967ce 100644
--- a/libs/renderengine/Android.bp
+++ b/libs/renderengine/Android.bp
@@ -77,6 +77,7 @@
srcs: [
"skia/SkiaRenderEngine.cpp",
"skia/SkiaGLRenderEngine.cpp",
+ "skia/filters/BlurFilter.cpp",
],
}
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
index cb752b0..0fed08b 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
@@ -29,12 +29,14 @@
#include <utils/Trace.h>
#include "../gl/GLExtensions.h"
#include "SkiaGLRenderEngine.h"
+#include "filters/BlurFilter.h"
#include <GrContextOptions.h>
#include <gl/GrGLInterface.h>
#include <SkCanvas.h>
#include <SkImage.h>
+#include <SkImageFilters.h>
#include <SkShadowUtils.h>
#include <SkSurface.h>
@@ -194,7 +196,7 @@
// initialize the renderer while GL is current
std::unique_ptr<SkiaGLRenderEngine> engine =
- std::make_unique<SkiaGLRenderEngine>(display, config, ctxt, placeholder,
+ std::make_unique<SkiaGLRenderEngine>(args, display, config, ctxt, placeholder,
protectedContext, protectedPlaceholder);
ALOGI("OpenGL ES informations:");
@@ -247,9 +249,9 @@
return config;
}
-SkiaGLRenderEngine::SkiaGLRenderEngine(EGLDisplay display, EGLConfig config, EGLContext ctxt,
- EGLSurface placeholder, EGLContext protectedContext,
- EGLSurface protectedPlaceholder)
+SkiaGLRenderEngine::SkiaGLRenderEngine(const RenderEngineCreationArgs& args, EGLDisplay display,
+ EGLConfig config, EGLContext ctxt, EGLSurface placeholder,
+ EGLContext protectedContext, EGLSurface protectedPlaceholder)
: mEGLDisplay(display),
mEGLConfig(config),
mEGLContext(ctxt),
@@ -273,6 +275,10 @@
options.fPreferExternalImagesOverES3 = true;
options.fDisableDistanceFieldPaths = true;
mGrContext = GrDirectContext::MakeGL(std::move(glInterface), options);
+
+ if (args.supportsBackgroundBlur) {
+ mBlurFilter = new BlurFilter();
+ }
}
base::unique_fd SkiaGLRenderEngine::flush() {
@@ -408,6 +414,11 @@
const auto& bounds = layer->geometry.boundaries;
const auto dest = getSkRect(bounds);
+ if (layer->backgroundBlurRadius > 0) {
+ ATRACE_NAME("BackgroundBlur");
+ mBlurFilter->draw(canvas, surface, layer->backgroundBlurRadius);
+ }
+
if (layer->source.buffer.buffer) {
ATRACE_NAME("DrawImage");
const auto& item = layer->source.buffer;
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.h b/libs/renderengine/skia/SkiaGLRenderEngine.h
index 3da7f25..898dc54 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.h
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.h
@@ -28,6 +28,7 @@
#include <SkSurface.h>
#include "SkiaRenderEngine.h"
+#include "filters/BlurFilter.h"
namespace android {
namespace renderengine {
@@ -36,8 +37,8 @@
class SkiaGLRenderEngine : public skia::SkiaRenderEngine {
public:
static std::unique_ptr<SkiaGLRenderEngine> create(const RenderEngineCreationArgs& args);
- SkiaGLRenderEngine(EGLDisplay display, EGLConfig config, EGLContext ctxt,
- EGLSurface placeholder, EGLContext protectedContext,
+ SkiaGLRenderEngine(const RenderEngineCreationArgs& args, EGLDisplay display, EGLConfig config,
+ EGLContext ctxt, EGLSurface placeholder, EGLContext protectedContext,
EGLSurface protectedPlaceholder);
~SkiaGLRenderEngine() override{};
@@ -78,6 +79,7 @@
EGLSurface mPlaceholderSurface;
EGLContext mProtectedEGLContext;
EGLSurface mProtectedPlaceholderSurface;
+ BlurFilter* mBlurFilter = nullptr;
// Cache of GL images that we'll store per GraphicBuffer ID
std::unordered_map<uint64_t, sk_sp<SkImage>> mImageCache GUARDED_BY(mRenderingMutex);
diff --git a/libs/renderengine/skia/filters/BlurFilter.cpp b/libs/renderengine/skia/filters/BlurFilter.cpp
new file mode 100644
index 0000000..eb791a7
--- /dev/null
+++ b/libs/renderengine/skia/filters/BlurFilter.cpp
@@ -0,0 +1,133 @@
+/*
+ * Copyright 2020 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.
+ */
+
+#include "BlurFilter.h"
+#include <SkCanvas.h>
+#include <SkData.h>
+#include <SkPaint.h>
+#include <SkRuntimeEffect.h>
+#include <SkSize.h>
+#include <SkString.h>
+#include <SkSurface.h>
+#include <log/log.h>
+#include <utils/Trace.h>
+
+namespace android {
+namespace renderengine {
+namespace skia {
+
+BlurFilter::BlurFilter() {
+ SkString blurString(R"(
+ in shader input;
+ uniform float in_inverseScale;
+ uniform float2 in_blurOffset;
+
+ half4 main(float2 xy) {
+ float2 scaled_xy = float2(xy.x * in_inverseScale, xy.y * in_inverseScale);
+
+ float4 c = float4(sample(input, scaled_xy));
+ c += float4(sample(input, scaled_xy + float2( in_blurOffset.x, in_blurOffset.y)));
+ c += float4(sample(input, scaled_xy + float2( in_blurOffset.x, -in_blurOffset.y)));
+ c += float4(sample(input, scaled_xy + float2(-in_blurOffset.x, in_blurOffset.y)));
+ c += float4(sample(input, scaled_xy + float2(-in_blurOffset.x, -in_blurOffset.y)));
+
+ return half4(c.rgb * 0.2, 1.0);
+ }
+ )");
+
+ auto [blurEffect, error] = SkRuntimeEffect::Make(blurString);
+ if (!blurEffect) {
+ LOG_ALWAYS_FATAL("RuntimeShader error: %s", error.c_str());
+ }
+ mBlurEffect = std::move(blurEffect);
+}
+
+void BlurFilter::draw(SkCanvas* canvas, sk_sp<SkSurface> input, const uint32_t blurRadius) const {
+ ATRACE_CALL();
+ // Kawase is an approximation of Gaussian, but it behaves differently from it.
+ // A radius transformation is required for approximating them, and also to introduce
+ // non-integer steps, necessary to smoothly interpolate large radii.
+ float tmpRadius = (float)blurRadius / 6.0f;
+ float numberOfPasses = std::min(kMaxPasses, (uint32_t)ceil(tmpRadius));
+ float radiusByPasses = tmpRadius / (float)numberOfPasses;
+
+ SkImageInfo scaledInfo = SkImageInfo::MakeN32Premul((float)input->width() * kInputScale,
+ (float)input->height() * kInputScale);
+ auto drawSurface = canvas->makeSurface(scaledInfo);
+
+ const float stepX = radiusByPasses;
+ const float stepY = radiusByPasses;
+
+ // start by drawing and downscaling and doing the first blur pass
+ SkRuntimeShaderBuilder blurBuilder(mBlurEffect);
+ blurBuilder.child("input") = input->makeImageSnapshot()->makeShader();
+ blurBuilder.uniform("in_inverseScale") = kInverseInputScale;
+ blurBuilder.uniform("in_blurOffset") =
+ SkV2{stepX * kInverseInputScale, stepY * kInverseInputScale};
+
+ {
+ // limit the lifetime of the input surface's snapshot to ensure that it goes out of
+ // scope before the surface is written into to avoid any copy-on-write behavior.
+ SkPaint paint;
+ paint.setShader(blurBuilder.makeShader(nullptr, false));
+ paint.setFilterQuality(kLow_SkFilterQuality);
+ drawSurface->getCanvas()->drawIRect(scaledInfo.bounds(), paint);
+ blurBuilder.child("input") = nullptr;
+ }
+
+ // And now we'll ping pong between our surfaces, to accumulate the result of various offsets.
+ auto lastDrawTarget = drawSurface;
+ if (numberOfPasses > 1) {
+ auto readSurface = drawSurface;
+ drawSurface = canvas->makeSurface(scaledInfo);
+
+ for (auto i = 1; i < numberOfPasses; i++) {
+ const float stepScale = (float)i * kInputScale;
+
+ blurBuilder.child("input") = readSurface->makeImageSnapshot()->makeShader();
+ blurBuilder.uniform("in_inverseScale") = 1.0f;
+ blurBuilder.uniform("in_blurOffset") = SkV2{stepX * stepScale, stepY * stepScale};
+
+ SkPaint paint;
+ paint.setShader(blurBuilder.makeShader(nullptr, false));
+ paint.setFilterQuality(kLow_SkFilterQuality);
+ drawSurface->getCanvas()->drawIRect(scaledInfo.bounds(), paint);
+
+ // Swap buffers for next iteration
+ auto tmp = drawSurface;
+ drawSurface = readSurface;
+ readSurface = tmp;
+ blurBuilder.child("input") = nullptr;
+ }
+ lastDrawTarget = readSurface;
+ }
+
+ drawSurface->flushAndSubmit();
+
+ // do the final composition, with alpha blending to hide downscaling artifacts.
+ {
+ SkPaint paint;
+ paint.setShader(lastDrawTarget->makeImageSnapshot()->makeShader(
+ SkMatrix::MakeScale(kInverseInputScale)));
+ paint.setFilterQuality(kLow_SkFilterQuality);
+ paint.setAlpha(std::min(1.0f, (float)blurRadius / kMaxCrossFadeRadius) * 255);
+ canvas->drawIRect(SkIRect::MakeWH(input->width(), input->height()), paint);
+ }
+}
+
+} // namespace skia
+} // namespace renderengine
+} // namespace android
\ No newline at end of file
diff --git a/libs/renderengine/skia/filters/BlurFilter.h b/libs/renderengine/skia/filters/BlurFilter.h
new file mode 100644
index 0000000..94b3673
--- /dev/null
+++ b/libs/renderengine/skia/filters/BlurFilter.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2020 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 <SkCanvas.h>
+#include <SkImage.h>
+#include <SkRuntimeEffect.h>
+#include <SkSurface.h>
+
+using namespace std;
+
+namespace android {
+namespace renderengine {
+namespace skia {
+
+/**
+ * This is an implementation of a Kawase blur, as described in here:
+ * https://community.arm.com/cfs-file/__key/communityserver-blogs-components-weblogfiles/
+ * 00-00-00-20-66/siggraph2015_2D00_mmg_2D00_marius_2D00_notes.pdf
+ */
+class BlurFilter {
+public:
+ // Downsample FBO to improve performance
+ static constexpr float kInputScale = 0.25f;
+ // Downsample scale factor used to improve performance
+ static constexpr float kInverseInputScale = 1.0f / kInputScale;
+ // Maximum number of render passes
+ static constexpr uint32_t kMaxPasses = 4;
+ // To avoid downscaling artifacts, we interpolate the blurred fbo with the full composited
+ // image, up to this radius.
+ static constexpr float kMaxCrossFadeRadius = 30.0f;
+
+ explicit BlurFilter();
+ virtual ~BlurFilter(){};
+
+ // Execute blur passes, rendering to a canvas.
+ void draw(SkCanvas* canvas, sk_sp<SkSurface> input, const uint32_t radius) const;
+
+private:
+ sk_sp<SkRuntimeEffect> mBlurEffect;
+};
+
+} // namespace skia
+} // namespace renderengine
+} // namespace android
diff --git a/opengl/include/EGL/eglext_angle.h b/opengl/include/EGL/eglext_angle.h
index 1f1bcb3..e753e0d 100644
--- a/opengl/include/EGL/eglext_angle.h
+++ b/opengl/include/EGL/eglext_angle.h
@@ -186,6 +186,26 @@
#define EGL_EXTENSIONS_ENABLED_ANGLE 0x345F
#endif /* EGL_ANGLE_create_context_extensions_enabled */
+#ifndef EGL_ANGLE_feature_control
+#define EGL_ANGLE_feature_control 1
+#define EGL_FEATURE_NAME_ANGLE 0x3460
+#define EGL_FEATURE_CATEGORY_ANGLE 0x3461
+#define EGL_FEATURE_DESCRIPTION_ANGLE 0x3462
+#define EGL_FEATURE_BUG_ANGLE 0x3463
+#define EGL_FEATURE_STATUS_ANGLE 0x3464
+#define EGL_FEATURE_COUNT_ANGLE 0x3465
+#define EGL_FEATURE_OVERRIDES_ENABLED_ANGLE 0x3466
+#define EGL_FEATURE_OVERRIDES_DISABLED_ANGLE 0x3467
+#define EGL_FEATURE_CONDITION_ANGLE 0x3468
+#define EGL_FEATURE_ALL_DISABLED_ANGLE 0x3469
+typedef const char *(EGLAPIENTRYP PFNEGLQUERYSTRINGIANGLEPROC) (EGLDisplay dpy, EGLint name, EGLint index);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYDISPLAYATTRIBANGLEPROC) (EGLDisplay dpy, EGLint attribute, EGLAttrib *value);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI const char *EGLAPIENTRY eglQueryStringiANGLE(EGLDisplay dpy, EGLint name, EGLint index);
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryDisplayAttribANGLE(EGLDisplay dpy, EGLint attribute, EGLAttrib *value);
+#endif
+#endif /* EGL_ANGLE_feature_control */
+
// clang-format on
#endif // INCLUDE_EGL_EGLEXT_ANGLE_
diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp
index a288c21..0b755aa 100644
--- a/opengl/libs/EGL/egl_display.cpp
+++ b/opengl/libs/EGL/egl_display.cpp
@@ -143,6 +143,16 @@
attrs.push_back(attr[1]);
}
}
+ const auto& eglFeatures = GraphicsEnv::getInstance().getAngleEglFeatures();
+ std::vector<const char*> features;
+ if (eglFeatures.size() > 0) {
+ for (const std::string& eglFeature : eglFeatures) {
+ features.push_back(eglFeature.c_str());
+ }
+ features.push_back(0);
+ attrs.push_back(EGL_FEATURE_OVERRIDES_ENABLED_ANGLE);
+ attrs.push_back(reinterpret_cast<EGLAttrib>(features.data()));
+ }
attrs.push_back(EGL_PLATFORM_ANGLE_TYPE_ANGLE);
attrs.push_back(EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE);
diff --git a/services/inputflinger/reader/InputDevice.cpp b/services/inputflinger/reader/InputDevice.cpp
index b224476..271bc2f 100644
--- a/services/inputflinger/reader/InputDevice.cpp
+++ b/services/inputflinger/reader/InputDevice.cpp
@@ -85,12 +85,13 @@
bumpGeneration();
}
-void InputDevice::dump(std::string& dump) {
+void InputDevice::dump(std::string& dump, const std::string& eventHubDevStr) {
InputDeviceInfo deviceInfo;
getDeviceInfo(&deviceInfo);
dump += StringPrintf(INDENT "Device %d: %s\n", deviceInfo.getId(),
deviceInfo.getDisplayName().c_str());
+ dump += StringPrintf(INDENT "%s", eventHubDevStr.c_str());
dump += StringPrintf(INDENT2 "Generation: %d\n", mGeneration);
dump += StringPrintf(INDENT2 "IsExternal: %s\n", toString(mIsExternal));
dump += StringPrintf(INDENT2 "AssociatedDisplayPort: ");
@@ -102,6 +103,7 @@
dump += StringPrintf(INDENT2 "HasMic: %s\n", toString(mHasMic));
dump += StringPrintf(INDENT2 "Sources: 0x%08x\n", deviceInfo.getSources());
dump += StringPrintf(INDENT2 "KeyboardType: %d\n", deviceInfo.getKeyboardType());
+ dump += StringPrintf(INDENT2 "ControllerNum: %d\n", deviceInfo.getControllerNumber());
const std::vector<InputDeviceInfo::MotionRange>& ranges = deviceInfo.getMotionRanges();
if (!ranges.empty()) {
@@ -201,6 +203,8 @@
// insert the context into the devices set
mDevices.insert({eventHubId, std::make_pair(std::move(contextPtr), std::move(mappers))});
+ // Must change generation to flag this device as changed
+ bumpGeneration();
}
void InputDevice::removeEventHubDevice(int32_t eventHubId) {
diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp
index feaacb3..7c96e54 100644
--- a/services/inputflinger/reader/InputReader.cpp
+++ b/services/inputflinger/reader/InputReader.cpp
@@ -207,6 +207,14 @@
}
mDevices.emplace(eventHubId, device);
+ // Add device to device to EventHub ids map.
+ const auto mapIt = mDeviceToEventHubIdsMap.find(device);
+ if (mapIt == mDeviceToEventHubIdsMap.end()) {
+ std::vector<int32_t> ids = {eventHubId};
+ mDeviceToEventHubIdsMap.emplace(device, ids);
+ } else {
+ mapIt->second.push_back(eventHubId);
+ }
bumpGenerationLocked();
if (device->getClasses().test(InputDeviceClass::EXTERNAL_STYLUS)) {
@@ -223,6 +231,17 @@
std::shared_ptr<InputDevice> device = std::move(deviceIt->second);
mDevices.erase(deviceIt);
+ // Erase device from device to EventHub ids map.
+ auto mapIt = mDeviceToEventHubIdsMap.find(device);
+ if (mapIt != mDeviceToEventHubIdsMap.end()) {
+ std::vector<int32_t>& eventHubIds = mapIt->second;
+ eventHubIds.erase(std::remove_if(eventHubIds.begin(), eventHubIds.end(),
+ [eventHubId](int32_t eId) { return eId == eventHubId; }),
+ eventHubIds.end());
+ if (eventHubIds.size() == 0) {
+ mDeviceToEventHubIdsMap.erase(mapIt);
+ }
+ }
bumpGenerationLocked();
if (device->isIgnored()) {
@@ -463,8 +482,7 @@
void InputReader::getInputDevicesLocked(std::vector<InputDeviceInfo>& outInputDevices) {
outInputDevices.clear();
- for (auto& devicePair : mDevices) {
- std::shared_ptr<InputDevice>& device = devicePair.second;
+ for (const auto& [device, eventHubIds] : mDeviceToEventHubIdsMap) {
if (!device->isIgnored()) {
InputDeviceInfo info;
device->getDeviceInfo(&info);
@@ -635,11 +653,17 @@
mEventHub->dump(dump);
dump += "\n";
- dump += "Input Reader State:\n";
+ dump += StringPrintf("Input Reader State (Nums of device: %zu):\n",
+ mDeviceToEventHubIdsMap.size());
- for (const auto& devicePair : mDevices) {
- const std::shared_ptr<InputDevice>& device = devicePair.second;
- device->dump(dump);
+ for (const auto& devicePair : mDeviceToEventHubIdsMap) {
+ const std::shared_ptr<InputDevice>& device = devicePair.first;
+ std::string eventHubDevStr = INDENT "EventHub Devices: [ ";
+ for (const auto& eId : devicePair.second) {
+ eventHubDevStr += StringPrintf("%d ", eId);
+ }
+ eventHubDevStr += "] \n";
+ device->dump(dump, eventHubDevStr);
}
dump += INDENT "Configuration:\n";
diff --git a/services/inputflinger/reader/include/InputDevice.h b/services/inputflinger/reader/include/InputDevice.h
index 6b28069..7d160eb 100644
--- a/services/inputflinger/reader/include/InputDevice.h
+++ b/services/inputflinger/reader/include/InputDevice.h
@@ -67,7 +67,7 @@
bool isEnabled();
void setEnabled(bool enabled, nsecs_t when);
- void dump(std::string& dump);
+ void dump(std::string& dump, const std::string& eventHubDevStr);
void addEventHubDevice(int32_t eventHubId, bool populateMappers = true);
void removeEventHubDevice(int32_t eventHubId);
void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes);
diff --git a/services/inputflinger/reader/include/InputReader.h b/services/inputflinger/reader/include/InputReader.h
index 2d6ccf5..a902482 100644
--- a/services/inputflinger/reader/include/InputReader.h
+++ b/services/inputflinger/reader/include/InputReader.h
@@ -142,6 +142,11 @@
// to lookup the input device instance from the EventHub device id.
std::unordered_map<int32_t /*eventHubId*/, std::shared_ptr<InputDevice>> mDevices;
+ // An input device contains one or more eventHubId, this map provides a way to lookup the
+ // EventHubIds contained in the input device from the input device instance.
+ std::unordered_map<std::shared_ptr<InputDevice>, std::vector<int32_t> /*eventHubId*/>
+ mDeviceToEventHubIdsMap;
+
// low-level input event decoding and device management
void processEventsLocked(const RawEvent* rawEvents, size_t count);
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 4b0a945..54a36a9 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -1354,6 +1354,29 @@
ASSERT_EQ(size_t(0), inputDevices[0].getMotionRanges().size());
}
+TEST_F(InputReaderTest, GetMergedInputDevices) {
+ constexpr int32_t deviceId = END_RESERVED_ID + 1000;
+ constexpr int32_t eventHubIds[2] = {END_RESERVED_ID, END_RESERVED_ID + 1};
+ // Add two subdevices to device
+ std::shared_ptr<InputDevice> device = mReader->newDevice(deviceId, "fake");
+ // Must add at least one mapper or the device will be ignored!
+ device->addMapper<FakeInputMapper>(eventHubIds[0], AINPUT_SOURCE_KEYBOARD);
+ device->addMapper<FakeInputMapper>(eventHubIds[1], AINPUT_SOURCE_KEYBOARD);
+
+ // Push same device instance for next device to be added, so they'll have same identifier.
+ mReader->pushNextDevice(device);
+ mReader->pushNextDevice(device);
+ ASSERT_NO_FATAL_FAILURE(
+ addDevice(eventHubIds[0], "fake1", InputDeviceClass::KEYBOARD, nullptr));
+ ASSERT_NO_FATAL_FAILURE(
+ addDevice(eventHubIds[1], "fake2", InputDeviceClass::KEYBOARD, nullptr));
+
+ // Two devices will be merged to one input device as they have same identifier
+ std::vector<InputDeviceInfo> inputDevices;
+ mReader->getInputDevices(inputDevices);
+ ASSERT_EQ(1U, inputDevices.size());
+}
+
TEST_F(InputReaderTest, WhenEnabledChanges_SendsDeviceResetNotification) {
constexpr int32_t deviceId = END_RESERVED_ID + 1000;
constexpr Flags<InputDeviceClass> deviceClass(InputDeviceClass::KEYBOARD);
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 59a2ea4..8ac459b 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1982,7 +1982,7 @@
mFrameTimeline->setSfPresent(systemTime(),
std::make_shared<FenceTime>(mPreviousPresentFences[0]));
- const bool prevFrameHadDeviceComposition = mHadDeviceComposition;
+ const bool prevFrameHadClientComposition = mHadClientComposition;
mHadClientComposition = std::any_of(displays.cbegin(), displays.cend(), [](const auto& pair) {
const auto& state = pair.second->getCompositionDisplay()->getState();
@@ -1997,9 +1997,8 @@
const auto& state = pair.second->getCompositionDisplay()->getState();
return state.reusedClientComposition;
});
-
- // Only report a strategy change if we move in and out of composition with hw overlays
- if (prevFrameHadDeviceComposition != mHadDeviceComposition) {
+ // Only report a strategy change if we move in and out of client composition
+ if (prevFrameHadClientComposition != mHadClientComposition) {
mTimeStats->incrementCompositionStrategyChanges();
}