Merge changes from topics "cursor_type_hotspot", "set_viewport_in_input_reader"

* changes:
  PointerController: Add guards to ensure display is valid
  Move setDisplayViewport to InputReader.
  Stop loading animation for addtional cursor type.
  Add cursor type and hotspot to surface metadata.
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index b2aef78..48a764e 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -483,11 +483,8 @@
 
     auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
 
-    std::vector<uint8_t> byteData(parcel->dataSize());
-    memcpy(byteData.data(), parcel->data(), parcel->dataSize());
-
     SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl*>(nativeObject);
-    transaction->setMetadata(ctrl, id, std::move(byteData));
+    transaction->setMetadata(ctrl, id, *parcel);
 }
 
 static void nativeSetColor(JNIEnv* env, jclass clazz, jlong transactionObj,
diff --git a/libs/input/Android.bp b/libs/input/Android.bp
index 89d3cc4..16f2917 100644
--- a/libs/input/Android.bp
+++ b/libs/input/Android.bp
@@ -20,6 +20,7 @@
     ],
 
     shared_libs: [
+        "libbinder",
         "libcutils",
         "liblog",
         "libutils",
diff --git a/libs/input/PointerController.cpp b/libs/input/PointerController.cpp
index abf0837..5c2ef15 100644
--- a/libs/input/PointerController.cpp
+++ b/libs/input/PointerController.cpp
@@ -257,19 +257,24 @@
 void PointerController::setPresentation(Presentation presentation) {
     AutoMutex _l(mLock);
 
-    if (presentation == PRESENTATION_POINTER && mLocked.additionalMouseResources.empty()) {
-        mPolicy->loadAdditionalMouseResources(&mLocked.additionalMouseResources,
-                &mLocked.animationResources, mLocked.viewport.displayId);
+    if (mLocked.presentation == presentation) {
+        return;
     }
 
-    if (mLocked.presentation != presentation) {
-        mLocked.presentation = presentation;
-        mLocked.presentationChanged = true;
+    mLocked.presentation = presentation;
+    mLocked.presentationChanged = true;
 
-        if (presentation != PRESENTATION_SPOT) {
-            fadeOutAndReleaseAllSpotsLocked();
+    if (!mLocked.viewport.isValid()) {
+        return;
+    }
+
+    if (presentation == PRESENTATION_POINTER) {
+        if (mLocked.additionalMouseResources.empty()) {
+            mPolicy->loadAdditionalMouseResources(&mLocked.additionalMouseResources,
+                                                  &mLocked.animationResources,
+                                                  mLocked.viewport.displayId);
         }
-
+        fadeOutAndReleaseAllSpotsLocked();
         updatePointerLocked();
     }
 }
@@ -291,6 +296,9 @@
 #endif
 
     AutoMutex _l(mLock);
+    if (!mLocked.viewport.isValid()) {
+        return;
+    }
 
     std::vector<Spot*> newSpots;
     std::map<int32_t, std::vector<Spot*>>::const_iterator iter =
@@ -337,6 +345,9 @@
 #endif
 
     AutoMutex _l(mLock);
+    if (!mLocked.viewport.isValid()) {
+        return;
+    }
 
     fadeOutAndReleaseAllSpotsLocked();
 }
@@ -758,6 +769,10 @@
 }
 
 void PointerController::loadResourcesLocked() REQUIRES(mLock) {
+    if (!mLocked.viewport.isValid()) {
+        return;
+    }
+
     mPolicy->loadPointerResources(&mResources, mLocked.viewport.displayId);
     mPolicy->loadPointerIcon(&mLocked.pointerIcon, mLocked.viewport.displayId);
 
diff --git a/libs/input/PointerController.h b/libs/input/PointerController.h
index 52305b8..ebc622b 100644
--- a/libs/input/PointerController.h
+++ b/libs/input/PointerController.h
@@ -100,6 +100,7 @@
     virtual int32_t getDisplayId() const;
     virtual void fade(Transition transition);
     virtual void unfade(Transition transition);
+    virtual void setDisplayViewport(const DisplayViewport& viewport);
 
     virtual void setPresentation(Presentation presentation);
     virtual void setSpots(const PointerCoords* spotCoords,
@@ -108,7 +109,6 @@
 
     void updatePointerIcon(int32_t iconId);
     void setCustomPointerIcon(const SpriteIcon& icon);
-    void setDisplayViewport(const DisplayViewport& viewport);
     void setInactivityTimeout(InactivityTimeout inactivityTimeout);
     void reloadPointerResources();
 
diff --git a/libs/input/SpriteController.cpp b/libs/input/SpriteController.cpp
index c1868d3..fd386e9 100644
--- a/libs/input/SpriteController.cpp
+++ b/libs/input/SpriteController.cpp
@@ -245,7 +245,8 @@
         if (update.state.surfaceControl != NULL && (becomingVisible || becomingHidden
                 || (wantSurfaceVisibleAndDrawn && (update.state.dirty & (DIRTY_ALPHA
                         | DIRTY_POSITION | DIRTY_TRANSFORMATION_MATRIX | DIRTY_LAYER
-                        | DIRTY_VISIBILITY | DIRTY_HOTSPOT | DIRTY_DISPLAY_ID))))) {
+                        | DIRTY_VISIBILITY | DIRTY_HOTSPOT | DIRTY_DISPLAY_ID
+                        | DIRTY_ICON_STYLE))))) {
             needApplyTransaction = true;
 
             if (wantSurfaceVisibleAndDrawn
@@ -274,6 +275,21 @@
                         update.state.transformationMatrix.dtdy);
             }
 
+            if (wantSurfaceVisibleAndDrawn
+                    && (becomingVisible
+                            || (update.state.dirty & (DIRTY_HOTSPOT | DIRTY_ICON_STYLE)))) {
+                Parcel p;
+                p.writeInt32(update.state.icon.style);
+                p.writeFloat(update.state.icon.hotSpotX);
+                p.writeFloat(update.state.icon.hotSpotY);
+
+                // Pass cursor metadata in the sprite surface so that when Android is running as a
+                // client OS (e.g. ARC++) the host OS can get the requested cursor metadata and
+                // update mouse cursor in the host OS.
+                t.setMetadata(
+                        update.state.surfaceControl, METADATA_MOUSE_CURSOR, p);
+            }
+
             int32_t surfaceLayer = mOverlayLayer + update.state.layer;
             if (wantSurfaceVisibleAndDrawn
                     && (becomingVisible || (update.state.dirty & DIRTY_LAYER))) {
@@ -397,9 +413,14 @@
         } else {
             dirty = DIRTY_BITMAP;
         }
+
+        if (mLocked.state.icon.style != icon.style) {
+            mLocked.state.icon.style = icon.style;
+            dirty |= DIRTY_ICON_STYLE;
+        }
     } else if (mLocked.state.icon.isValid()) {
         mLocked.state.icon.bitmap.reset();
-        dirty = DIRTY_BITMAP | DIRTY_HOTSPOT;
+        dirty = DIRTY_BITMAP | DIRTY_HOTSPOT | DIRTY_ICON_STYLE;
     } else {
         return; // setting to invalid icon and already invalid so nothing to do
     }
diff --git a/libs/input/SpriteController.h b/libs/input/SpriteController.h
index 5b216f5..79a904f 100644
--- a/libs/input/SpriteController.h
+++ b/libs/input/SpriteController.h
@@ -55,11 +55,12 @@
  * Icon that a sprite displays, including its hotspot.
  */
 struct SpriteIcon {
-    inline SpriteIcon() : hotSpotX(0), hotSpotY(0) { }
-    inline SpriteIcon(const SkBitmap& bitmap, float hotSpotX, float hotSpotY) :
-            bitmap(bitmap), hotSpotX(hotSpotX), hotSpotY(hotSpotY) { }
+    inline SpriteIcon() : style(0), hotSpotX(0), hotSpotY(0) { }
+    inline SpriteIcon(const SkBitmap& bitmap, int32_t style, float hotSpotX, float hotSpotY) :
+            bitmap(bitmap), style(style), hotSpotX(hotSpotX), hotSpotY(hotSpotY) { }
 
     SkBitmap bitmap;
+    int32_t style;
     float hotSpotX;
     float hotSpotY;
 
@@ -69,11 +70,12 @@
             bitmap.readPixels(bitmapCopy.info(), bitmapCopy.getPixels(), bitmapCopy.rowBytes(),
                     0, 0);
         }
-        return SpriteIcon(bitmapCopy, hotSpotX, hotSpotY);
+        return SpriteIcon(bitmapCopy, style, hotSpotX, hotSpotY);
     }
 
     inline void reset() {
         bitmap.reset();
+        style = 0;
         hotSpotX = 0;
         hotSpotY = 0;
     }
@@ -149,15 +151,15 @@
     SpriteController(const sp<Looper>& looper, int32_t overlayLayer);
 
     /* Creates a new sprite, initially invisible. */
-    sp<Sprite> createSprite();
+    virtual sp<Sprite> createSprite();
 
     /* Opens or closes a transaction to perform a batch of sprite updates as part of
      * a single operation such as setPosition and setAlpha.  It is not necessary to
      * open a transaction when updating a single property.
      * Calls to openTransaction() nest and must be matched by an equal number
      * of calls to closeTransaction(). */
-    void openTransaction();
-    void closeTransaction();
+    virtual void openTransaction();
+    virtual void closeTransaction();
 
 private:
     enum {
@@ -174,6 +176,7 @@
         DIRTY_VISIBILITY = 1 << 5,
         DIRTY_HOTSPOT = 1 << 6,
         DIRTY_DISPLAY_ID = 1 << 7,
+        DIRTY_ICON_STYLE = 1 << 8,
     };
 
     /* Describes the state of a sprite.
diff --git a/libs/input/TEST_MAPPING b/libs/input/TEST_MAPPING
new file mode 100644
index 0000000..fe74c62
--- /dev/null
+++ b/libs/input/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+    "presubmit": [
+        {
+            "name": "libinputservice_test"
+        }
+    ]
+}
diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp
new file mode 100644
index 0000000..e83b2a7
--- /dev/null
+++ b/libs/input/tests/Android.bp
@@ -0,0 +1,45 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_test {
+    name: "libinputservice_test",
+    srcs: [
+        "PointerController_test.cpp",
+    ],
+    shared_libs: [
+        "libinputservice",
+        "libgui",
+        "libhwui",
+        "libutils",
+    ],
+    static_libs: [
+        "libgmock",
+        "libgtest",
+    ],
+    header_libs: [
+        "libbase_headers",
+        "libinputflinger_headers",
+    ],
+    include_dirs: [
+        "frameworks/base/libs",
+    ],
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wextra",
+    ],
+    test_suites: [
+        "general-tests",
+    ],
+}
diff --git a/libs/input/tests/PointerController_test.cpp b/libs/input/tests/PointerController_test.cpp
new file mode 100644
index 0000000..a157426
--- /dev/null
+++ b/libs/input/tests/PointerController_test.cpp
@@ -0,0 +1,262 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mocks/MockSprite.h"
+#include "mocks/MockSpriteController.h"
+
+#include <input/PointerController.h>
+#include <input/SpriteController.h>
+
+#include <atomic>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <thread>
+
+namespace android {
+
+enum TestCursorType {
+    CURSOR_TYPE_DEFAULT = 0,
+    CURSOR_TYPE_HOVER,
+    CURSOR_TYPE_TOUCH,
+    CURSOR_TYPE_ANCHOR,
+    CURSOR_TYPE_ADDITIONAL,
+    CURSOR_TYPE_ADDITIONAL_ANIM,
+    CURSOR_TYPE_CUSTOM = -1,
+};
+
+using ::testing::AllOf;
+using ::testing::Field;
+using ::testing::Mock;
+using ::testing::NiceMock;
+using ::testing::Return;
+using ::testing::Test;
+
+std::pair<float, float> getHotSpotCoordinatesForType(int32_t type) {
+    return std::make_pair(type * 10, type * 10 + 5);
+}
+
+class MockPointerControllerPolicyInterface : public PointerControllerPolicyInterface {
+public:
+    virtual void loadPointerIcon(SpriteIcon* icon, int32_t displayId) override;
+    virtual void loadPointerResources(PointerResources* outResources, int32_t displayId) override;
+    virtual void loadAdditionalMouseResources(std::map<int32_t, SpriteIcon>* outResources,
+            std::map<int32_t, PointerAnimation>* outAnimationResources, int32_t displayId) override;
+    virtual int32_t getDefaultPointerIconId() override;
+    virtual int32_t getCustomPointerIconId() override;
+
+    bool allResourcesAreLoaded();
+    bool noResourcesAreLoaded();
+
+private:
+    void loadPointerIconForType(SpriteIcon* icon, int32_t cursorType);
+
+    bool pointerIconLoaded{false};
+    bool pointerResourcesLoaded{false};
+    bool additionalMouseResourcesLoaded{false};
+};
+
+void MockPointerControllerPolicyInterface::loadPointerIcon(SpriteIcon* icon, int32_t) {
+    loadPointerIconForType(icon, CURSOR_TYPE_DEFAULT);
+    pointerIconLoaded = true;
+}
+
+void MockPointerControllerPolicyInterface::loadPointerResources(PointerResources* outResources,
+        int32_t) {
+    loadPointerIconForType(&outResources->spotHover, CURSOR_TYPE_HOVER);
+    loadPointerIconForType(&outResources->spotTouch, CURSOR_TYPE_TOUCH);
+    loadPointerIconForType(&outResources->spotAnchor, CURSOR_TYPE_ANCHOR);
+    pointerResourcesLoaded = true;
+}
+
+void MockPointerControllerPolicyInterface::loadAdditionalMouseResources(
+        std::map<int32_t, SpriteIcon>* outResources,
+        std::map<int32_t, PointerAnimation>* outAnimationResources,
+        int32_t) {
+    SpriteIcon icon;
+    PointerAnimation anim;
+
+    // CURSOR_TYPE_ADDITIONAL doesn't have animation resource.
+    int32_t cursorType = CURSOR_TYPE_ADDITIONAL;
+    loadPointerIconForType(&icon, cursorType);
+    (*outResources)[cursorType] = icon;
+
+    // CURSOR_TYPE_ADDITIONAL_ANIM has animation resource.
+    cursorType = CURSOR_TYPE_ADDITIONAL_ANIM;
+    loadPointerIconForType(&icon, cursorType);
+    anim.animationFrames.push_back(icon);
+    anim.durationPerFrame = 10;
+    (*outResources)[cursorType] = icon;
+    (*outAnimationResources)[cursorType] = anim;
+
+    additionalMouseResourcesLoaded = true;
+}
+
+int32_t MockPointerControllerPolicyInterface::getDefaultPointerIconId() {
+    return CURSOR_TYPE_DEFAULT;
+}
+
+int32_t MockPointerControllerPolicyInterface::getCustomPointerIconId() {
+    return CURSOR_TYPE_CUSTOM;
+}
+
+bool MockPointerControllerPolicyInterface::allResourcesAreLoaded() {
+    return pointerIconLoaded && pointerResourcesLoaded && additionalMouseResourcesLoaded;
+}
+
+bool MockPointerControllerPolicyInterface::noResourcesAreLoaded() {
+    return !(pointerIconLoaded || pointerResourcesLoaded || additionalMouseResourcesLoaded);
+}
+
+void MockPointerControllerPolicyInterface::loadPointerIconForType(SpriteIcon* icon, int32_t type) {
+    icon->style = type;
+    std::pair<float, float> hotSpot = getHotSpotCoordinatesForType(type);
+    icon->hotSpotX = hotSpot.first;
+    icon->hotSpotY = hotSpot.second;
+}
+class PointerControllerTest : public Test {
+protected:
+    PointerControllerTest();
+    ~PointerControllerTest();
+
+    void ensureDisplayViewportIsSet();
+
+    sp<MockSprite> mPointerSprite;
+    sp<MockPointerControllerPolicyInterface> mPolicy;
+    sp<MockSpriteController> mSpriteController;
+    sp<PointerController> mPointerController;
+
+private:
+    void loopThread();
+
+    std::atomic<bool> mRunning = true;
+    class MyLooper : public Looper {
+    public:
+        MyLooper() : Looper(false) {}
+        ~MyLooper() = default;
+    };
+    sp<MyLooper> mLooper;
+    std::thread mThread;
+};
+
+PointerControllerTest::PointerControllerTest() : mPointerSprite(new NiceMock<MockSprite>),
+        mLooper(new MyLooper), mThread(&PointerControllerTest::loopThread, this) {
+
+    mSpriteController = new NiceMock<MockSpriteController>(mLooper);
+    mPolicy = new MockPointerControllerPolicyInterface();
+
+    EXPECT_CALL(*mSpriteController, createSprite())
+            .WillOnce(Return(mPointerSprite));
+
+    mPointerController = new PointerController(mPolicy, mLooper, mSpriteController);
+}
+
+PointerControllerTest::~PointerControllerTest() {
+    mRunning.store(false, std::memory_order_relaxed);
+    mThread.join();
+}
+
+void PointerControllerTest::ensureDisplayViewportIsSet() {
+    DisplayViewport viewport;
+    viewport.displayId = ADISPLAY_ID_DEFAULT;
+    viewport.logicalRight = 1600;
+    viewport.logicalBottom = 1200;
+    viewport.physicalRight = 800;
+    viewport.physicalBottom = 600;
+    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() {
+    Looper::setForThread(mLooper);
+
+    while (mRunning.load(std::memory_order_relaxed)) {
+        mLooper->pollOnce(100);
+    }
+}
+
+TEST_F(PointerControllerTest, useDefaultCursorTypeByDefault) {
+    ensureDisplayViewportIsSet();
+    mPointerController->unfade(PointerController::TRANSITION_IMMEDIATE);
+
+    std::pair<float, float> hotspot = getHotSpotCoordinatesForType(CURSOR_TYPE_DEFAULT);
+    EXPECT_CALL(*mPointerSprite, setVisible(true));
+    EXPECT_CALL(*mPointerSprite, setAlpha(1.0f));
+    EXPECT_CALL(*mPointerSprite, setIcon(
+            AllOf(
+                    Field(&SpriteIcon::style, CURSOR_TYPE_DEFAULT),
+                    Field(&SpriteIcon::hotSpotX, hotspot.first),
+                    Field(&SpriteIcon::hotSpotY, hotspot.second))));
+    mPointerController->reloadPointerResources();
+}
+
+TEST_F(PointerControllerTest, updatePointerIcon) {
+    ensureDisplayViewportIsSet();
+    mPointerController->unfade(PointerController::TRANSITION_IMMEDIATE);
+
+    int32_t type = CURSOR_TYPE_ADDITIONAL;
+    std::pair<float, float> hotspot = getHotSpotCoordinatesForType(type);
+    EXPECT_CALL(*mPointerSprite, setVisible(true));
+    EXPECT_CALL(*mPointerSprite, setAlpha(1.0f));
+    EXPECT_CALL(*mPointerSprite, setIcon(
+            AllOf(
+                    Field(&SpriteIcon::style, type),
+                    Field(&SpriteIcon::hotSpotX, hotspot.first),
+                    Field(&SpriteIcon::hotSpotY, hotspot.second))));
+    mPointerController->updatePointerIcon(type);
+}
+
+TEST_F(PointerControllerTest, setCustomPointerIcon) {
+    ensureDisplayViewportIsSet();
+    mPointerController->unfade(PointerController::TRANSITION_IMMEDIATE);
+
+    int32_t style = CURSOR_TYPE_CUSTOM;
+    float hotSpotX = 15;
+    float hotSpotY = 20;
+
+    SpriteIcon icon;
+    icon.style = style;
+    icon.hotSpotX = hotSpotX;
+    icon.hotSpotY = hotSpotY;
+
+    EXPECT_CALL(*mPointerSprite, setVisible(true));
+    EXPECT_CALL(*mPointerSprite, setAlpha(1.0f));
+    EXPECT_CALL(*mPointerSprite, setIcon(
+            AllOf(
+                    Field(&SpriteIcon::style, style),
+                    Field(&SpriteIcon::hotSpotX, hotSpotX),
+                    Field(&SpriteIcon::hotSpotY, hotSpotY))));
+    mPointerController->setCustomPointerIcon(icon);
+}
+
+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);
+    mPointerController->fade(PointerController::TRANSITION_IMMEDIATE);
+
+    EXPECT_TRUE(mPolicy->noResourcesAreLoaded());
+
+    ensureDisplayViewportIsSet();
+}
+
+}  // namespace android
diff --git a/libs/input/tests/mocks/MockSprite.h b/libs/input/tests/mocks/MockSprite.h
new file mode 100644
index 0000000..013b79c
--- /dev/null
+++ b/libs/input/tests/mocks/MockSprite.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _MOCK_SPRITE_H
+#define _MOCK_SPRITE_H
+
+#include <input/SpriteController.h>
+
+#include <gmock/gmock.h>
+
+namespace android {
+
+class MockSprite : public Sprite {
+public:
+    virtual ~MockSprite() = default;
+
+    MOCK_METHOD(void, setIcon, (const SpriteIcon& icon), (override));
+    MOCK_METHOD(void, setVisible, (bool), (override));
+    MOCK_METHOD(void, setPosition, (float, float), (override));
+    MOCK_METHOD(void, setLayer, (int32_t), (override));
+    MOCK_METHOD(void, setAlpha, (float), (override));
+    MOCK_METHOD(void, setTransformationMatrix, (const SpriteTransformationMatrix&), (override));
+    MOCK_METHOD(void, setDisplayId, (int32_t), (override));
+};
+
+}  // namespace android
+
+#endif  // _MOCK_SPRITE_H
diff --git a/libs/input/tests/mocks/MockSpriteController.h b/libs/input/tests/mocks/MockSpriteController.h
new file mode 100644
index 0000000..a034f66
--- /dev/null
+++ b/libs/input/tests/mocks/MockSpriteController.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _MOCK_SPRITE_CONTROLLER_H
+#define _MOCK_SPRITE_CONTROLLER_H
+
+#include "MockSprite.h"
+
+#include <input/SpriteController.h>
+
+namespace android {
+
+class MockSpriteController : public SpriteController {
+
+public:
+    MockSpriteController(sp<Looper> looper) : SpriteController(looper, 0) {}
+    ~MockSpriteController() {}
+
+    MOCK_METHOD(sp<Sprite>, createSprite, (), (override));
+    MOCK_METHOD(void, openTransaction, (), (override));
+    MOCK_METHOD(void, closeTransaction, (), (override));
+};
+
+}  // namespace android
+
+#endif  // _MOCK_SPRITE_CONTROLLER_H
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index d331d1f..89bcb7f 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -166,6 +166,7 @@
             outPointerIcon->bitmap.readPixels(bitmapCopy->info(), bitmapCopy->getPixels(),
                     bitmapCopy->rowBytes(), 0, 0);
         }
+        outSpriteIcon->style = outPointerIcon->style;
         outSpriteIcon->hotSpotX = outPointerIcon->hotSpotX;
         outSpriteIcon->hotSpotY = outPointerIcon->hotSpotY;
     }
@@ -318,7 +319,6 @@
     void updateInactivityTimeoutLocked();
     void handleInterceptActions(jint wmActions, nsecs_t when, uint32_t& policyFlags);
     void ensureSpriteControllerLocked();
-    const DisplayViewport* findDisplayViewportLocked(int32_t displayId);
     int32_t getPointerDisplayId();
     void updatePointerDisplayLocked();
     static bool checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName);
@@ -396,16 +396,6 @@
     return false;
 }
 
-const DisplayViewport* NativeInputManager::findDisplayViewportLocked(int32_t displayId)
-        REQUIRES(mLock) {
-    for (const DisplayViewport& v : mLocked.viewports) {
-        if (v.displayId == displayId) {
-            return &v;
-        }
-    }
-    return nullptr;
-}
-
 void NativeInputManager::setDisplayViewports(JNIEnv* env, jobjectArray viewportObjArray) {
     std::vector<DisplayViewport> viewports;
 
@@ -554,6 +544,8 @@
 
         outConfig->setDisplayViewports(mLocked.viewports);
 
+        outConfig->defaultPointerDisplayId = mLocked.pointerDisplayId;
+
         outConfig->disabledDevices = mLocked.disabledInputDevices;
     } // release lock
 }
@@ -571,8 +563,6 @@
         updateInactivityTimeoutLocked();
     }
 
-    updatePointerDisplayLocked();
-
     return controller;
 }
 
@@ -587,23 +577,6 @@
     return pointerDisplayId;
 }
 
-void NativeInputManager::updatePointerDisplayLocked() REQUIRES(mLock) {
-    ATRACE_CALL();
-
-    sp<PointerController> controller = mLocked.pointerController.promote();
-    if (controller != nullptr) {
-        const DisplayViewport* viewport = findDisplayViewportLocked(mLocked.pointerDisplayId);
-        if (viewport == nullptr) {
-            ALOGW("Can't find pointer display viewport, fallback to default display.");
-            viewport = findDisplayViewportLocked(ADISPLAY_ID_DEFAULT);
-        }
-
-        if (viewport != nullptr) {
-            controller->setDisplayViewport(*viewport);
-        }
-    }
-}
-
 void NativeInputManager::ensureSpriteControllerLocked() REQUIRES(mLock) {
     if (mLocked.spriteController == nullptr) {
         JNIEnv* env = jniEnv();
@@ -1252,7 +1225,8 @@
     status_t status = android_view_PointerIcon_load(env, pointerIconObj.get(),
             displayContext.get(), &pointerIcon);
     if (!status && !pointerIcon.isNullIcon()) {
-        *icon = SpriteIcon(pointerIcon.bitmap, pointerIcon.hotSpotX, pointerIcon.hotSpotY);
+        *icon = SpriteIcon(
+                pointerIcon.bitmap, pointerIcon.style, pointerIcon.hotSpotX, pointerIcon.hotSpotY);
     } else {
         *icon = SpriteIcon();
     }
@@ -1293,10 +1267,12 @@
                     milliseconds_to_nanoseconds(pointerIcon.durationPerFrame);
             animationData.animationFrames.reserve(numFrames);
             animationData.animationFrames.push_back(SpriteIcon(
-                    pointerIcon.bitmap, pointerIcon.hotSpotX, pointerIcon.hotSpotY));
+                    pointerIcon.bitmap, pointerIcon.style,
+                    pointerIcon.hotSpotX, pointerIcon.hotSpotY));
             for (size_t i = 0; i < numFrames - 1; ++i) {
               animationData.animationFrames.push_back(SpriteIcon(
-                      pointerIcon.bitmapFrames[i], pointerIcon.hotSpotX, pointerIcon.hotSpotY));
+                      pointerIcon.bitmapFrames[i], pointerIcon.style,
+                      pointerIcon.hotSpotX, pointerIcon.hotSpotY));
             }
         }
     }
@@ -1732,6 +1708,7 @@
         pointerIcon.bitmap.readPixels(spriteInfo, spriteIcon.bitmap.getPixels(),
                 spriteIcon.bitmap.rowBytes(), 0, 0);
     }
+    spriteIcon.style = pointerIcon.style;
     spriteIcon.hotSpotX = pointerIcon.hotSpotX;
     spriteIcon.hotSpotY = pointerIcon.hotSpotY;
     im->setCustomPointerIcon(spriteIcon);