summaryrefslogtreecommitdiff
path: root/libs
diff options
context:
space:
mode:
Diffstat (limited to 'libs')
-rw-r--r--libs/androidfw/Android.bp2
-rw-r--r--libs/androidfw/ResourceTypes.cpp1
-rw-r--r--libs/androidfw/fuzz/resourcefile_fuzzer/Android.bp46
-rw-r--r--libs/androidfw/fuzz/resourcefile_fuzzer/corpus/resources.arscbin0 -> 724 bytes
-rw-r--r--libs/androidfw/fuzz/resourcefile_fuzzer/resourcefile_fuzzer.cpp39
-rw-r--r--libs/androidfw/libandroidfw_blocklist.txt (renamed from libs/androidfw/libandroidfw_blacklist.txt)0
-rw-r--r--libs/hwui/OWNERS7
-rw-r--r--libs/hwui/hwui/Bitmap.cpp7
-rw-r--r--libs/input/Android.bp3
-rw-r--r--libs/input/MouseCursorController.cpp489
-rw-r--r--libs/input/MouseCursorController.h118
-rw-r--r--libs/input/PointerController.cpp762
-rw-r--r--libs/input/PointerController.h164
-rw-r--r--libs/input/PointerControllerContext.cpp228
-rw-r--r--libs/input/PointerControllerContext.h183
-rw-r--r--libs/input/TouchSpotController.cpp264
-rw-r--r--libs/input/TouchSpotController.h97
-rw-r--r--libs/input/tests/PointerController_test.cpp6
18 files changed, 1571 insertions, 845 deletions
diff --git a/libs/androidfw/Android.bp b/libs/androidfw/Android.bp
index 02c85aa34f4b..aa34edf487fe 100644
--- a/libs/androidfw/Android.bp
+++ b/libs/androidfw/Android.bp
@@ -101,7 +101,7 @@ cc_library {
},
},
sanitize: {
- blacklist: "libandroidfw_blacklist.txt",
+ blocklist: "libandroidfw_blocklist.txt",
},
}
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 4d7e5dfea4f7..dfb4009b07e2 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -37,7 +37,6 @@
#include <androidfw/TypeWrappers.h>
#include <cutils/atomic.h>
#include <utils/ByteOrder.h>
-#include <utils/Debug.h>
#include <utils/Log.h>
#include <utils/String16.h>
#include <utils/String8.h>
diff --git a/libs/androidfw/fuzz/resourcefile_fuzzer/Android.bp b/libs/androidfw/fuzz/resourcefile_fuzzer/Android.bp
new file mode 100644
index 000000000000..77ef8dfb9725
--- /dev/null
+++ b/libs/androidfw/fuzz/resourcefile_fuzzer/Android.bp
@@ -0,0 +1,46 @@
+// Copyright (C) 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.
+
+cc_fuzz {
+ name: "resourcefile_fuzzer",
+ srcs: [
+ "resourcefile_fuzzer.cpp",
+ ],
+ host_supported: true,
+ corpus: ["corpus/*"],
+ static_libs: ["libgmock"],
+ target: {
+ android: {
+ shared_libs:[
+ "libandroidfw",
+ "libbase",
+ "libcutils",
+ "libutils",
+ "libziparchive",
+ "libui",
+ ],
+ },
+ host: {
+ static_libs: [
+ "libandroidfw",
+ "libbase",
+ "libcutils",
+ "libutils",
+ "libziparchive",
+ "liblog",
+ "libz",
+ ],
+ },
+ },
+}
diff --git a/libs/androidfw/fuzz/resourcefile_fuzzer/corpus/resources.arsc b/libs/androidfw/fuzz/resourcefile_fuzzer/corpus/resources.arsc
new file mode 100644
index 000000000000..3cf2ea733d28
--- /dev/null
+++ b/libs/androidfw/fuzz/resourcefile_fuzzer/corpus/resources.arsc
Binary files differ
diff --git a/libs/androidfw/fuzz/resourcefile_fuzzer/resourcefile_fuzzer.cpp b/libs/androidfw/fuzz/resourcefile_fuzzer/resourcefile_fuzzer.cpp
new file mode 100644
index 000000000000..96d44ab8e45c
--- /dev/null
+++ b/libs/androidfw/fuzz/resourcefile_fuzzer/resourcefile_fuzzer.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 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 <stddef.h>
+#include <stdint.h>
+#include <string.h>
+#include <string>
+#include <memory>
+
+#include <androidfw/ApkAssets.h>
+#include <androidfw/LoadedArsc.h>
+#include <androidfw/StringPiece.h>
+
+#include <fuzzer/FuzzedDataProvider.h>
+
+using android::ApkAssets;
+using android::LoadedArsc;
+using android::StringPiece;
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+
+ std::unique_ptr<const LoadedArsc> loaded_arsc =
+ LoadedArsc::Load(StringPiece(reinterpret_cast<const char*>(data), size));
+
+ return 0;
+} \ No newline at end of file
diff --git a/libs/androidfw/libandroidfw_blacklist.txt b/libs/androidfw/libandroidfw_blocklist.txt
index dd17e4d5b1e8..dd17e4d5b1e8 100644
--- a/libs/androidfw/libandroidfw_blacklist.txt
+++ b/libs/androidfw/libandroidfw_blocklist.txt
diff --git a/libs/hwui/OWNERS b/libs/hwui/OWNERS
index 936ba5cc8311..c232d1360419 100644
--- a/libs/hwui/OWNERS
+++ b/libs/hwui/OWNERS
@@ -1,6 +1,7 @@
+alecmouri@google.com
+djsollen@google.com
jreck@google.com
njawad@google.com
-djsollen@google.com
-stani@google.com
-scroggo@google.com
reed@google.com
+scroggo@google.com
+stani@google.com
diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp
index 56d951cdb338..60ef4371d38d 100644
--- a/libs/hwui/hwui/Bitmap.cpp
+++ b/libs/hwui/hwui/Bitmap.cpp
@@ -217,11 +217,8 @@ static SkImageInfo validateAlpha(const SkImageInfo& info) {
void Bitmap::reconfigure(const SkImageInfo& newInfo, size_t rowBytes) {
mInfo = validateAlpha(newInfo);
- // Dirty hack is dirty
- // TODO: Figure something out here, Skia's current design makes this
- // really hard to work with. Skia really, really wants immutable objects,
- // but with the nested-ref-count hackery going on that's just not
- // feasible without going insane trying to figure it out
+ // TODO: Skia intends for SkPixelRef to be immutable, but this method
+ // modifies it. Find another way to support reusing the same pixel memory.
this->android_only_reset(mInfo.width(), mInfo.height(), rowBytes);
}
diff --git a/libs/input/Android.bp b/libs/input/Android.bp
index 5252cd041199..dca35012cbdd 100644
--- a/libs/input/Android.bp
+++ b/libs/input/Android.bp
@@ -16,6 +16,9 @@ cc_library_shared {
name: "libinputservice",
srcs: [
"PointerController.cpp",
+ "PointerControllerContext.cpp",
+ "MouseCursorController.cpp",
+ "TouchSpotController.cpp",
"SpriteController.cpp",
"SpriteIcon.cpp",
],
diff --git a/libs/input/MouseCursorController.cpp b/libs/input/MouseCursorController.cpp
new file mode 100644
index 000000000000..45da008c3e8e
--- /dev/null
+++ b/libs/input/MouseCursorController.cpp
@@ -0,0 +1,489 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#define LOG_TAG "MouseCursorController"
+//#define LOG_NDEBUG 0
+
+// Log debug messages about pointer updates
+#define DEBUG_MOUSE_CURSOR_UPDATES 0
+
+#include "MouseCursorController.h"
+
+#include <log/log.h>
+
+#include <SkBitmap.h>
+#include <SkBlendMode.h>
+#include <SkCanvas.h>
+#include <SkColor.h>
+#include <SkPaint.h>
+
+namespace {
+// Time to spend fading out the pointer completely.
+const nsecs_t POINTER_FADE_DURATION = 500 * 1000000LL; // 500 ms
+} // namespace
+
+namespace android {
+
+// --- MouseCursorController ---
+
+MouseCursorController::MouseCursorController(PointerControllerContext& context)
+ : mContext(context) {
+ std::scoped_lock lock(mLock);
+
+ mLocked.animationFrameIndex = 0;
+ mLocked.lastFrameUpdatedTime = 0;
+
+ mLocked.pointerFadeDirection = 0;
+ mLocked.pointerX = 0;
+ mLocked.pointerY = 0;
+ mLocked.pointerAlpha = 0.0f; // pointer is initially faded
+ mLocked.pointerSprite = mContext.getSpriteController()->createSprite();
+ mLocked.updatePointerIcon = false;
+ mLocked.requestedPointerType = mContext.getPolicy()->getDefaultPointerIconId();
+
+ mLocked.resourcesLoaded = false;
+
+ mLocked.buttonState = 0;
+}
+
+MouseCursorController::~MouseCursorController() {
+ std::scoped_lock lock(mLock);
+
+ mLocked.pointerSprite.clear();
+}
+
+bool MouseCursorController::getBounds(float* outMinX, float* outMinY, float* outMaxX,
+ float* outMaxY) const {
+ std::scoped_lock lock(mLock);
+
+ return getBoundsLocked(outMinX, outMinY, outMaxX, outMaxY);
+}
+
+bool MouseCursorController::getBoundsLocked(float* outMinX, float* outMinY, float* outMaxX,
+ float* outMaxY) const REQUIRES(mLock) {
+ if (!mLocked.viewport.isValid()) {
+ return false;
+ }
+
+ *outMinX = mLocked.viewport.logicalLeft;
+ *outMinY = mLocked.viewport.logicalTop;
+ *outMaxX = mLocked.viewport.logicalRight - 1;
+ *outMaxY = mLocked.viewport.logicalBottom - 1;
+ return true;
+}
+
+void MouseCursorController::move(float deltaX, float deltaY) {
+#if DEBUG_MOUSE_CURSOR_UPDATES
+ ALOGD("Move pointer by deltaX=%0.3f, deltaY=%0.3f", deltaX, deltaY);
+#endif
+ if (deltaX == 0.0f && deltaY == 0.0f) {
+ return;
+ }
+
+ std::scoped_lock lock(mLock);
+
+ setPositionLocked(mLocked.pointerX + deltaX, mLocked.pointerY + deltaY);
+}
+
+void MouseCursorController::setButtonState(int32_t buttonState) {
+#if DEBUG_MOUSE_CURSOR_UPDATES
+ ALOGD("Set button state 0x%08x", buttonState);
+#endif
+ std::scoped_lock lock(mLock);
+
+ if (mLocked.buttonState != buttonState) {
+ mLocked.buttonState = buttonState;
+ }
+}
+
+int32_t MouseCursorController::getButtonState() const {
+ std::scoped_lock lock(mLock);
+ return mLocked.buttonState;
+}
+
+void MouseCursorController::setPosition(float x, float y) {
+#if DEBUG_MOUSE_CURSOR_UPDATES
+ ALOGD("Set pointer position to x=%0.3f, y=%0.3f", x, y);
+#endif
+ std::scoped_lock lock(mLock);
+ setPositionLocked(x, y);
+}
+
+void MouseCursorController::setPositionLocked(float x, float y) REQUIRES(mLock) {
+ float minX, minY, maxX, maxY;
+ if (getBoundsLocked(&minX, &minY, &maxX, &maxY)) {
+ if (x <= minX) {
+ mLocked.pointerX = minX;
+ } else if (x >= maxX) {
+ mLocked.pointerX = maxX;
+ } else {
+ mLocked.pointerX = x;
+ }
+ if (y <= minY) {
+ mLocked.pointerY = minY;
+ } else if (y >= maxY) {
+ mLocked.pointerY = maxY;
+ } else {
+ mLocked.pointerY = y;
+ }
+ updatePointerLocked();
+ }
+}
+
+void MouseCursorController::getPosition(float* outX, float* outY) const {
+ std::scoped_lock lock(mLock);
+
+ *outX = mLocked.pointerX;
+ *outY = mLocked.pointerY;
+}
+
+int32_t MouseCursorController::getDisplayId() const {
+ std::scoped_lock lock(mLock);
+ return mLocked.viewport.displayId;
+}
+
+void MouseCursorController::fade(PointerControllerInterface::Transition transition) {
+ std::scoped_lock lock(mLock);
+
+ // Remove the inactivity timeout, since we are fading now.
+ mContext.removeInactivityTimeout();
+
+ // Start fading.
+ if (transition == PointerControllerInterface::Transition::IMMEDIATE) {
+ mLocked.pointerFadeDirection = 0;
+ mLocked.pointerAlpha = 0.0f;
+ updatePointerLocked();
+ } else {
+ mLocked.pointerFadeDirection = -1;
+ startAnimationLocked();
+ }
+}
+
+void MouseCursorController::unfade(PointerControllerInterface::Transition transition) {
+ std::scoped_lock lock(mLock);
+
+ // Always reset the inactivity timer.
+ mContext.resetInactivityTimeout();
+
+ // Start unfading.
+ if (transition == PointerControllerInterface::Transition::IMMEDIATE) {
+ mLocked.pointerFadeDirection = 0;
+ mLocked.pointerAlpha = 1.0f;
+ updatePointerLocked();
+ } else {
+ mLocked.pointerFadeDirection = 1;
+ startAnimationLocked();
+ }
+}
+
+void MouseCursorController::reloadPointerResources(bool getAdditionalMouseResources) {
+ std::scoped_lock lock(mLock);
+
+ loadResourcesLocked(getAdditionalMouseResources);
+ updatePointerLocked();
+}
+
+/**
+ * The viewport values for deviceHeight and deviceWidth have already been adjusted for rotation,
+ * so here we are getting the dimensions in the original, unrotated orientation (orientation 0).
+ */
+static void getNonRotatedSize(const DisplayViewport& viewport, int32_t& width, int32_t& height) {
+ width = viewport.deviceWidth;
+ height = viewport.deviceHeight;
+
+ if (viewport.orientation == DISPLAY_ORIENTATION_90 ||
+ viewport.orientation == DISPLAY_ORIENTATION_270) {
+ std::swap(width, height);
+ }
+}
+
+void MouseCursorController::setDisplayViewport(const DisplayViewport& viewport,
+ bool getAdditionalMouseResources) {
+ std::scoped_lock lock(mLock);
+
+ if (viewport == mLocked.viewport) {
+ return;
+ }
+
+ const DisplayViewport oldViewport = mLocked.viewport;
+ mLocked.viewport = viewport;
+
+ int32_t oldDisplayWidth, oldDisplayHeight;
+ getNonRotatedSize(oldViewport, oldDisplayWidth, oldDisplayHeight);
+ int32_t newDisplayWidth, newDisplayHeight;
+ getNonRotatedSize(viewport, newDisplayWidth, newDisplayHeight);
+
+ // Reset cursor position to center if size or display changed.
+ if (oldViewport.displayId != viewport.displayId || oldDisplayWidth != newDisplayWidth ||
+ oldDisplayHeight != newDisplayHeight) {
+ float minX, minY, maxX, maxY;
+ if (getBoundsLocked(&minX, &minY, &maxX, &maxY)) {
+ mLocked.pointerX = (minX + maxX) * 0.5f;
+ mLocked.pointerY = (minY + maxY) * 0.5f;
+ // Reload icon resources for density may be changed.
+ loadResourcesLocked(getAdditionalMouseResources);
+ } else {
+ mLocked.pointerX = 0;
+ mLocked.pointerY = 0;
+ }
+ } else if (oldViewport.orientation != viewport.orientation) {
+ // Apply offsets to convert from the pixel top-left corner position to the pixel center.
+ // This creates an invariant frame of reference that we can easily rotate when
+ // taking into account that the pointer may be located at fractional pixel offsets.
+ float x = mLocked.pointerX + 0.5f;
+ float y = mLocked.pointerY + 0.5f;
+ float temp;
+
+ // Undo the previous rotation.
+ switch (oldViewport.orientation) {
+ case DISPLAY_ORIENTATION_90:
+ temp = x;
+ x = oldViewport.deviceHeight - y;
+ y = temp;
+ break;
+ case DISPLAY_ORIENTATION_180:
+ x = oldViewport.deviceWidth - x;
+ y = oldViewport.deviceHeight - y;
+ break;
+ case DISPLAY_ORIENTATION_270:
+ temp = x;
+ x = y;
+ y = oldViewport.deviceWidth - temp;
+ break;
+ }
+
+ // Perform the new rotation.
+ switch (viewport.orientation) {
+ case DISPLAY_ORIENTATION_90:
+ temp = x;
+ x = y;
+ y = viewport.deviceHeight - temp;
+ break;
+ case DISPLAY_ORIENTATION_180:
+ x = viewport.deviceWidth - x;
+ y = viewport.deviceHeight - y;
+ break;
+ case DISPLAY_ORIENTATION_270:
+ temp = x;
+ x = viewport.deviceWidth - y;
+ y = temp;
+ break;
+ }
+
+ // Apply offsets to convert from the pixel center to the pixel top-left corner position
+ // and save the results.
+ mLocked.pointerX = x - 0.5f;
+ mLocked.pointerY = y - 0.5f;
+ }
+
+ updatePointerLocked();
+}
+
+void MouseCursorController::updatePointerIcon(int32_t iconId) {
+ std::scoped_lock lock(mLock);
+
+ if (mLocked.requestedPointerType != iconId) {
+ mLocked.requestedPointerType = iconId;
+ mLocked.updatePointerIcon = true;
+ updatePointerLocked();
+ }
+}
+
+void MouseCursorController::setCustomPointerIcon(const SpriteIcon& icon) {
+ std::scoped_lock lock(mLock);
+
+ const int32_t iconId = mContext.getPolicy()->getCustomPointerIconId();
+ mLocked.additionalMouseResources[iconId] = icon;
+ mLocked.requestedPointerType = iconId;
+ mLocked.updatePointerIcon = true;
+ updatePointerLocked();
+}
+
+bool MouseCursorController::doFadingAnimationLocked(nsecs_t timestamp) REQUIRES(mLock) {
+ nsecs_t frameDelay = timestamp - mContext.getAnimationTime();
+ bool keepAnimating = false;
+
+ // Animate pointer fade.
+ if (mLocked.pointerFadeDirection < 0) {
+ mLocked.pointerAlpha -= float(frameDelay) / POINTER_FADE_DURATION;
+ if (mLocked.pointerAlpha <= 0.0f) {
+ mLocked.pointerAlpha = 0.0f;
+ mLocked.pointerFadeDirection = 0;
+ } else {
+ keepAnimating = true;
+ }
+ updatePointerLocked();
+ } else if (mLocked.pointerFadeDirection > 0) {
+ mLocked.pointerAlpha += float(frameDelay) / POINTER_FADE_DURATION;
+ if (mLocked.pointerAlpha >= 1.0f) {
+ mLocked.pointerAlpha = 1.0f;
+ mLocked.pointerFadeDirection = 0;
+ } else {
+ keepAnimating = true;
+ }
+ updatePointerLocked();
+ }
+ return keepAnimating;
+}
+
+bool MouseCursorController::doBitmapAnimationLocked(nsecs_t timestamp) REQUIRES(mLock) {
+ std::map<int32_t, PointerAnimation>::const_iterator iter =
+ mLocked.animationResources.find(mLocked.requestedPointerType);
+ if (iter == mLocked.animationResources.end()) {
+ return false;
+ }
+
+ if (timestamp - mLocked.lastFrameUpdatedTime > iter->second.durationPerFrame) {
+ sp<SpriteController> spriteController = mContext.getSpriteController();
+ spriteController->openTransaction();
+
+ int incr = (timestamp - mLocked.lastFrameUpdatedTime) / iter->second.durationPerFrame;
+ mLocked.animationFrameIndex += incr;
+ mLocked.lastFrameUpdatedTime += iter->second.durationPerFrame * incr;
+ while (mLocked.animationFrameIndex >= iter->second.animationFrames.size()) {
+ mLocked.animationFrameIndex -= iter->second.animationFrames.size();
+ }
+ mLocked.pointerSprite->setIcon(iter->second.animationFrames[mLocked.animationFrameIndex]);
+
+ spriteController->closeTransaction();
+ }
+ // Keep animating.
+ return true;
+}
+
+void MouseCursorController::updatePointerLocked() REQUIRES(mLock) {
+ if (!mLocked.viewport.isValid()) {
+ return;
+ }
+ sp<SpriteController> spriteController = mContext.getSpriteController();
+ spriteController->openTransaction();
+
+ mLocked.pointerSprite->setLayer(Sprite::BASE_LAYER_POINTER);
+ mLocked.pointerSprite->setPosition(mLocked.pointerX, mLocked.pointerY);
+ mLocked.pointerSprite->setDisplayId(mLocked.viewport.displayId);
+
+ if (mLocked.pointerAlpha > 0) {
+ mLocked.pointerSprite->setAlpha(mLocked.pointerAlpha);
+ mLocked.pointerSprite->setVisible(true);
+ } else {
+ mLocked.pointerSprite->setVisible(false);
+ }
+
+ if (mLocked.updatePointerIcon) {
+ if (mLocked.requestedPointerType == mContext.getPolicy()->getDefaultPointerIconId()) {
+ mLocked.pointerSprite->setIcon(mLocked.pointerIcon);
+ } else {
+ std::map<int32_t, SpriteIcon>::const_iterator iter =
+ mLocked.additionalMouseResources.find(mLocked.requestedPointerType);
+ if (iter != mLocked.additionalMouseResources.end()) {
+ std::map<int32_t, PointerAnimation>::const_iterator anim_iter =
+ mLocked.animationResources.find(mLocked.requestedPointerType);
+ if (anim_iter != mLocked.animationResources.end()) {
+ mLocked.animationFrameIndex = 0;
+ mLocked.lastFrameUpdatedTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ startAnimationLocked();
+ }
+ mLocked.pointerSprite->setIcon(iter->second);
+ } else {
+ ALOGW("Can't find the resource for icon id %d", mLocked.requestedPointerType);
+ mLocked.pointerSprite->setIcon(mLocked.pointerIcon);
+ }
+ }
+ mLocked.updatePointerIcon = false;
+ }
+
+ spriteController->closeTransaction();
+}
+
+void MouseCursorController::loadResourcesLocked(bool getAdditionalMouseResources) REQUIRES(mLock) {
+ if (!mLocked.viewport.isValid()) {
+ return;
+ }
+
+ if (!mLocked.resourcesLoaded) mLocked.resourcesLoaded = true;
+
+ sp<PointerControllerPolicyInterface> policy = mContext.getPolicy();
+ policy->loadPointerResources(&mResources, mLocked.viewport.displayId);
+ policy->loadPointerIcon(&mLocked.pointerIcon, mLocked.viewport.displayId);
+
+ mLocked.additionalMouseResources.clear();
+ mLocked.animationResources.clear();
+ if (getAdditionalMouseResources) {
+ policy->loadAdditionalMouseResources(&mLocked.additionalMouseResources,
+ &mLocked.animationResources,
+ mLocked.viewport.displayId);
+ }
+
+ mLocked.updatePointerIcon = true;
+}
+
+bool MouseCursorController::isViewportValid() {
+ std::scoped_lock lock(mLock);
+ return mLocked.viewport.isValid();
+}
+
+void MouseCursorController::getAdditionalMouseResources() {
+ std::scoped_lock lock(mLock);
+
+ if (mLocked.additionalMouseResources.empty()) {
+ mContext.getPolicy()->loadAdditionalMouseResources(&mLocked.additionalMouseResources,
+ &mLocked.animationResources,
+ mLocked.viewport.displayId);
+ }
+ mLocked.updatePointerIcon = true;
+ updatePointerLocked();
+}
+
+bool MouseCursorController::resourcesLoaded() {
+ std::scoped_lock lock(mLock);
+ return mLocked.resourcesLoaded;
+}
+
+bool MouseCursorController::doAnimations(nsecs_t timestamp) {
+ std::scoped_lock lock(mLock);
+ bool keepFading = doFadingAnimationLocked(timestamp);
+ bool keepBitmap = doBitmapAnimationLocked(timestamp);
+ bool keepAnimating = keepFading || keepBitmap;
+ if (!keepAnimating) {
+ /*
+ * We know that this callback will be removed before another
+ * is added. mLock in PointerAnimator will not be released
+ * until after this is removed, and adding another callback
+ * requires that lock. Thus it's safe to set mLocked.animating
+ * here.
+ */
+ mLocked.animating = false;
+ }
+ return keepAnimating;
+}
+
+void MouseCursorController::startAnimationLocked() REQUIRES(mLock) {
+ using namespace std::placeholders;
+
+ if (mLocked.animating) {
+ return;
+ }
+ mLocked.animating = true;
+
+ std::function<bool(nsecs_t)> func = std::bind(&MouseCursorController::doAnimations, this, _1);
+ /*
+ * Using -1 for displayId here to avoid removing the callback
+ * if a TouchSpotController with the same display is removed.
+ */
+ mContext.addAnimationCallback(-1, func);
+}
+
+} // namespace android
diff --git a/libs/input/MouseCursorController.h b/libs/input/MouseCursorController.h
new file mode 100644
index 000000000000..e6dfc4c6f99a
--- /dev/null
+++ b/libs/input/MouseCursorController.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef _UI_MOUSE_CURSOR_CONTROLLER_H
+#define _UI_MOUSE_CURSOR_CONTROLLER_H
+
+#include <gui/DisplayEventReceiver.h>
+#include <input/DisplayViewport.h>
+#include <input/Input.h>
+#include <ui/DisplayInfo.h>
+#include <utils/BitSet.h>
+#include <utils/Looper.h>
+#include <utils/RefBase.h>
+
+#include <functional>
+#include <map>
+#include <memory>
+#include <vector>
+
+#include "PointerControllerContext.h"
+#include "SpriteController.h"
+
+namespace android {
+
+/*
+ * Helper class for PointerController that specifically handles
+ * mouse cursor resources and actions.
+ */
+class MouseCursorController {
+public:
+ MouseCursorController(PointerControllerContext& context);
+ ~MouseCursorController();
+
+ bool getBounds(float* outMinX, float* outMinY, float* outMaxX, float* outMaxY) const;
+ void move(float deltaX, float deltaY);
+ void setButtonState(int32_t buttonState);
+ int32_t getButtonState() const;
+ void setPosition(float x, float y);
+ void getPosition(float* outX, float* outY) const;
+ int32_t getDisplayId() const;
+ void fade(PointerControllerInterface::Transition transition);
+ void unfade(PointerControllerInterface::Transition transition);
+ void setDisplayViewport(const DisplayViewport& viewport, bool getAdditionalMouseResources);
+
+ void updatePointerIcon(int32_t iconId);
+ void setCustomPointerIcon(const SpriteIcon& icon);
+ void reloadPointerResources(bool getAdditionalMouseResources);
+
+ void getAdditionalMouseResources();
+ bool isViewportValid();
+
+ bool doAnimations(nsecs_t timestamp);
+
+ bool resourcesLoaded();
+
+private:
+ mutable std::mutex mLock;
+
+ PointerResources mResources;
+
+ PointerControllerContext& mContext;
+
+ struct Locked {
+ DisplayViewport viewport;
+
+ size_t animationFrameIndex;
+ nsecs_t lastFrameUpdatedTime;
+
+ int32_t pointerFadeDirection;
+ float pointerX;
+ float pointerY;
+ float pointerAlpha;
+ sp<Sprite> pointerSprite;
+ SpriteIcon pointerIcon;
+ bool updatePointerIcon;
+
+ bool resourcesLoaded;
+
+ std::map<int32_t, SpriteIcon> additionalMouseResources;
+ std::map<int32_t, PointerAnimation> animationResources;
+
+ int32_t requestedPointerType;
+
+ int32_t buttonState;
+
+ bool animating{false};
+
+ } mLocked GUARDED_BY(mLock);
+
+ bool getBoundsLocked(float* outMinX, float* outMinY, float* outMaxX, float* outMaxY) const;
+ void setPositionLocked(float x, float y);
+
+ void updatePointerLocked();
+
+ void loadResourcesLocked(bool getAdditionalMouseResources);
+
+ bool doBitmapAnimationLocked(nsecs_t timestamp);
+ bool doFadingAnimationLocked(nsecs_t timestamp);
+
+ void startAnimationLocked();
+};
+
+} // namespace android
+
+#endif // _UI_MOUSE_CURSOR_CONTROLLER_H
diff --git a/libs/input/PointerController.cpp b/libs/input/PointerController.cpp
index 5e480a66c355..8f04cfb70469 100644
--- a/libs/input/PointerController.cpp
+++ b/libs/input/PointerController.cpp
@@ -21,31 +21,26 @@
#define DEBUG_POINTER_UPDATES 0
#include "PointerController.h"
+#include "MouseCursorController.h"
+#include "PointerControllerContext.h"
+#include "TouchSpotController.h"
#include <log/log.h>
-#include <memory>
+#include <SkBitmap.h>
+#include <SkBlendMode.h>
+#include <SkCanvas.h>
+#include <SkColor.h>
+#include <SkPaint.h>
namespace android {
// --- PointerController ---
-// Time to wait before starting the fade when the pointer is inactive.
-static const nsecs_t INACTIVITY_TIMEOUT_DELAY_TIME_NORMAL = 15 * 1000 * 1000000LL; // 15 seconds
-static const nsecs_t INACTIVITY_TIMEOUT_DELAY_TIME_SHORT = 3 * 1000 * 1000000LL; // 3 seconds
-
-// Time to spend fading out the spot completely.
-static const nsecs_t SPOT_FADE_DURATION = 200 * 1000000LL; // 200 ms
-
-// Time to spend fading out the pointer completely.
-static const nsecs_t POINTER_FADE_DURATION = 500 * 1000000LL; // 500 ms
-
-// The number of events to be read at once for DisplayEventReceiver.
-static const int EVENT_BUFFER_SIZE = 100;
-
std::shared_ptr<PointerController> PointerController::create(
const sp<PointerControllerPolicyInterface>& policy, const sp<Looper>& looper,
const sp<SpriteController>& spriteController) {
+ // using 'new' to access non-public constructor
std::shared_ptr<PointerController> controller = std::shared_ptr<PointerController>(
new PointerController(policy, looper, spriteController));
@@ -60,758 +55,161 @@ std::shared_ptr<PointerController> PointerController::create(
* weak_ptr's which themselves cannot be constructed until there's at least one shared_ptr.
*/
- controller->mHandler->pointerController = controller;
- controller->mCallback->pointerController = controller;
- if (controller->mDisplayEventReceiver.initCheck() == NO_ERROR) {
- controller->mLooper->addFd(controller->mDisplayEventReceiver.getFd(), Looper::POLL_CALLBACK,
- Looper::EVENT_INPUT, controller->mCallback, nullptr);
- } else {
- ALOGE("Failed to initialize DisplayEventReceiver.");
- }
+ controller->mContext.setHandlerController(controller);
+ controller->mContext.setCallbackController(controller);
return controller;
}
PointerController::PointerController(const sp<PointerControllerPolicyInterface>& policy,
const sp<Looper>& looper,
const sp<SpriteController>& spriteController)
- : mPolicy(policy),
- mLooper(looper),
- mSpriteController(spriteController),
- mHandler(new MessageHandler()),
- mCallback(new LooperCallback()) {
- AutoMutex _l(mLock);
-
- mLocked.animationPending = false;
-
- mLocked.presentation = Presentation::POINTER;
- mLocked.presentationChanged = false;
-
- mLocked.inactivityTimeout = InactivityTimeout::NORMAL;
-
- mLocked.pointerFadeDirection = 0;
- mLocked.pointerX = 0;
- mLocked.pointerY = 0;
- mLocked.pointerAlpha = 0.0f; // pointer is initially faded
- mLocked.pointerSprite = mSpriteController->createSprite();
- mLocked.pointerIconChanged = false;
- mLocked.requestedPointerType = mPolicy->getDefaultPointerIconId();
-
- mLocked.animationFrameIndex = 0;
- mLocked.lastFrameUpdatedTime = 0;
-
- mLocked.buttonState = 0;
-}
-
-PointerController::~PointerController() {
- mLooper->removeMessages(mHandler);
-
- AutoMutex _l(mLock);
-
- mLocked.pointerSprite.clear();
-
- for (auto& it : mLocked.spotsByDisplay) {
- const std::vector<Spot*>& spots = it.second;
- size_t numSpots = spots.size();
- for (size_t i = 0; i < numSpots; i++) {
- delete spots[i];
- }
- }
- mLocked.spotsByDisplay.clear();
- mLocked.recycledSprites.clear();
+ : mContext(policy, looper, spriteController, *this), mCursorController(mContext) {
+ std::scoped_lock lock(mLock);
+ mLocked.presentation = Presentation::SPOT;
}
-bool PointerController::getBounds(float* outMinX, float* outMinY,
- float* outMaxX, float* outMaxY) const {
- AutoMutex _l(mLock);
-
- return getBoundsLocked(outMinX, outMinY, outMaxX, outMaxY);
-}
-
-bool PointerController::getBoundsLocked(float* outMinX, float* outMinY,
- float* outMaxX, float* outMaxY) const {
-
- if (!mLocked.viewport.isValid()) {
- return false;
- }
-
- *outMinX = mLocked.viewport.logicalLeft;
- *outMinY = mLocked.viewport.logicalTop;
- *outMaxX = mLocked.viewport.logicalRight - 1;
- *outMaxY = mLocked.viewport.logicalBottom - 1;
- return true;
+bool PointerController::getBounds(float* outMinX, float* outMinY, float* outMaxX,
+ float* outMaxY) const {
+ return mCursorController.getBounds(outMinX, outMinY, outMaxX, outMaxY);
}
void PointerController::move(float deltaX, float deltaY) {
-#if DEBUG_POINTER_UPDATES
- ALOGD("Move pointer by deltaX=%0.3f, deltaY=%0.3f", deltaX, deltaY);
-#endif
- if (deltaX == 0.0f && deltaY == 0.0f) {
- return;
- }
-
- AutoMutex _l(mLock);
-
- setPositionLocked(mLocked.pointerX + deltaX, mLocked.pointerY + deltaY);
+ mCursorController.move(deltaX, deltaY);
}
void PointerController::setButtonState(int32_t buttonState) {
-#if DEBUG_POINTER_UPDATES
- ALOGD("Set button state 0x%08x", buttonState);
-#endif
- AutoMutex _l(mLock);
-
- if (mLocked.buttonState != buttonState) {
- mLocked.buttonState = buttonState;
- }
+ mCursorController.setButtonState(buttonState);
}
int32_t PointerController::getButtonState() const {
- AutoMutex _l(mLock);
-
- return mLocked.buttonState;
+ return mCursorController.getButtonState();
}
void PointerController::setPosition(float x, float y) {
-#if DEBUG_POINTER_UPDATES
- ALOGD("Set pointer position to x=%0.3f, y=%0.3f", x, y);
-#endif
- AutoMutex _l(mLock);
-
- setPositionLocked(x, y);
-}
-
-void PointerController::setPositionLocked(float x, float y) {
- float minX, minY, maxX, maxY;
- if (getBoundsLocked(&minX, &minY, &maxX, &maxY)) {
- if (x <= minX) {
- mLocked.pointerX = minX;
- } else if (x >= maxX) {
- mLocked.pointerX = maxX;
- } else {
- mLocked.pointerX = x;
- }
- if (y <= minY) {
- mLocked.pointerY = minY;
- } else if (y >= maxY) {
- mLocked.pointerY = maxY;
- } else {
- mLocked.pointerY = y;
- }
- updatePointerLocked();
- }
+ std::scoped_lock lock(mLock);
+ mCursorController.setPosition(x, y);
}
void PointerController::getPosition(float* outX, float* outY) const {
- AutoMutex _l(mLock);
-
- *outX = mLocked.pointerX;
- *outY = mLocked.pointerY;
+ mCursorController.getPosition(outX, outY);
}
int32_t PointerController::getDisplayId() const {
- AutoMutex _l(mLock);
-
- return mLocked.viewport.displayId;
+ return mCursorController.getDisplayId();
}
void PointerController::fade(Transition transition) {
- AutoMutex _l(mLock);
-
- // Remove the inactivity timeout, since we are fading now.
- removeInactivityTimeoutLocked();
-
- // Start fading.
- if (transition == Transition::IMMEDIATE) {
- mLocked.pointerFadeDirection = 0;
- mLocked.pointerAlpha = 0.0f;
- updatePointerLocked();
- } else {
- mLocked.pointerFadeDirection = -1;
- startAnimationLocked();
- }
+ std::scoped_lock lock(mLock);
+ mCursorController.fade(transition);
}
void PointerController::unfade(Transition transition) {
- AutoMutex _l(mLock);
-
- // Always reset the inactivity timer.
- resetInactivityTimeoutLocked();
-
- // Start unfading.
- if (transition == Transition::IMMEDIATE) {
- mLocked.pointerFadeDirection = 0;
- mLocked.pointerAlpha = 1.0f;
- updatePointerLocked();
- } else {
- mLocked.pointerFadeDirection = 1;
- startAnimationLocked();
- }
+ std::scoped_lock lock(mLock);
+ mCursorController.unfade(transition);
}
void PointerController::setPresentation(Presentation presentation) {
- AutoMutex _l(mLock);
+ std::scoped_lock lock(mLock);
if (mLocked.presentation == presentation) {
return;
}
mLocked.presentation = presentation;
- mLocked.presentationChanged = true;
- if (!mLocked.viewport.isValid()) {
+ if (!mCursorController.isViewportValid()) {
return;
}
if (presentation == Presentation::POINTER) {
- if (mLocked.additionalMouseResources.empty()) {
- mPolicy->loadAdditionalMouseResources(&mLocked.additionalMouseResources,
- &mLocked.animationResources,
- mLocked.viewport.displayId);
- }
- fadeOutAndReleaseAllSpotsLocked();
- updatePointerLocked();
+ mCursorController.getAdditionalMouseResources();
+ clearSpotsLocked();
}
}
-void PointerController::setSpots(const PointerCoords* spotCoords,
- const uint32_t* spotIdToIndex, BitSet32 spotIdBits, int32_t displayId) {
-#if DEBUG_POINTER_UPDATES
- ALOGD("setSpots: idBits=%08x", spotIdBits.value);
- for (BitSet32 idBits(spotIdBits); !idBits.isEmpty(); ) {
- uint32_t id = idBits.firstMarkedBit();
- idBits.clearBit(id);
- const PointerCoords& c = spotCoords[spotIdToIndex[id]];
- ALOGD(" spot %d: position=(%0.3f, %0.3f), pressure=%0.3f, displayId=%" PRId32 ".", id,
- c.getAxisValue(AMOTION_EVENT_AXIS_X),
- c.getAxisValue(AMOTION_EVENT_AXIS_Y),
- c.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE),
- displayId);
- }
-#endif
-
- AutoMutex _l(mLock);
- if (!mLocked.viewport.isValid()) {
- return;
- }
-
- std::vector<Spot*> newSpots;
- std::map<int32_t, std::vector<Spot*>>::const_iterator iter =
- mLocked.spotsByDisplay.find(displayId);
- if (iter != mLocked.spotsByDisplay.end()) {
- newSpots = iter->second;
- }
-
- mSpriteController->openTransaction();
-
- // Add or move spots for fingers that are down.
- for (BitSet32 idBits(spotIdBits); !idBits.isEmpty(); ) {
- uint32_t id = idBits.clearFirstMarkedBit();
- const PointerCoords& c = spotCoords[spotIdToIndex[id]];
- const SpriteIcon& icon = c.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE) > 0
- ? mResources.spotTouch : mResources.spotHover;
- float x = c.getAxisValue(AMOTION_EVENT_AXIS_X);
- float y = c.getAxisValue(AMOTION_EVENT_AXIS_Y);
-
- Spot* spot = getSpot(id, newSpots);
- if (!spot) {
- spot = createAndAddSpotLocked(id, newSpots);
- }
-
- spot->updateSprite(&icon, x, y, displayId);
- }
-
- // Remove spots for fingers that went up.
- for (size_t i = 0; i < newSpots.size(); i++) {
- Spot* spot = newSpots[i];
- if (spot->id != Spot::INVALID_ID
- && !spotIdBits.hasBit(spot->id)) {
- fadeOutAndReleaseSpotLocked(spot);
- }
+void PointerController::setSpots(const PointerCoords* spotCoords, const uint32_t* spotIdToIndex,
+ BitSet32 spotIdBits, int32_t displayId) {
+ std::scoped_lock lock(mLock);
+ auto it = mLocked.spotControllers.find(displayId);
+ if (it == mLocked.spotControllers.end()) {
+ mLocked.spotControllers.try_emplace(displayId, displayId, mContext);
}
-
- mSpriteController->closeTransaction();
- mLocked.spotsByDisplay[displayId] = newSpots;
+ mLocked.spotControllers.at(displayId).setSpots(spotCoords, spotIdToIndex, spotIdBits);
}
void PointerController::clearSpots() {
-#if DEBUG_POINTER_UPDATES
- ALOGD("clearSpots");
-#endif
+ std::scoped_lock lock(mLock);
+ clearSpotsLocked();
+}
- AutoMutex _l(mLock);
- if (!mLocked.viewport.isValid()) {
- return;
+void PointerController::clearSpotsLocked() REQUIRES(mLock) {
+ for (auto& [displayID, spotController] : mLocked.spotControllers) {
+ spotController.clearSpots();
}
-
- fadeOutAndReleaseAllSpotsLocked();
}
void PointerController::setInactivityTimeout(InactivityTimeout inactivityTimeout) {
- AutoMutex _l(mLock);
-
- if (mLocked.inactivityTimeout != inactivityTimeout) {
- mLocked.inactivityTimeout = inactivityTimeout;
- resetInactivityTimeoutLocked();
- }
+ mContext.setInactivityTimeout(inactivityTimeout);
}
void PointerController::reloadPointerResources() {
- AutoMutex _l(mLock);
-
- loadResourcesLocked();
- updatePointerLocked();
-}
+ std::scoped_lock lock(mLock);
-/**
- * The viewport values for deviceHeight and deviceWidth have already been adjusted for rotation,
- * so here we are getting the dimensions in the original, unrotated orientation (orientation 0).
- */
-static void getNonRotatedSize(const DisplayViewport& viewport, int32_t& width, int32_t& height) {
- width = viewport.deviceWidth;
- height = viewport.deviceHeight;
+ for (auto& [displayID, spotController] : mLocked.spotControllers) {
+ spotController.reloadSpotResources();
+ }
- if (viewport.orientation == DISPLAY_ORIENTATION_90
- || viewport.orientation == DISPLAY_ORIENTATION_270) {
- std::swap(width, height);
+ if (mCursorController.resourcesLoaded()) {
+ bool getAdditionalMouseResources = false;
+ if (mLocked.presentation == PointerController::Presentation::POINTER) {
+ getAdditionalMouseResources = true;
+ }
+ mCursorController.reloadPointerResources(getAdditionalMouseResources);
}
}
void PointerController::setDisplayViewport(const DisplayViewport& viewport) {
- AutoMutex _l(mLock);
- if (viewport == mLocked.viewport) {
- return;
- }
+ std::scoped_lock lock(mLock);
- const DisplayViewport oldViewport = mLocked.viewport;
- mLocked.viewport = viewport;
-
- int32_t oldDisplayWidth, oldDisplayHeight;
- getNonRotatedSize(oldViewport, oldDisplayWidth, oldDisplayHeight);
- int32_t newDisplayWidth, newDisplayHeight;
- getNonRotatedSize(viewport, newDisplayWidth, newDisplayHeight);
-
- // Reset cursor position to center if size or display changed.
- if (oldViewport.displayId != viewport.displayId
- || oldDisplayWidth != newDisplayWidth
- || oldDisplayHeight != newDisplayHeight) {
-
- float minX, minY, maxX, maxY;
- if (getBoundsLocked(&minX, &minY, &maxX, &maxY)) {
- mLocked.pointerX = (minX + maxX) * 0.5f;
- mLocked.pointerY = (minY + maxY) * 0.5f;
- // Reload icon resources for density may be changed.
- loadResourcesLocked();
- } else {
- mLocked.pointerX = 0;
- mLocked.pointerY = 0;
- }
-
- fadeOutAndReleaseAllSpotsLocked();
- } else if (oldViewport.orientation != viewport.orientation) {
- // Apply offsets to convert from the pixel top-left corner position to the pixel center.
- // This creates an invariant frame of reference that we can easily rotate when
- // taking into account that the pointer may be located at fractional pixel offsets.
- float x = mLocked.pointerX + 0.5f;
- float y = mLocked.pointerY + 0.5f;
- float temp;
-
- // Undo the previous rotation.
- switch (oldViewport.orientation) {
- case DISPLAY_ORIENTATION_90:
- temp = x;
- x = oldViewport.deviceHeight - y;
- y = temp;
- break;
- case DISPLAY_ORIENTATION_180:
- x = oldViewport.deviceWidth - x;
- y = oldViewport.deviceHeight - y;
- break;
- case DISPLAY_ORIENTATION_270:
- temp = x;
- x = y;
- y = oldViewport.deviceWidth - temp;
- break;
- }
-
- // Perform the new rotation.
- switch (viewport.orientation) {
- case DISPLAY_ORIENTATION_90:
- temp = x;
- x = y;
- y = viewport.deviceHeight - temp;
- break;
- case DISPLAY_ORIENTATION_180:
- x = viewport.deviceWidth - x;
- y = viewport.deviceHeight - y;
- break;
- case DISPLAY_ORIENTATION_270:
- temp = x;
- x = viewport.deviceWidth - y;
- y = temp;
- break;
- }
-
- // Apply offsets to convert from the pixel center to the pixel top-left corner position
- // and save the results.
- mLocked.pointerX = x - 0.5f;
- mLocked.pointerY = y - 0.5f;
+ bool getAdditionalMouseResources = false;
+ if (mLocked.presentation == PointerController::Presentation::POINTER) {
+ getAdditionalMouseResources = true;
}
-
- updatePointerLocked();
+ mCursorController.setDisplayViewport(viewport, getAdditionalMouseResources);
}
void PointerController::updatePointerIcon(int32_t iconId) {
- AutoMutex _l(mLock);
- if (mLocked.requestedPointerType != iconId) {
- mLocked.requestedPointerType = iconId;
- mLocked.presentationChanged = true;
- updatePointerLocked();
- }
+ std::scoped_lock lock(mLock);
+ mCursorController.updatePointerIcon(iconId);
}
void PointerController::setCustomPointerIcon(const SpriteIcon& icon) {
- AutoMutex _l(mLock);
-
- const int32_t iconId = mPolicy->getCustomPointerIconId();
- mLocked.additionalMouseResources[iconId] = icon;
- mLocked.requestedPointerType = iconId;
- mLocked.presentationChanged = true;
-
- updatePointerLocked();
-}
-
-void PointerController::MessageHandler::handleMessage(const Message& message) {
- std::shared_ptr<PointerController> controller = pointerController.lock();
-
- if (controller == nullptr) {
- ALOGE("PointerController instance was released before processing message: what=%d",
- message.what);
- return;
- }
- switch (message.what) {
- case MSG_INACTIVITY_TIMEOUT:
- controller->doInactivityTimeout();
- break;
- }
-}
-
-int PointerController::LooperCallback::handleEvent(int /* fd */, int events, void* /* data */) {
- std::shared_ptr<PointerController> controller = pointerController.lock();
- if (controller == nullptr) {
- ALOGW("PointerController instance was released with pending callbacks. events=0x%x",
- events);
- return 0; // Remove the callback, the PointerController is gone anyways
- }
- if (events & (Looper::EVENT_ERROR | Looper::EVENT_HANGUP)) {
- ALOGE("Display event receiver pipe was closed or an error occurred. events=0x%x", events);
- return 0; // remove the callback
- }
-
- if (!(events & Looper::EVENT_INPUT)) {
- ALOGW("Received spurious callback for unhandled poll event. events=0x%x", events);
- return 1; // keep the callback
- }
-
- bool gotVsync = false;
- ssize_t n;
- nsecs_t timestamp;
- DisplayEventReceiver::Event buf[EVENT_BUFFER_SIZE];
- while ((n = controller->mDisplayEventReceiver.getEvents(buf, EVENT_BUFFER_SIZE)) > 0) {
- for (size_t i = 0; i < static_cast<size_t>(n); ++i) {
- if (buf[i].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) {
- timestamp = buf[i].header.timestamp;
- gotVsync = true;
- }
- }
- }
- if (gotVsync) {
- controller->doAnimate(timestamp);
- }
- return 1; // keep the callback
-}
-
-void PointerController::doAnimate(nsecs_t timestamp) {
- AutoMutex _l(mLock);
-
- mLocked.animationPending = false;
-
- bool keepFading = doFadingAnimationLocked(timestamp);
- bool keepBitmapFlipping = doBitmapAnimationLocked(timestamp);
- if (keepFading || keepBitmapFlipping) {
- startAnimationLocked();
- }
-}
-
-bool PointerController::doFadingAnimationLocked(nsecs_t timestamp) {
- bool keepAnimating = false;
- nsecs_t frameDelay = timestamp - mLocked.animationTime;
-
- // Animate pointer fade.
- if (mLocked.pointerFadeDirection < 0) {
- mLocked.pointerAlpha -= float(frameDelay) / POINTER_FADE_DURATION;
- if (mLocked.pointerAlpha <= 0.0f) {
- mLocked.pointerAlpha = 0.0f;
- mLocked.pointerFadeDirection = 0;
- } else {
- keepAnimating = true;
- }
- updatePointerLocked();
- } else if (mLocked.pointerFadeDirection > 0) {
- mLocked.pointerAlpha += float(frameDelay) / POINTER_FADE_DURATION;
- if (mLocked.pointerAlpha >= 1.0f) {
- mLocked.pointerAlpha = 1.0f;
- mLocked.pointerFadeDirection = 0;
- } else {
- keepAnimating = true;
- }
- updatePointerLocked();
- }
-
- // Animate spots that are fading out and being removed.
- for(auto it = mLocked.spotsByDisplay.begin(); it != mLocked.spotsByDisplay.end();) {
- std::vector<Spot*>& spots = it->second;
- size_t numSpots = spots.size();
- for (size_t i = 0; i < numSpots;) {
- Spot* spot = spots[i];
- if (spot->id == Spot::INVALID_ID) {
- spot->alpha -= float(frameDelay) / SPOT_FADE_DURATION;
- if (spot->alpha <= 0) {
- spots.erase(spots.begin() + i);
- releaseSpotLocked(spot);
- numSpots--;
- continue;
- } else {
- spot->sprite->setAlpha(spot->alpha);
- keepAnimating = true;
- }
- }
- ++i;
- }
-
- if (spots.size() == 0) {
- it = mLocked.spotsByDisplay.erase(it);
- } else {
- ++it;
- }
- }
-
- return keepAnimating;
-}
-
-bool PointerController::doBitmapAnimationLocked(nsecs_t timestamp) {
- std::map<int32_t, PointerAnimation>::const_iterator iter = mLocked.animationResources.find(
- mLocked.requestedPointerType);
- if (iter == mLocked.animationResources.end()) {
- return false;
- }
-
- if (timestamp - mLocked.lastFrameUpdatedTime > iter->second.durationPerFrame) {
- mSpriteController->openTransaction();
-
- int incr = (timestamp - mLocked.lastFrameUpdatedTime) / iter->second.durationPerFrame;
- mLocked.animationFrameIndex += incr;
- mLocked.lastFrameUpdatedTime += iter->second.durationPerFrame * incr;
- while (mLocked.animationFrameIndex >= iter->second.animationFrames.size()) {
- mLocked.animationFrameIndex -= iter->second.animationFrames.size();
- }
- mLocked.pointerSprite->setIcon(iter->second.animationFrames[mLocked.animationFrameIndex]);
-
- mSpriteController->closeTransaction();
- }
-
- // Keep animating.
- return true;
+ std::scoped_lock lock(mLock);
+ mCursorController.setCustomPointerIcon(icon);
}
void PointerController::doInactivityTimeout() {
fade(Transition::GRADUAL);
}
-void PointerController::startAnimationLocked() {
- if (!mLocked.animationPending) {
- mLocked.animationPending = true;
- mLocked.animationTime = systemTime(SYSTEM_TIME_MONOTONIC);
- mDisplayEventReceiver.requestNextVsync();
- }
-}
-
-void PointerController::resetInactivityTimeoutLocked() {
- mLooper->removeMessages(mHandler, MSG_INACTIVITY_TIMEOUT);
-
- nsecs_t timeout = mLocked.inactivityTimeout == InactivityTimeout::SHORT
- ? INACTIVITY_TIMEOUT_DELAY_TIME_SHORT
- : INACTIVITY_TIMEOUT_DELAY_TIME_NORMAL;
- mLooper->sendMessageDelayed(timeout, mHandler, MSG_INACTIVITY_TIMEOUT);
-}
-
-void PointerController::removeInactivityTimeoutLocked() {
- mLooper->removeMessages(mHandler, MSG_INACTIVITY_TIMEOUT);
-}
-
-void PointerController::updatePointerLocked() REQUIRES(mLock) {
- if (!mLocked.viewport.isValid()) {
- return;
- }
-
- mSpriteController->openTransaction();
-
- mLocked.pointerSprite->setLayer(Sprite::BASE_LAYER_POINTER);
- mLocked.pointerSprite->setPosition(mLocked.pointerX, mLocked.pointerY);
- mLocked.pointerSprite->setDisplayId(mLocked.viewport.displayId);
-
- if (mLocked.pointerAlpha > 0) {
- mLocked.pointerSprite->setAlpha(mLocked.pointerAlpha);
- mLocked.pointerSprite->setVisible(true);
- } else {
- mLocked.pointerSprite->setVisible(false);
+void PointerController::onDisplayViewportsUpdated(std::vector<DisplayViewport>& viewports) {
+ std::unordered_set<int32_t> displayIdSet;
+ for (DisplayViewport viewport : viewports) {
+ displayIdSet.insert(viewport.displayId);
}
- if (mLocked.pointerIconChanged || mLocked.presentationChanged) {
- if (mLocked.presentation == Presentation::POINTER) {
- if (mLocked.requestedPointerType == mPolicy->getDefaultPointerIconId()) {
- mLocked.pointerSprite->setIcon(mLocked.pointerIcon);
- } else {
- std::map<int32_t, SpriteIcon>::const_iterator iter =
- mLocked.additionalMouseResources.find(mLocked.requestedPointerType);
- if (iter != mLocked.additionalMouseResources.end()) {
- std::map<int32_t, PointerAnimation>::const_iterator anim_iter =
- mLocked.animationResources.find(mLocked.requestedPointerType);
- if (anim_iter != mLocked.animationResources.end()) {
- mLocked.animationFrameIndex = 0;
- mLocked.lastFrameUpdatedTime = systemTime(SYSTEM_TIME_MONOTONIC);
- startAnimationLocked();
- }
- mLocked.pointerSprite->setIcon(iter->second);
- } else {
- ALOGW("Can't find the resource for icon id %d", mLocked.requestedPointerType);
- mLocked.pointerSprite->setIcon(mLocked.pointerIcon);
- }
- }
+ std::scoped_lock lock(mLock);
+ for (auto it = mLocked.spotControllers.begin(); it != mLocked.spotControllers.end();) {
+ int32_t displayID = it->first;
+ if (!displayIdSet.count(displayID)) {
+ /*
+ * Ensures that an in-progress animation won't dereference
+ * a null pointer to TouchSpotController.
+ */
+ mContext.removeAnimationCallback(displayID);
+ it = mLocked.spotControllers.erase(it);
} else {
- mLocked.pointerSprite->setIcon(mResources.spotAnchor);
- }
- mLocked.pointerIconChanged = false;
- mLocked.presentationChanged = false;
- }
-
- mSpriteController->closeTransaction();
-}
-
-PointerController::Spot* PointerController::getSpot(uint32_t id, const std::vector<Spot*>& spots) {
- for (size_t i = 0; i < spots.size(); i++) {
- Spot* spot = spots[i];
- if (spot->id == id) {
- return spot;
- }
- }
-
- return nullptr;
-}
-
-PointerController::Spot* PointerController::createAndAddSpotLocked(uint32_t id,
- std::vector<Spot*>& spots) {
- // Remove spots until we have fewer than MAX_SPOTS remaining.
- while (spots.size() >= MAX_SPOTS) {
- Spot* spot = removeFirstFadingSpotLocked(spots);
- if (!spot) {
- spot = spots[0];
- spots.erase(spots.begin());
- }
- releaseSpotLocked(spot);
- }
-
- // Obtain a sprite from the recycled pool.
- sp<Sprite> sprite;
- if (! mLocked.recycledSprites.empty()) {
- sprite = mLocked.recycledSprites.back();
- mLocked.recycledSprites.pop_back();
- } else {
- sprite = mSpriteController->createSprite();
- }
-
- // Return the new spot.
- Spot* spot = new Spot(id, sprite);
- spots.push_back(spot);
- return spot;
-}
-
-PointerController::Spot* PointerController::removeFirstFadingSpotLocked(std::vector<Spot*>& spots) {
- for (size_t i = 0; i < spots.size(); i++) {
- Spot* spot = spots[i];
- if (spot->id == Spot::INVALID_ID) {
- spots.erase(spots.begin() + i);
- return spot;
- }
- }
- return nullptr;
-}
-
-void PointerController::releaseSpotLocked(Spot* spot) {
- spot->sprite->clearIcon();
-
- if (mLocked.recycledSprites.size() < MAX_RECYCLED_SPRITES) {
- mLocked.recycledSprites.push_back(spot->sprite);
- }
-
- delete spot;
-}
-
-void PointerController::fadeOutAndReleaseSpotLocked(Spot* spot) {
- if (spot->id != Spot::INVALID_ID) {
- spot->id = Spot::INVALID_ID;
- startAnimationLocked();
- }
-}
-
-void PointerController::fadeOutAndReleaseAllSpotsLocked() {
- for (auto& it : mLocked.spotsByDisplay) {
- const std::vector<Spot*>& spots = it.second;
- size_t numSpots = spots.size();
- for (size_t i = 0; i < numSpots; i++) {
- Spot* spot = spots[i];
- fadeOutAndReleaseSpotLocked(spot);
- }
- }
-}
-
-void PointerController::loadResourcesLocked() REQUIRES(mLock) {
- if (!mLocked.viewport.isValid()) {
- return;
- }
-
- mPolicy->loadPointerResources(&mResources, mLocked.viewport.displayId);
- mPolicy->loadPointerIcon(&mLocked.pointerIcon, mLocked.viewport.displayId);
-
- mLocked.additionalMouseResources.clear();
- mLocked.animationResources.clear();
- if (mLocked.presentation == Presentation::POINTER) {
- mPolicy->loadAdditionalMouseResources(&mLocked.additionalMouseResources,
- &mLocked.animationResources, mLocked.viewport.displayId);
- }
-
- mLocked.pointerIconChanged = true;
-}
-
-
-// --- PointerController::Spot ---
-
-void PointerController::Spot::updateSprite(const SpriteIcon* icon, float x, float y,
- int32_t displayId) {
- sprite->setLayer(Sprite::BASE_LAYER_SPOT + id);
- sprite->setAlpha(alpha);
- sprite->setTransformationMatrix(SpriteTransformationMatrix(scale, 0.0f, 0.0f, scale));
- sprite->setPosition(x, y);
- sprite->setDisplayId(displayId);
- this->x = x;
- this->y = y;
-
- if (icon != lastIcon) {
- lastIcon = icon;
- if (icon) {
- sprite->setIcon(*icon);
- sprite->setVisible(true);
- } else {
- sprite->setVisible(false);
+ ++it;
}
}
}
diff --git a/libs/input/PointerController.h b/libs/input/PointerController.h
index 14c0679654c6..827fcf1e1bc1 100644
--- a/libs/input/PointerController.h
+++ b/libs/input/PointerController.h
@@ -30,48 +30,14 @@
#include <memory>
#include <vector>
+#include "MouseCursorController.h"
+#include "PointerControllerContext.h"
#include "SpriteController.h"
+#include "TouchSpotController.h"
namespace android {
/*
- * Pointer resources.
- */
-struct PointerResources {
- SpriteIcon spotHover;
- SpriteIcon spotTouch;
- SpriteIcon spotAnchor;
-};
-
-struct PointerAnimation {
- std::vector<SpriteIcon> animationFrames;
- nsecs_t durationPerFrame;
-};
-
-/*
- * Pointer controller policy interface.
- *
- * The pointer controller policy is used by the pointer controller to interact with
- * the Window Manager and other system components.
- *
- * The actual implementation is partially supported by callbacks into the DVM
- * via JNI. This interface is also mocked in the unit tests.
- */
-class PointerControllerPolicyInterface : public virtual RefBase {
-protected:
- PointerControllerPolicyInterface() { }
- virtual ~PointerControllerPolicyInterface() { }
-
-public:
- virtual void loadPointerIcon(SpriteIcon* icon, int32_t displayId) = 0;
- virtual void loadPointerResources(PointerResources* outResources, int32_t displayId) = 0;
- virtual void loadAdditionalMouseResources(std::map<int32_t, SpriteIcon>* outResources,
- std::map<int32_t, PointerAnimation>* outAnimationResources, int32_t displayId) = 0;
- virtual int32_t getDefaultPointerIconId() = 0;
- virtual int32_t getCustomPointerIconId() = 0;
-};
-
-/*
* Tracks pointer movements and draws the pointer sprite to a surface.
*
* Handles pointer acceleration and animation.
@@ -81,15 +47,10 @@ public:
static std::shared_ptr<PointerController> create(
const sp<PointerControllerPolicyInterface>& policy, const sp<Looper>& looper,
const sp<SpriteController>& spriteController);
- enum class InactivityTimeout {
- NORMAL = 0,
- SHORT = 1,
- };
- virtual ~PointerController();
+ virtual ~PointerController() = default;
- virtual bool getBounds(float* outMinX, float* outMinY,
- float* outMaxX, float* outMaxY) const;
+ virtual bool getBounds(float* outMinX, float* outMinY, float* outMaxX, float* outMaxY) const;
virtual void move(float deltaX, float deltaY);
virtual void setButtonState(int32_t buttonState);
virtual int32_t getButtonState() const;
@@ -101,129 +62,36 @@ public:
virtual void setDisplayViewport(const DisplayViewport& viewport);
virtual void setPresentation(Presentation presentation);
- virtual void setSpots(const PointerCoords* spotCoords,
- const uint32_t* spotIdToIndex, BitSet32 spotIdBits, int32_t displayId);
+ virtual void setSpots(const PointerCoords* spotCoords, const uint32_t* spotIdToIndex,
+ BitSet32 spotIdBits, int32_t displayId);
virtual void clearSpots();
void updatePointerIcon(int32_t iconId);
void setCustomPointerIcon(const SpriteIcon& icon);
void setInactivityTimeout(InactivityTimeout inactivityTimeout);
+ void doInactivityTimeout();
void reloadPointerResources();
+ void onDisplayViewportsUpdated(std::vector<DisplayViewport>& viewports);
private:
- static constexpr size_t MAX_RECYCLED_SPRITES = 12;
- static constexpr size_t MAX_SPOTS = 12;
-
- enum {
- MSG_INACTIVITY_TIMEOUT,
- };
-
- struct Spot {
- static const uint32_t INVALID_ID = 0xffffffff;
-
- uint32_t id;
- sp<Sprite> sprite;
- float alpha;
- float scale;
- float x, y;
-
- inline Spot(uint32_t id, const sp<Sprite>& sprite)
- : id(id),
- sprite(sprite),
- alpha(1.0f),
- scale(1.0f),
- x(0.0f),
- y(0.0f),
- lastIcon(nullptr) {}
-
- void updateSprite(const SpriteIcon* icon, float x, float y, int32_t displayId);
+ friend PointerControllerContext::LooperCallback;
+ friend PointerControllerContext::MessageHandler;
- private:
- const SpriteIcon* lastIcon;
- };
+ mutable std::mutex mLock;
- class MessageHandler : public virtual android::MessageHandler {
- public:
- void handleMessage(const Message& message) override;
- std::weak_ptr<PointerController> pointerController;
- };
+ PointerControllerContext mContext;
- class LooperCallback : public virtual android::LooperCallback {
- public:
- int handleEvent(int fd, int events, void* data) override;
- std::weak_ptr<PointerController> pointerController;
- };
-
- mutable Mutex mLock;
-
- sp<PointerControllerPolicyInterface> mPolicy;
- sp<Looper> mLooper;
- sp<SpriteController> mSpriteController;
- sp<MessageHandler> mHandler;
- sp<LooperCallback> mCallback;
-
- DisplayEventReceiver mDisplayEventReceiver;
-
- PointerResources mResources;
+ MouseCursorController mCursorController;
struct Locked {
- bool animationPending;
- nsecs_t animationTime;
-
- size_t animationFrameIndex;
- nsecs_t lastFrameUpdatedTime;
-
- DisplayViewport viewport;
-
- InactivityTimeout inactivityTimeout;
-
Presentation presentation;
- bool presentationChanged;
-
- int32_t pointerFadeDirection;
- float pointerX;
- float pointerY;
- float pointerAlpha;
- sp<Sprite> pointerSprite;
- SpriteIcon pointerIcon;
- bool pointerIconChanged;
-
- std::map<int32_t, SpriteIcon> additionalMouseResources;
- std::map<int32_t, PointerAnimation> animationResources;
- int32_t requestedPointerType;
-
- int32_t buttonState;
-
- std::map<int32_t /* displayId */, std::vector<Spot*>> spotsByDisplay;
- std::vector<sp<Sprite>> recycledSprites;
+ std::unordered_map<int32_t /* displayId */, TouchSpotController> spotControllers;
} mLocked GUARDED_BY(mLock);
PointerController(const sp<PointerControllerPolicyInterface>& policy, const sp<Looper>& looper,
const sp<SpriteController>& spriteController);
-
- bool getBoundsLocked(float* outMinX, float* outMinY, float* outMaxX, float* outMaxY) const;
- void setPositionLocked(float x, float y);
-
- void doAnimate(nsecs_t timestamp);
- bool doFadingAnimationLocked(nsecs_t timestamp);
- bool doBitmapAnimationLocked(nsecs_t timestamp);
- void doInactivityTimeout();
-
- void startAnimationLocked();
-
- void resetInactivityTimeoutLocked();
- void removeInactivityTimeoutLocked();
- void updatePointerLocked();
-
- Spot* getSpot(uint32_t id, const std::vector<Spot*>& spots);
- Spot* createAndAddSpotLocked(uint32_t id, std::vector<Spot*>& spots);
- Spot* removeFirstFadingSpotLocked(std::vector<Spot*>& spots);
- void releaseSpotLocked(Spot* spot);
- void fadeOutAndReleaseSpotLocked(Spot* spot);
- void fadeOutAndReleaseAllSpotsLocked();
-
- void loadResourcesLocked();
+ void clearSpotsLocked();
};
} // namespace android
diff --git a/libs/input/PointerControllerContext.cpp b/libs/input/PointerControllerContext.cpp
new file mode 100644
index 000000000000..f30e8d8e33a5
--- /dev/null
+++ b/libs/input/PointerControllerContext.cpp
@@ -0,0 +1,228 @@
+/*
+ * Copyright (C) 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 "PointerControllerContext.h"
+#include "PointerController.h"
+
+namespace {
+// Time to wait before starting the fade when the pointer is inactive.
+const nsecs_t INACTIVITY_TIMEOUT_DELAY_TIME_NORMAL = 15 * 1000 * 1000000LL; // 15 seconds
+const nsecs_t INACTIVITY_TIMEOUT_DELAY_TIME_SHORT = 3 * 1000 * 1000000LL; // 3 seconds
+
+// The number of events to be read at once for DisplayEventReceiver.
+const int EVENT_BUFFER_SIZE = 100;
+} // namespace
+
+namespace android {
+
+// --- PointerControllerContext ---
+
+PointerControllerContext::PointerControllerContext(
+ const sp<PointerControllerPolicyInterface>& policy, const sp<Looper>& looper,
+ const sp<SpriteController>& spriteController, PointerController& controller)
+ : mPolicy(policy),
+ mLooper(looper),
+ mSpriteController(spriteController),
+ mHandler(new MessageHandler()),
+ mCallback(new LooperCallback()),
+ mController(controller),
+ mAnimator(*this) {
+ std::scoped_lock lock(mLock);
+ mLocked.inactivityTimeout = InactivityTimeout::NORMAL;
+}
+
+PointerControllerContext::~PointerControllerContext() {
+ mLooper->removeMessages(mHandler);
+}
+
+void PointerControllerContext::setInactivityTimeout(InactivityTimeout inactivityTimeout) {
+ std::scoped_lock lock(mLock);
+
+ if (mLocked.inactivityTimeout != inactivityTimeout) {
+ mLocked.inactivityTimeout = inactivityTimeout;
+ resetInactivityTimeoutLocked();
+ }
+}
+
+void PointerControllerContext::resetInactivityTimeout() {
+ std::scoped_lock lock(mLock);
+ resetInactivityTimeoutLocked();
+}
+
+void PointerControllerContext::resetInactivityTimeoutLocked() REQUIRES(mLock) {
+ mLooper->removeMessages(mHandler, MessageHandler::MSG_INACTIVITY_TIMEOUT);
+
+ nsecs_t timeout = mLocked.inactivityTimeout == InactivityTimeout::SHORT
+ ? INACTIVITY_TIMEOUT_DELAY_TIME_SHORT
+ : INACTIVITY_TIMEOUT_DELAY_TIME_NORMAL;
+ mLooper->sendMessageDelayed(timeout, mHandler, MessageHandler::MSG_INACTIVITY_TIMEOUT);
+}
+
+void PointerControllerContext::removeInactivityTimeout() {
+ std::scoped_lock lock(mLock);
+ mLooper->removeMessages(mHandler, MessageHandler::MSG_INACTIVITY_TIMEOUT);
+}
+
+nsecs_t PointerControllerContext::getAnimationTime() REQUIRES(mAnimator.mLock) {
+ return mAnimator.getAnimationTimeLocked();
+}
+
+void PointerControllerContext::setHandlerController(std::shared_ptr<PointerController> controller) {
+ mHandler->pointerController = controller;
+}
+
+void PointerControllerContext::setCallbackController(
+ std::shared_ptr<PointerController> controller) {
+ mCallback->pointerController = controller;
+}
+
+sp<PointerControllerPolicyInterface> PointerControllerContext::getPolicy() {
+ return mPolicy;
+}
+
+sp<SpriteController> PointerControllerContext::getSpriteController() {
+ return mSpriteController;
+}
+
+void PointerControllerContext::handleDisplayEvents() {
+ mAnimator.handleVsyncEvents();
+}
+
+void PointerControllerContext::MessageHandler::handleMessage(const Message& message) {
+ std::shared_ptr<PointerController> controller = pointerController.lock();
+
+ if (controller == nullptr) {
+ ALOGE("PointerController instance was released before processing message: what=%d",
+ message.what);
+ return;
+ }
+ switch (message.what) {
+ case MSG_INACTIVITY_TIMEOUT:
+ controller->doInactivityTimeout();
+ break;
+ }
+}
+
+int PointerControllerContext::LooperCallback::handleEvent(int /* fd */, int events,
+ void* /* data */) {
+ std::shared_ptr<PointerController> controller = pointerController.lock();
+ if (controller == nullptr) {
+ ALOGW("PointerController instance was released with pending callbacks. events=0x%x",
+ events);
+ return 0; // Remove the callback, the PointerController is gone anyways
+ }
+ if (events & (Looper::EVENT_ERROR | Looper::EVENT_HANGUP)) {
+ ALOGE("Display event receiver pipe was closed or an error occurred. events=0x%x", events);
+ return 0; // remove the callback
+ }
+
+ if (!(events & Looper::EVENT_INPUT)) {
+ ALOGW("Received spurious callback for unhandled poll event. events=0x%x", events);
+ return 1; // keep the callback
+ }
+
+ controller->mContext.handleDisplayEvents();
+ return 1; // keep the callback
+}
+
+void PointerControllerContext::addAnimationCallback(int32_t displayId,
+ std::function<bool(nsecs_t)> callback) {
+ mAnimator.addCallback(displayId, callback);
+}
+
+void PointerControllerContext::removeAnimationCallback(int32_t displayId) {
+ mAnimator.removeCallback(displayId);
+}
+
+PointerControllerContext::PointerAnimator::PointerAnimator(PointerControllerContext& context)
+ : mContext(context) {
+ initializeDisplayEventReceiver();
+}
+
+void PointerControllerContext::PointerAnimator::initializeDisplayEventReceiver() {
+ if (mDisplayEventReceiver.initCheck() == NO_ERROR) {
+ mContext.mLooper->addFd(mDisplayEventReceiver.getFd(), Looper::POLL_CALLBACK,
+ Looper::EVENT_INPUT, mContext.mCallback, nullptr);
+ } else {
+ ALOGE("Failed to initialize DisplayEventReceiver.");
+ }
+}
+
+void PointerControllerContext::PointerAnimator::addCallback(int32_t displayId,
+ std::function<bool(nsecs_t)> callback) {
+ std::scoped_lock lock(mLock);
+ mLocked.callbacks[displayId] = callback;
+ startAnimationLocked();
+}
+
+void PointerControllerContext::PointerAnimator::removeCallback(int32_t displayId) {
+ std::scoped_lock lock(mLock);
+ auto it = mLocked.callbacks.find(displayId);
+ if (it == mLocked.callbacks.end()) {
+ return;
+ }
+ mLocked.callbacks.erase(it);
+}
+
+void PointerControllerContext::PointerAnimator::handleVsyncEvents() {
+ bool gotVsync = false;
+ ssize_t n;
+ nsecs_t timestamp;
+ DisplayEventReceiver::Event buf[EVENT_BUFFER_SIZE];
+ while ((n = mDisplayEventReceiver.getEvents(buf, EVENT_BUFFER_SIZE)) > 0) {
+ for (size_t i = 0; i < static_cast<size_t>(n); ++i) {
+ if (buf[i].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) {
+ timestamp = buf[i].header.timestamp;
+ gotVsync = true;
+ }
+ }
+ }
+ if (gotVsync) {
+ std::scoped_lock lock(mLock);
+ mLocked.animationPending = false;
+ handleCallbacksLocked(timestamp);
+ }
+}
+
+nsecs_t PointerControllerContext::PointerAnimator::getAnimationTimeLocked() REQUIRES(mLock) {
+ return mLocked.animationTime;
+}
+
+void PointerControllerContext::PointerAnimator::startAnimationLocked() REQUIRES(mLock) {
+ if (!mLocked.animationPending) {
+ mLocked.animationPending = true;
+ mLocked.animationTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ mDisplayEventReceiver.requestNextVsync();
+ }
+}
+
+void PointerControllerContext::PointerAnimator::handleCallbacksLocked(nsecs_t timestamp)
+ REQUIRES(mLock) {
+ for (auto it = mLocked.callbacks.begin(); it != mLocked.callbacks.end();) {
+ bool keepCallback = it->second(timestamp);
+ if (!keepCallback) {
+ it = mLocked.callbacks.erase(it);
+ } else {
+ ++it;
+ }
+ }
+
+ if (!mLocked.callbacks.empty()) {
+ startAnimationLocked();
+ }
+}
+
+} // namespace android
diff --git a/libs/input/PointerControllerContext.h b/libs/input/PointerControllerContext.h
new file mode 100644
index 000000000000..98073fea323e
--- /dev/null
+++ b/libs/input/PointerControllerContext.h
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef _UI_POINTER_CONTROLLER_CONTEXT_H
+#define _UI_POINTER_CONTROLLER_CONTEXT_H
+
+#include <PointerControllerInterface.h>
+#include <gui/DisplayEventReceiver.h>
+#include <input/DisplayViewport.h>
+#include <input/Input.h>
+#include <ui/DisplayInfo.h>
+#include <utils/BitSet.h>
+#include <utils/Looper.h>
+#include <utils/RefBase.h>
+
+#include <functional>
+#include <map>
+#include <memory>
+#include <vector>
+
+#include "SpriteController.h"
+
+namespace android {
+
+class PointerController;
+class MouseCursorController;
+class TouchSpotController;
+
+/*
+ * Pointer resources.
+ */
+struct PointerResources {
+ SpriteIcon spotHover;
+ SpriteIcon spotTouch;
+ SpriteIcon spotAnchor;
+};
+
+struct PointerAnimation {
+ std::vector<SpriteIcon> animationFrames;
+ nsecs_t durationPerFrame;
+};
+
+enum class InactivityTimeout {
+ NORMAL = 0,
+ SHORT = 1,
+};
+
+/*
+ * Pointer controller policy interface.
+ *
+ * The pointer controller policy is used by the pointer controller to interact with
+ * the Window Manager and other system components.
+ *
+ * The actual implementation is partially supported by callbacks into the DVM
+ * via JNI. This interface is also mocked in the unit tests.
+ */
+class PointerControllerPolicyInterface : public virtual RefBase {
+protected:
+ PointerControllerPolicyInterface() {}
+ virtual ~PointerControllerPolicyInterface() {}
+
+public:
+ virtual void loadPointerIcon(SpriteIcon* icon, int32_t displayId) = 0;
+ virtual void loadPointerResources(PointerResources* outResources, int32_t displayId) = 0;
+ virtual void loadAdditionalMouseResources(
+ std::map<int32_t, SpriteIcon>* outResources,
+ std::map<int32_t, PointerAnimation>* outAnimationResources, int32_t displayId) = 0;
+ virtual int32_t getDefaultPointerIconId() = 0;
+ virtual int32_t getCustomPointerIconId() = 0;
+};
+
+/*
+ * Contains logic and resources shared among PointerController,
+ * MouseCursorController, and TouchSpotController.
+ */
+
+class PointerControllerContext {
+public:
+ PointerControllerContext(const sp<PointerControllerPolicyInterface>& policy,
+ const sp<Looper>& looper, const sp<SpriteController>& spriteController,
+ PointerController& controller);
+ ~PointerControllerContext();
+
+ void removeInactivityTimeout();
+ void resetInactivityTimeout();
+ void startAnimation();
+ void setInactivityTimeout(InactivityTimeout inactivityTimeout);
+
+ nsecs_t getAnimationTime();
+
+ void clearSpotsByDisplay(int32_t displayId);
+
+ void setHandlerController(std::shared_ptr<PointerController> controller);
+ void setCallbackController(std::shared_ptr<PointerController> controller);
+
+ sp<PointerControllerPolicyInterface> getPolicy();
+ sp<SpriteController> getSpriteController();
+
+ void handleDisplayEvents();
+
+ void addAnimationCallback(int32_t displayId, std::function<bool(nsecs_t)> callback);
+ void removeAnimationCallback(int32_t displayId);
+
+ class MessageHandler : public virtual android::MessageHandler {
+ public:
+ enum {
+ MSG_INACTIVITY_TIMEOUT,
+ };
+
+ void handleMessage(const Message& message) override;
+ std::weak_ptr<PointerController> pointerController;
+ };
+
+ class LooperCallback : public virtual android::LooperCallback {
+ public:
+ int handleEvent(int fd, int events, void* data) override;
+ std::weak_ptr<PointerController> pointerController;
+ };
+
+private:
+ class PointerAnimator {
+ public:
+ PointerAnimator(PointerControllerContext& context);
+
+ void addCallback(int32_t displayId, std::function<bool(nsecs_t)> callback);
+ void removeCallback(int32_t displayId);
+ void handleVsyncEvents();
+ nsecs_t getAnimationTimeLocked();
+
+ mutable std::mutex mLock;
+
+ private:
+ struct Locked {
+ bool animationPending{false};
+ nsecs_t animationTime{systemTime(SYSTEM_TIME_MONOTONIC)};
+
+ std::unordered_map<int32_t, std::function<bool(nsecs_t)>> callbacks;
+ } mLocked GUARDED_BY(mLock);
+
+ DisplayEventReceiver mDisplayEventReceiver;
+
+ PointerControllerContext& mContext;
+
+ void initializeDisplayEventReceiver();
+ void startAnimationLocked();
+ void handleCallbacksLocked(nsecs_t timestamp);
+ };
+
+ sp<PointerControllerPolicyInterface> mPolicy;
+ sp<Looper> mLooper;
+ sp<SpriteController> mSpriteController;
+ sp<MessageHandler> mHandler;
+ sp<LooperCallback> mCallback;
+
+ PointerController& mController;
+
+ PointerAnimator mAnimator;
+
+ mutable std::mutex mLock;
+
+ struct Locked {
+ InactivityTimeout inactivityTimeout;
+ } mLocked GUARDED_BY(mLock);
+
+ void resetInactivityTimeoutLocked();
+};
+
+} // namespace android
+
+#endif // _UI_POINTER_CONTROLLER_CONTEXT_H
diff --git a/libs/input/TouchSpotController.cpp b/libs/input/TouchSpotController.cpp
new file mode 100644
index 000000000000..f7c685ff8ba6
--- /dev/null
+++ b/libs/input/TouchSpotController.cpp
@@ -0,0 +1,264 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#define LOG_TAG "TouchSpotController"
+
+// Log debug messages about pointer updates
+#define DEBUG_SPOT_UPDATES 0
+
+#include "TouchSpotController.h"
+
+#include <log/log.h>
+
+#include <SkBitmap.h>
+#include <SkBlendMode.h>
+#include <SkCanvas.h>
+#include <SkColor.h>
+#include <SkPaint.h>
+
+namespace {
+// Time to spend fading out the spot completely.
+const nsecs_t SPOT_FADE_DURATION = 200 * 1000000LL; // 200 ms
+} // namespace
+
+namespace android {
+
+// --- Spot ---
+
+void TouchSpotController::Spot::updateSprite(const SpriteIcon* icon, float x, float y,
+ int32_t displayId) {
+ sprite->setLayer(Sprite::BASE_LAYER_SPOT + id);
+ sprite->setAlpha(alpha);
+ sprite->setTransformationMatrix(SpriteTransformationMatrix(scale, 0.0f, 0.0f, scale));
+ sprite->setPosition(x, y);
+ sprite->setDisplayId(displayId);
+ this->x = x;
+ this->y = y;
+
+ if (icon != mLastIcon) {
+ mLastIcon = icon;
+ if (icon) {
+ sprite->setIcon(*icon);
+ sprite->setVisible(true);
+ } else {
+ sprite->setVisible(false);
+ }
+ }
+}
+
+// --- TouchSpotController ---
+
+TouchSpotController::TouchSpotController(int32_t displayId, PointerControllerContext& context)
+ : mDisplayId(displayId), mContext(context) {
+ mContext.getPolicy()->loadPointerResources(&mResources, mDisplayId);
+}
+
+TouchSpotController::~TouchSpotController() {
+ std::scoped_lock lock(mLock);
+
+ size_t numSpots = mLocked.displaySpots.size();
+ for (size_t i = 0; i < numSpots; i++) {
+ delete mLocked.displaySpots[i];
+ }
+ mLocked.displaySpots.clear();
+}
+
+void TouchSpotController::setSpots(const PointerCoords* spotCoords, const uint32_t* spotIdToIndex,
+ BitSet32 spotIdBits) {
+#if DEBUG_SPOT_UPDATES
+ ALOGD("setSpots: idBits=%08x", spotIdBits.value);
+ for (BitSet32 idBits(spotIdBits); !idBits.isEmpty();) {
+ uint32_t id = idBits.firstMarkedBit();
+ idBits.clearBit(id);
+ const PointerCoords& c = spotCoords[spotIdToIndex[id]];
+ ALOGD(" spot %d: position=(%0.3f, %0.3f), pressure=%0.3f, displayId=%" PRId32 ".", id,
+ c.getAxisValue(AMOTION_EVENT_AXIS_X), c.getAxisValue(AMOTION_EVENT_AXIS_Y),
+ c.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE), displayId);
+ }
+#endif
+
+ std::scoped_lock lock(mLock);
+ sp<SpriteController> spriteController = mContext.getSpriteController();
+ spriteController->openTransaction();
+
+ // Add or move spots for fingers that are down.
+ for (BitSet32 idBits(spotIdBits); !idBits.isEmpty();) {
+ uint32_t id = idBits.clearFirstMarkedBit();
+ const PointerCoords& c = spotCoords[spotIdToIndex[id]];
+ const SpriteIcon& icon = c.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE) > 0
+ ? mResources.spotTouch
+ : mResources.spotHover;
+ float x = c.getAxisValue(AMOTION_EVENT_AXIS_X);
+ float y = c.getAxisValue(AMOTION_EVENT_AXIS_Y);
+
+ Spot* spot = getSpot(id, mLocked.displaySpots);
+ if (!spot) {
+ spot = createAndAddSpotLocked(id, mLocked.displaySpots);
+ }
+
+ spot->updateSprite(&icon, x, y, mDisplayId);
+ }
+
+ for (Spot* spot : mLocked.displaySpots) {
+ if (spot->id != Spot::INVALID_ID && !spotIdBits.hasBit(spot->id)) {
+ fadeOutAndReleaseSpotLocked(spot);
+ }
+ }
+
+ spriteController->closeTransaction();
+}
+
+void TouchSpotController::clearSpots() {
+#if DEBUG_SPOT_UPDATES
+ ALOGD("clearSpots");
+#endif
+
+ std::scoped_lock lock(mLock);
+ fadeOutAndReleaseAllSpotsLocked();
+}
+
+TouchSpotController::Spot* TouchSpotController::getSpot(uint32_t id,
+ const std::vector<Spot*>& spots) {
+ for (size_t i = 0; i < spots.size(); i++) {
+ Spot* spot = spots[i];
+ if (spot->id == id) {
+ return spot;
+ }
+ }
+ return nullptr;
+}
+
+TouchSpotController::Spot* TouchSpotController::createAndAddSpotLocked(uint32_t id,
+ std::vector<Spot*>& spots)
+ REQUIRES(mLock) {
+ // Remove spots until we have fewer than MAX_SPOTS remaining.
+ while (spots.size() >= MAX_SPOTS) {
+ Spot* spot = removeFirstFadingSpotLocked(spots);
+ if (!spot) {
+ spot = spots[0];
+ spots.erase(spots.begin());
+ }
+ releaseSpotLocked(spot);
+ }
+
+ // Obtain a sprite from the recycled pool.
+ sp<Sprite> sprite;
+ if (!mLocked.recycledSprites.empty()) {
+ sprite = mLocked.recycledSprites.back();
+ mLocked.recycledSprites.pop_back();
+ } else {
+ sprite = mContext.getSpriteController()->createSprite();
+ }
+
+ // Return the new spot.
+ Spot* spot = new Spot(id, sprite);
+ spots.push_back(spot);
+ return spot;
+}
+
+TouchSpotController::Spot* TouchSpotController::removeFirstFadingSpotLocked(
+ std::vector<Spot*>& spots) REQUIRES(mLock) {
+ for (size_t i = 0; i < spots.size(); i++) {
+ Spot* spot = spots[i];
+ if (spot->id == Spot::INVALID_ID) {
+ spots.erase(spots.begin() + i);
+ return spot;
+ }
+ }
+ return NULL;
+}
+
+void TouchSpotController::releaseSpotLocked(Spot* spot) REQUIRES(mLock) {
+ spot->sprite->clearIcon();
+
+ if (mLocked.recycledSprites.size() < MAX_RECYCLED_SPRITES) {
+ mLocked.recycledSprites.push_back(spot->sprite);
+ }
+ delete spot;
+}
+
+void TouchSpotController::fadeOutAndReleaseSpotLocked(Spot* spot) REQUIRES(mLock) {
+ if (spot->id != Spot::INVALID_ID) {
+ spot->id = Spot::INVALID_ID;
+ startAnimationLocked();
+ }
+}
+
+void TouchSpotController::fadeOutAndReleaseAllSpotsLocked() REQUIRES(mLock) {
+ size_t numSpots = mLocked.displaySpots.size();
+ for (size_t i = 0; i < numSpots; i++) {
+ Spot* spot = mLocked.displaySpots[i];
+ fadeOutAndReleaseSpotLocked(spot);
+ }
+}
+
+void TouchSpotController::reloadSpotResources() {
+ mContext.getPolicy()->loadPointerResources(&mResources, mDisplayId);
+}
+
+bool TouchSpotController::doAnimations(nsecs_t timestamp) {
+ std::scoped_lock lock(mLock);
+ bool keepAnimating = doFadingAnimationLocked(timestamp);
+ if (!keepAnimating) {
+ /*
+ * We know that this callback will be removed before another
+ * is added. mLock in PointerAnimator will not be released
+ * until after this is removed, and adding another callback
+ * requires that lock. Thus it's safe to set mLocked.animating
+ * here.
+ */
+ mLocked.animating = false;
+ }
+ return keepAnimating;
+}
+
+bool TouchSpotController::doFadingAnimationLocked(nsecs_t timestamp) REQUIRES(mLock) {
+ bool keepAnimating = false;
+ nsecs_t animationTime = mContext.getAnimationTime();
+ nsecs_t frameDelay = timestamp - animationTime;
+ size_t numSpots = mLocked.displaySpots.size();
+ for (size_t i = 0; i < numSpots;) {
+ Spot* spot = mLocked.displaySpots[i];
+ if (spot->id == Spot::INVALID_ID) {
+ spot->alpha -= float(frameDelay) / SPOT_FADE_DURATION;
+ if (spot->alpha <= 0) {
+ mLocked.displaySpots.erase(mLocked.displaySpots.begin() + i);
+ releaseSpotLocked(spot);
+ numSpots--;
+ continue;
+ } else {
+ spot->sprite->setAlpha(spot->alpha);
+ keepAnimating = true;
+ }
+ }
+ ++i;
+ }
+ return keepAnimating;
+}
+
+void TouchSpotController::startAnimationLocked() REQUIRES(mLock) {
+ using namespace std::placeholders;
+
+ if (mLocked.animating) {
+ return;
+ }
+ mLocked.animating = true;
+
+ std::function<bool(nsecs_t)> func = std::bind(&TouchSpotController::doAnimations, this, _1);
+ mContext.addAnimationCallback(mDisplayId, func);
+}
+
+} // namespace android
diff --git a/libs/input/TouchSpotController.h b/libs/input/TouchSpotController.h
new file mode 100644
index 000000000000..703de3603f48
--- /dev/null
+++ b/libs/input/TouchSpotController.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef _UI_TOUCH_SPOT_CONTROLLER_H
+#define _UI_TOUCH_SPOT_CONTROLLER_H
+
+#include <functional>
+
+#include "PointerControllerContext.h"
+
+namespace android {
+
+/*
+ * Helper class for PointerController that specifically handles
+ * touch spot resources and actions for a single display.
+ */
+class TouchSpotController {
+public:
+ TouchSpotController(int32_t displayId, PointerControllerContext& context);
+ ~TouchSpotController();
+ void setSpots(const PointerCoords* spotCoords, const uint32_t* spotIdToIndex,
+ BitSet32 spotIdBits);
+ void clearSpots();
+
+ void reloadSpotResources();
+ bool doAnimations(nsecs_t timestamp);
+
+private:
+ struct Spot {
+ static const uint32_t INVALID_ID = 0xffffffff;
+
+ uint32_t id;
+ sp<Sprite> sprite;
+ float alpha;
+ float scale;
+ float x, y;
+
+ inline Spot(uint32_t id, const sp<Sprite>& sprite)
+ : id(id),
+ sprite(sprite),
+ alpha(1.0f),
+ scale(1.0f),
+ x(0.0f),
+ y(0.0f),
+ mLastIcon(nullptr) {}
+
+ void updateSprite(const SpriteIcon* icon, float x, float y, int32_t displayId);
+
+ private:
+ const SpriteIcon* mLastIcon;
+ };
+
+ int32_t mDisplayId;
+
+ mutable std::mutex mLock;
+
+ PointerResources mResources;
+
+ PointerControllerContext& mContext;
+
+ static constexpr size_t MAX_RECYCLED_SPRITES = 12;
+ static constexpr size_t MAX_SPOTS = 12;
+
+ struct Locked {
+ std::vector<Spot*> displaySpots;
+ std::vector<sp<Sprite>> recycledSprites;
+
+ bool animating{false};
+
+ } mLocked GUARDED_BY(mLock);
+
+ Spot* getSpot(uint32_t id, const std::vector<Spot*>& spots);
+ Spot* createAndAddSpotLocked(uint32_t id, std::vector<Spot*>& spots);
+ Spot* removeFirstFadingSpotLocked(std::vector<Spot*>& spots);
+ void releaseSpotLocked(Spot* spot);
+ void fadeOutAndReleaseSpotLocked(Spot* spot);
+ void fadeOutAndReleaseAllSpotsLocked();
+ bool doFadingAnimationLocked(nsecs_t timestamp);
+ void startAnimationLocked();
+};
+
+} // namespace android
+
+#endif // _UI_TOUCH_SPOT_CONTROLLER_H
diff --git a/libs/input/tests/PointerController_test.cpp b/libs/input/tests/PointerController_test.cpp
index 6e129a064385..b67088a389b6 100644
--- a/libs/input/tests/PointerController_test.cpp
+++ b/libs/input/tests/PointerController_test.cpp
@@ -178,9 +178,6 @@ void PointerControllerTest::ensureDisplayViewportIsSet() {
viewport.deviceWidth = 400;
viewport.deviceHeight = 300;
mPointerController->setDisplayViewport(viewport);
-
- // The first call to setDisplayViewport should trigger the loading of the necessary resources.
- EXPECT_TRUE(mPolicy->allResourcesAreLoaded());
}
void PointerControllerTest::loopThread() {
@@ -208,6 +205,7 @@ TEST_F(PointerControllerTest, useDefaultCursorTypeByDefault) {
TEST_F(PointerControllerTest, updatePointerIcon) {
ensureDisplayViewportIsSet();
+ mPointerController->setPresentation(PointerController::Presentation::POINTER);
mPointerController->unfade(PointerController::Transition::IMMEDIATE);
int32_t type = CURSOR_TYPE_ADDITIONAL;
@@ -247,8 +245,6 @@ TEST_F(PointerControllerTest, setCustomPointerIcon) {
TEST_F(PointerControllerTest, doesNotGetResourcesBeforeSettingViewport) {
mPointerController->setPresentation(PointerController::Presentation::POINTER);
- mPointerController->setSpots(nullptr, nullptr, BitSet32(), -1);
- mPointerController->clearSpots();
mPointerController->setPosition(1.0f, 1.0f);
mPointerController->move(1.0f, 1.0f);
mPointerController->unfade(PointerController::Transition::IMMEDIATE);