Merge changes from topic "sfinput4"

* changes:
  SurfaceFlinger Input: Correct screen magnification.
  Remove inputflinger.rc as init file
  SurfaceFlinger Input: Shrink frame by surfaceInsets.
  InputDispatcher: Notify policy of focus changes.
  Rework InputApplicationInfo
  Replace InputWindowInfo#inputChannel with an IBinder token.
  Add some tests for native input.
  Forward input windows from SurfaceFlinger to InputDispatcher.
diff --git a/include/input/IInputFlinger.h b/include/input/IInputFlinger.h
index 1ef8986..610834d 100644
--- a/include/input/IInputFlinger.h
+++ b/include/input/IInputFlinger.h
@@ -36,6 +36,9 @@
     DECLARE_META_INTERFACE(InputFlinger)
 
     virtual void setInputWindows(const Vector<InputWindowInfo>& inputHandles) = 0;
+
+    virtual void registerInputChannel(const sp<InputChannel>& channel) = 0;
+    virtual void unregisterInputChannel(const sp<InputChannel>& channel) = 0;
 };
 
 
@@ -46,6 +49,8 @@
 public:
     enum {
         SET_INPUT_WINDOWS_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
+        REGISTER_INPUT_CHANNEL_TRANSACTION,
+        UNREGISTER_INPUT_CHANNEL_TRANSACTION
     };
 
     virtual status_t onTransact(uint32_t code, const Parcel& data,
diff --git a/include/input/Input.h b/include/input/Input.h
index cc45aef..ee22bc6 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -244,7 +244,12 @@
     float getAxisValue(int32_t axis) const;
     status_t setAxisValue(int32_t axis, float value);
 
-    void scale(float scale);
+    void scale(float globalScale);
+
+    // Scale the pointer coordinates according to a global scale and a
+    // window scale. The global scale will be applied to TOUCH/TOOL_MAJOR/MINOR
+    // axes, however the window scaling will not.
+    void scale(float globalScale, float windowXScale, float windowYScale);
     void applyOffset(float xOffset, float yOffset);
 
     inline float getX() const {
@@ -595,7 +600,7 @@
 
     void offsetLocation(float xOffset, float yOffset);
 
-    void scale(float scaleFactor);
+    void scale(float globalScaleFactor);
 
     // Apply 3x3 perspective matrix transformation.
     // Matrix is in row-major form and compatible with SkMatrix.
diff --git a/include/input/InputApplication.h b/include/input/InputApplication.h
index 9b365b9..71a8f20 100644
--- a/include/input/InputApplication.h
+++ b/include/input/InputApplication.h
@@ -19,6 +19,9 @@
 
 #include <string>
 
+#include <binder/IBinder.h>
+#include <binder/Parcel.h>
+
 #include <input/Input.h>
 #include <utils/RefBase.h>
 #include <utils/Timers.h>
@@ -29,8 +32,12 @@
  * Describes the properties of an application that can receive input.
  */
 struct InputApplicationInfo {
+    sp<IBinder> token;
     std::string name;
     nsecs_t dispatchingTimeout;
+
+    status_t write(Parcel& output) const;
+    static InputApplicationInfo read(const Parcel& from);
 };
 
 
@@ -54,6 +61,10 @@
         return mInfo ? mInfo->dispatchingTimeout : defaultValue;
     }
 
+    inline sp<IBinder> getApplicationToken() const {
+        return mInfo ? mInfo->token : nullptr;
+    }
+
     /**
      * Requests that the state of this object be updated to reflect
      * the most current available information about the application.
diff --git a/include/input/InputWindow.h b/include/input/InputWindow.h
index 9e3d334..8dd95cf 100644
--- a/include/input/InputWindow.h
+++ b/include/input/InputWindow.h
@@ -116,17 +116,42 @@
         INPUT_FEATURE_NO_INPUT_CHANNEL = 0x00000002,
         INPUT_FEATURE_DISABLE_USER_ACTIVITY = 0x00000004,
     };
-
-    sp<InputChannel> inputChannel;
+    
+    /* These values are filled in by the WM and passed through SurfaceFlinger
+     * unless specified otherwise.
+     */
+    sp<IBinder> token;
     std::string name;
     int32_t layoutParamsFlags;
     int32_t layoutParamsType;
     nsecs_t dispatchingTimeout;
+
+    /* These values are filled in by SurfaceFlinger. */
     int32_t frameLeft;
     int32_t frameTop;
     int32_t frameRight;
     int32_t frameBottom;
-    float scaleFactor;
+
+    /*
+     * SurfaceFlinger consumes this value to shrink the computed frame. This is
+     * different from shrinking the touchable region in that it DOES shift the coordinate
+     * space where-as the touchable region does not and is more like "cropping". This
+     * is used for window shadows.
+     */
+    int32_t surfaceInset = 0;
+
+    // A global scaling factor for all windows. Unlike windowScaleX/Y this results
+    // in scaling of the TOUCH_MAJOR/TOUCH_MINOR axis.
+    float globalScaleFactor;
+
+    // Scaling factors applied to individual windows.
+    float windowXScale = 1.0f;
+    float windowYScale = 1.0f;
+
+    /*
+     * This is filled in by the WM relative to the frame and then translated
+     * to absolute coordinates by SurfaceFlinger once the frame is computed.
+     */
     Region touchableRegion;
     bool visible;
     bool canReceiveKeys;
@@ -138,6 +163,7 @@
     int32_t ownerUid;
     int32_t inputFeatures;
     int32_t displayId;
+    InputApplicationInfo applicationInfo;
 
     void addTouchableRegion(const Rect& region);
 
@@ -168,20 +194,23 @@
  */
 class InputWindowHandle : public RefBase {
 public:
-    const sp<InputApplicationHandle> inputApplicationHandle;
 
     inline const InputWindowInfo* getInfo() const {
         return &mInfo;
     }
 
-    sp<InputChannel> getInputChannel() const;
+    sp<IBinder> getToken() const;
+
+    sp<IBinder> getApplicationToken() {
+        return mInfo.applicationInfo.token;
+    }
 
     inline std::string getName() const {
-        return mInfo.inputChannel ? mInfo.name : "<invalid>";
+        return mInfo.token ? mInfo.name : "<invalid>";
     }
 
     inline nsecs_t getDispatchingTimeout(nsecs_t defaultValue) const {
-        return mInfo.inputChannel? mInfo.dispatchingTimeout : defaultValue;
+        return mInfo.token ? mInfo.dispatchingTimeout : defaultValue;
     }
 
     /**
@@ -202,7 +231,7 @@
     void releaseChannel();
 
 protected:
-    explicit InputWindowHandle(const sp<InputApplicationHandle>& inputApplicationHandle);
+    explicit InputWindowHandle();
     virtual ~InputWindowHandle();
 
     InputWindowInfo mInfo;
diff --git a/libs/gui/tests/Android.bp b/libs/gui/tests/Android.bp
index 7ecadf8..a6295e0 100644
--- a/libs/gui/tests/Android.bp
+++ b/libs/gui/tests/Android.bp
@@ -16,6 +16,7 @@
         "BufferItemConsumer_test.cpp",
         "BufferQueue_test.cpp",
         "CpuConsumer_test.cpp",
+        "EndToEndNativeInputTest.cpp",
         "FillBuffer.cpp",
         "GLTest.cpp",
         "IGraphicBufferProducer_test.cpp",
diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp
new file mode 100644
index 0000000..2871302
--- /dev/null
+++ b/libs/gui/tests/EndToEndNativeInputTest.cpp
@@ -0,0 +1,272 @@
+/*
+ * Copyright 2018 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 <gtest/gtest.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <poll.h>
+
+#include <memory>
+
+#include <binder/Binder.h>
+#include <binder/IServiceManager.h>
+#include <binder/Parcel.h>
+#include <binder/ProcessState.h>
+
+#include <gui/SurfaceComposerClient.h>
+#include <gui/SurfaceControl.h>
+
+#include <input/InputWindow.h>
+#include <input/IInputFlinger.h>
+#include <input/InputTransport.h>
+#include <input/Input.h>
+
+#include <ui/Rect.h>
+#include <ui/Region.h>
+
+
+namespace android {
+namespace test {
+
+sp<IInputFlinger> getInputFlinger() {
+   sp<IBinder> input(defaultServiceManager()->getService(
+            String16("inputflinger")));
+    if (input == nullptr) {
+        ALOGE("Failed to link to input service");
+    } else { ALOGE("Linked to input"); }
+    return interface_cast<IInputFlinger>(input);
+}
+
+// We use the top 10 layers as a way to haphazardly place ourselves above anything else.
+static const int LAYER_BASE = INT32_MAX - 10;
+
+class InputSurface {
+public:
+    InputSurface(const sp<SurfaceComposerClient>& scc, int width, int height) {
+        mSurfaceControl = scc->createSurface(String8("Test Surface"),
+                width, height, PIXEL_FORMAT_RGBA_8888,
+                ISurfaceComposerClient::eFXSurfaceColor);
+
+        InputChannel::openInputChannelPair("testchannels", mServerChannel, mClientChannel);
+        mServerChannel->setToken(new BBinder());
+
+        mInputFlinger = getInputFlinger();
+        mInputFlinger->registerInputChannel(mServerChannel);
+
+        populateInputInfo(width, height);
+
+        mInputConsumer = new InputConsumer(mClientChannel);
+    }
+
+    InputEvent* consumeEvent() {
+        waitForEventAvailable();
+
+        InputEvent *ev;
+        uint32_t seqId;
+        status_t consumed = mInputConsumer->consume(&mInputEventFactory, true, -1, &seqId, &ev);
+        if (consumed != OK) {
+            return nullptr;
+        }
+        mInputConsumer->sendFinishedSignal(seqId, true);
+        return ev;
+    }
+
+    void expectTap(int x, int y) {
+        InputEvent* ev = consumeEvent();
+        EXPECT_TRUE(ev != nullptr);
+        EXPECT_TRUE(ev->getType() == AINPUT_EVENT_TYPE_MOTION);
+        MotionEvent* mev = static_cast<MotionEvent*>(ev);
+        EXPECT_EQ(AMOTION_EVENT_ACTION_DOWN, mev->getAction());
+        EXPECT_EQ(x, mev->getX(0));
+        EXPECT_EQ(y, mev->getY(0));
+
+        ev = consumeEvent();
+        EXPECT_TRUE(ev != nullptr);
+        EXPECT_TRUE(ev->getType() == AINPUT_EVENT_TYPE_MOTION);
+        mev = static_cast<MotionEvent*>(ev);
+        EXPECT_EQ(AMOTION_EVENT_ACTION_UP, mev->getAction());
+    }
+
+    ~InputSurface() {
+        mInputFlinger->unregisterInputChannel(mServerChannel);
+    }
+
+    void doTransaction(std::function<void(SurfaceComposerClient::Transaction&,
+                    const sp<SurfaceControl>&)> transactionBody) {
+        SurfaceComposerClient::Transaction t;
+        transactionBody(t, mSurfaceControl);
+        t.apply(true);
+    }
+
+    void showAt(int x, int y) {
+        SurfaceComposerClient::Transaction t;
+        t.show(mSurfaceControl);
+        t.setInputWindowInfo(mSurfaceControl, mInputInfo);
+        t.setLayer(mSurfaceControl, LAYER_BASE);
+        t.setPosition(mSurfaceControl, x, y);
+        t.setCrop_legacy(mSurfaceControl, Rect(0, 0, 100, 100));
+        t.setAlpha(mSurfaceControl, 1);
+        t.apply(true);
+    }
+
+private:
+    void waitForEventAvailable() {
+        struct pollfd fd;
+
+        fd.fd = mClientChannel->getFd();
+        fd.events = POLLIN;
+        poll(&fd, 1, 3000);
+    }
+
+    void populateInputInfo(int width, int height) {
+        mInputInfo.token = mServerChannel->getToken();
+        mInputInfo.name = "Test info";
+        mInputInfo.layoutParamsFlags = InputWindowInfo::FLAG_NOT_TOUCH_MODAL;
+        mInputInfo.layoutParamsType = InputWindowInfo::TYPE_BASE_APPLICATION;
+        mInputInfo.dispatchingTimeout = 100000;
+        mInputInfo.globalScaleFactor = 1.0;
+        mInputInfo.canReceiveKeys = true;
+        mInputInfo.hasFocus = true;
+        mInputInfo.hasWallpaper = false;
+        mInputInfo.paused = false;
+
+        mInputInfo.touchableRegion.orSelf(Rect(0, 0, width, height));
+
+        // TODO: Fill in from SF?
+        mInputInfo.ownerPid = 11111;
+        mInputInfo.ownerUid = 11111;
+        mInputInfo.inputFeatures = 0;
+        mInputInfo.displayId = 0;
+
+        InputApplicationInfo aInfo;
+        aInfo.token = new BBinder();
+        aInfo.name = "Test app info";
+        aInfo.dispatchingTimeout = 100000;
+
+        mInputInfo.applicationInfo = aInfo;
+    }
+public:
+    sp<SurfaceControl> mSurfaceControl;
+    sp<InputChannel> mServerChannel, mClientChannel;
+    sp<IInputFlinger> mInputFlinger;
+
+    InputWindowInfo mInputInfo;
+
+    PreallocatedInputEventFactory mInputEventFactory;
+    InputConsumer* mInputConsumer;
+};
+
+class InputSurfacesTest : public ::testing::Test {
+public:
+    InputSurfacesTest() {
+        ProcessState::self()->startThreadPool();
+    }
+
+    void SetUp() {
+        mComposerClient = new SurfaceComposerClient;
+        ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
+    }
+
+    void TearDown() {
+        mComposerClient->dispose();
+    }
+
+    std::unique_ptr<InputSurface> makeSurface(int width, int height) {
+        return std::make_unique<InputSurface>(mComposerClient, width, height);
+    }
+
+    sp<SurfaceComposerClient> mComposerClient;
+};
+
+void injectTap(int x, int y) {
+    char *buf1, *buf2;
+    asprintf(&buf1, "%d", x);
+    asprintf(&buf2, "%d", y);
+    if (fork() == 0) {
+        execlp("input", "input", "tap", buf1, buf2, NULL);
+    }
+}
+
+TEST_F(InputSurfacesTest, can_receive_input) {
+    std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
+    surface->showAt(100, 100);
+
+    injectTap(101, 101);
+
+    EXPECT_TRUE(surface->consumeEvent() != nullptr);
+}
+
+TEST_F(InputSurfacesTest, input_respects_positioning) {
+    std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
+    surface->showAt(100, 100);
+
+    std::unique_ptr<InputSurface> surface2 = makeSurface(100, 100);
+    surface2->showAt(200, 200);
+
+    injectTap(201, 201);
+    surface2->expectTap(1, 1);
+
+    injectTap(101, 101);
+    surface->expectTap(1, 1);
+
+    surface2->doTransaction([](auto &t, auto &sc) {
+         t.setPosition(sc, 100, 100);
+    });
+    surface->doTransaction([](auto &t, auto &sc) {
+         t.setPosition(sc, 200, 200);
+    });
+
+    injectTap(101, 101);
+    surface2->expectTap(1, 1);
+
+    injectTap(201, 201);
+    surface->expectTap(1, 1);
+}
+
+TEST_F(InputSurfacesTest, input_respects_layering) {
+    std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
+    std::unique_ptr<InputSurface> surface2 = makeSurface(100, 100);
+
+    surface->showAt(10, 10);
+    surface2->showAt(10, 10);
+
+    surface->doTransaction([](auto &t, auto &sc) {
+         t.setLayer(sc, LAYER_BASE + 1);
+    });
+
+    injectTap(11, 11);
+    surface->expectTap(1, 1);
+
+    surface2->doTransaction([](auto &t, auto &sc) {
+         t.setLayer(sc, LAYER_BASE + 1);
+    });
+
+    injectTap(11, 11);
+    surface2->expectTap(1, 1);
+
+    surface2->doTransaction([](auto &t, auto &sc) {
+         t.hide(sc);
+    });
+
+    injectTap(11, 11);
+    surface->expectTap(1, 1);
+}
+
+}
+}
diff --git a/libs/input/IInputFlinger.cpp b/libs/input/IInputFlinger.cpp
index 47a2c0c..477e54e 100644
--- a/libs/input/IInputFlinger.cpp
+++ b/libs/input/IInputFlinger.cpp
@@ -40,6 +40,20 @@
         }
         remote()->transact(BnInputFlinger::SET_INPUT_WINDOWS_TRANSACTION, data, &reply);
     }
+
+    virtual void registerInputChannel(const sp<InputChannel>& channel) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IInputFlinger::getInterfaceDescriptor());
+        channel->write(data);
+        remote()->transact(BnInputFlinger::REGISTER_INPUT_CHANNEL_TRANSACTION, data, &reply);
+    }
+
+    virtual void unregisterInputChannel(const sp<InputChannel>& channel) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IInputFlinger::getInterfaceDescriptor());
+        channel->write(data);
+        remote()->transact(BnInputFlinger::UNREGISTER_INPUT_CHANNEL_TRANSACTION, data, &reply);
+    }
 };
 
 IMPLEMENT_META_INTERFACE(InputFlinger, "android.input.IInputFlinger");
@@ -61,6 +75,20 @@
         setInputWindows(handles);
         break;
     }
+    case REGISTER_INPUT_CHANNEL_TRANSACTION: {
+        CHECK_INTERFACE(IInputFlinger, data, reply);
+        sp<InputChannel> channel = new InputChannel();
+        channel->read(data);
+        registerInputChannel(channel);
+        break;
+    }
+    case UNREGISTER_INPUT_CHANNEL_TRANSACTION: {
+        CHECK_INTERFACE(IInputFlinger, data, reply);
+        sp<InputChannel> channel = new InputChannel();
+        channel->read(data);
+        unregisterInputChannel(channel);
+        break;
+    }
     default:
         return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp
index 8a15e2f..a558970 100644
--- a/libs/input/Input.cpp
+++ b/libs/input/Input.cpp
@@ -131,15 +131,24 @@
     }
 }
 
-void PointerCoords::scale(float scaleFactor) {
+void PointerCoords::scale(float globalScaleFactor, float windowXScale, float windowYScale) {
     // No need to scale pressure or size since they are normalized.
     // No need to scale orientation since it is meaningless to do so.
-    scaleAxisValue(*this, AMOTION_EVENT_AXIS_X, scaleFactor);
-    scaleAxisValue(*this, AMOTION_EVENT_AXIS_Y, scaleFactor);
-    scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOUCH_MAJOR, scaleFactor);
-    scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOUCH_MINOR, scaleFactor);
-    scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOOL_MAJOR, scaleFactor);
-    scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOOL_MINOR, scaleFactor);
+
+    // If there is a global scale factor, it is included in the windowX/YScale
+    // so we don't need to apply it twice to the X/Y axes.
+    // However we don't want to apply any windowXYScale not included in the global scale
+    // to the TOUCH_MAJOR/MINOR coordinates.
+    scaleAxisValue(*this, AMOTION_EVENT_AXIS_X, windowXScale);
+    scaleAxisValue(*this, AMOTION_EVENT_AXIS_Y, windowYScale);
+    scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOUCH_MAJOR, globalScaleFactor);
+    scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOUCH_MINOR, globalScaleFactor);
+    scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOOL_MAJOR, globalScaleFactor);
+    scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOOL_MINOR, globalScaleFactor);
+}
+
+void PointerCoords::scale(float globalScaleFactor) {
+    scale(globalScaleFactor, globalScaleFactor, globalScaleFactor);
 }
 
 void PointerCoords::applyOffset(float xOffset, float yOffset) {
@@ -345,15 +354,15 @@
     mYOffset += yOffset;
 }
 
-void MotionEvent::scale(float scaleFactor) {
-    mXOffset *= scaleFactor;
-    mYOffset *= scaleFactor;
-    mXPrecision *= scaleFactor;
-    mYPrecision *= scaleFactor;
+void MotionEvent::scale(float globalScaleFactor) {
+    mXOffset *= globalScaleFactor;
+    mYOffset *= globalScaleFactor;
+    mXPrecision *= globalScaleFactor;
+    mYPrecision *= globalScaleFactor;
 
     size_t numSamples = mSamplePointerCoords.size();
     for (size_t i = 0; i < numSamples; i++) {
-        mSamplePointerCoords.editItemAt(i).scale(scaleFactor);
+        mSamplePointerCoords.editItemAt(i).scale(globalScaleFactor);
     }
 }
 
diff --git a/libs/input/InputApplication.cpp b/libs/input/InputApplication.cpp
index a0d1668..7936f50 100644
--- a/libs/input/InputApplication.cpp
+++ b/libs/input/InputApplication.cpp
@@ -39,4 +39,21 @@
     }
 }
 
+InputApplicationInfo InputApplicationInfo::read(const Parcel& from) {
+    InputApplicationInfo ret;
+    ret.token = from.readStrongBinder();
+    ret.name = from.readString8().c_str();
+    ret.dispatchingTimeout = from.readInt64();
+
+    return ret;
+}
+
+status_t InputApplicationInfo::write(Parcel& output) const {
+    output.writeStrongBinder(token);
+    output.writeString8(String8(name.c_str()));
+    output.writeInt64(dispatchingTimeout);
+    
+    return OK;
+}
+
 } // namespace android
diff --git a/libs/input/InputWindow.cpp b/libs/input/InputWindow.cpp
index f82437e..556a005 100644
--- a/libs/input/InputWindow.cpp
+++ b/libs/input/InputWindow.cpp
@@ -65,12 +65,12 @@
 }
 
 status_t InputWindowInfo::write(Parcel& output) const {
-    if (inputChannel == nullptr) {
+    if (token == nullptr) {
         output.writeInt32(0);
         return OK;
     }
     output.writeInt32(1);
-    status_t s = inputChannel->write(output);
+    status_t s = output.writeStrongBinder(token);
     if (s != OK) return s;
 
     output.writeString8(String8(name.c_str()));
@@ -81,7 +81,10 @@
     output.writeInt32(frameTop);
     output.writeInt32(frameRight);
     output.writeInt32(frameBottom);
-    output.writeFloat(scaleFactor);
+    output.writeInt32(surfaceInset);
+    output.writeFloat(globalScaleFactor);
+    output.writeFloat(windowXScale);
+    output.writeFloat(windowYScale);
     output.writeBool(visible);
     output.writeBool(canReceiveKeys);
     output.writeBool(hasFocus);
@@ -92,6 +95,7 @@
     output.writeInt32(ownerUid);
     output.writeInt32(inputFeatures);
     output.writeInt32(displayId);
+    applicationInfo.write(output);
     output.write(touchableRegion);
 
     return OK;
@@ -102,15 +106,14 @@
 
     if (from.readInt32() == 0) {
         return ret;
-
     }
-    sp<InputChannel> inputChannel = new InputChannel();
-    status_t s = inputChannel->read(from);
-    if (s != OK) {
+
+    sp<IBinder> token = from.readStrongBinder();
+    if (token == nullptr) {
         return ret;
     }
 
-    ret.inputChannel = inputChannel;
+    ret.token = token;
     ret.name = from.readString8().c_str();
     ret.layoutParamsFlags = from.readInt32();
     ret.layoutParamsType = from.readInt32();
@@ -119,7 +122,10 @@
     ret.frameTop = from.readInt32();
     ret.frameRight = from.readInt32();
     ret.frameBottom = from.readInt32();
-    ret.scaleFactor = from.readFloat();
+    ret.surfaceInset = from.readInt32();
+    ret.globalScaleFactor = from.readFloat();
+    ret.windowXScale = from.readFloat();
+    ret.windowYScale = from.readFloat();
     ret.visible = from.readBool();
     ret.canReceiveKeys = from.readBool();
     ret.hasFocus = from.readBool();
@@ -130,6 +136,7 @@
     ret.ownerUid = from.readInt32();
     ret.inputFeatures = from.readInt32();
     ret.displayId = from.readInt32();
+    ret.applicationInfo = InputApplicationInfo::read(from);
     from.read(ret.touchableRegion);
 
     return ret;
@@ -141,19 +148,18 @@
 
 // --- InputWindowHandle ---
 
-InputWindowHandle::InputWindowHandle(const sp<InputApplicationHandle>& inputApplicationHandle) :
-    inputApplicationHandle(inputApplicationHandle) {
+InputWindowHandle::InputWindowHandle() {
 }
 
 InputWindowHandle::~InputWindowHandle() {
 }
 
 void InputWindowHandle::releaseChannel() {
-    mInfo.inputChannel.clear();
+    mInfo.token.clear();
 }
 
-sp<InputChannel> InputWindowHandle::getInputChannel() const {
-    return mInfo.inputChannel;
+sp<IBinder> InputWindowHandle::getToken() const {
+    return mInfo.token;
 }
 
 } // namespace android
diff --git a/libs/input/tests/InputWindow_test.cpp b/libs/input/tests/InputWindow_test.cpp
index 39ad26e..5e5893f 100644
--- a/libs/input/tests/InputWindow_test.cpp
+++ b/libs/input/tests/InputWindow_test.cpp
@@ -16,6 +16,7 @@
 
 #include <gtest/gtest.h>
 
+#include <binder/Binder.h>
 #include <binder/Parcel.h>
 
 #include <input/InputWindow.h>
@@ -24,24 +25,20 @@
 namespace android {
 namespace test {
 
-TEST(InputWindowInfo, ParcellingWithoutChannel) {
+TEST(InputWindowInfo, ParcellingWithoutToken) {
     InputWindowInfo i;
-    i.inputChannel = nullptr;
+    i.token = nullptr;
 
     Parcel p;
     ASSERT_EQ(OK, i.write(p));
     p.setDataPosition(0);
     InputWindowInfo i2 = InputWindowInfo::read(p);
-    ASSERT_TRUE(i2.inputChannel == nullptr);
+    ASSERT_TRUE(i2.token == nullptr);
 }
 
 TEST(InputWindowInfo, Parcelling) {
-    sp<InputChannel> channel, junkChannel;
-    status_t result = InputChannel::openInputChannelPair("name", channel, junkChannel);
-    ASSERT_EQ(OK, result) << "openInputChannelPair should have returned valid channels";
-
     InputWindowInfo i;
-    i.inputChannel = channel;
+    i.token = new BBinder();
     i.name = "Foobar";
     i.layoutParamsFlags = 7;
     i.layoutParamsType = 39;
@@ -50,7 +47,10 @@
     i.frameTop = 34;
     i.frameRight = 16;
     i.frameBottom = 19;
-    i.scaleFactor = 0.3;
+    i.surfaceInset = 17;
+    i.globalScaleFactor = 0.3;
+    i.windowXScale = 0.4;
+    i.windowYScale = 0.5;
     i.visible = false;
     i.canReceiveKeys = false;
     i.hasFocus = false;
@@ -67,7 +67,7 @@
 
     p.setDataPosition(0);
     InputWindowInfo i2 = InputWindowInfo::read(p);
-    ASSERT_EQ(i.inputChannel->getName(), i2.inputChannel->getName());
+    ASSERT_EQ(i.token, i2.token);
     ASSERT_EQ(i.name, i2.name);
     ASSERT_EQ(i.layoutParamsFlags, i2.layoutParamsFlags);
     ASSERT_EQ(i.layoutParamsType, i2.layoutParamsType);
@@ -76,7 +76,10 @@
     ASSERT_EQ(i.frameTop, i2.frameTop);
     ASSERT_EQ(i.frameRight, i2.frameRight);
     ASSERT_EQ(i.frameBottom, i2.frameBottom);
-    ASSERT_EQ(i.scaleFactor, i2.scaleFactor);
+    ASSERT_EQ(i.surfaceInset, i2.surfaceInset);
+    ASSERT_EQ(i.globalScaleFactor, i2.globalScaleFactor);
+    ASSERT_EQ(i.windowXScale, i2.windowXScale);
+    ASSERT_EQ(i.windowYScale, i2.windowYScale);
     ASSERT_EQ(i.visible, i2.visible);
     ASSERT_EQ(i.canReceiveKeys, i2.canReceiveKeys);
     ASSERT_EQ(i.hasFocus, i2.hasFocus);
diff --git a/libs/ui/Region.cpp b/libs/ui/Region.cpp
index fe4ae6c..8150931 100644
--- a/libs/ui/Region.cpp
+++ b/libs/ui/Region.cpp
@@ -325,6 +325,20 @@
     return *this;
 }
 
+Region& Region::scaleSelf(int sx, int sy) {
+    size_t count = mStorage.size();
+    Rect* rects = mStorage.editArray();
+    while (count) {
+        rects->left *= sx;
+        rects->right *= sx;
+        rects->top *= sy;
+        rects->bottom *= sy;
+        rects++;
+        count--;
+    }
+    return *this;
+}
+
 // ----------------------------------------------------------------------------
 
 const Region Region::merge(const Rect& rhs) const {
diff --git a/libs/ui/Transform.cpp b/libs/ui/Transform.cpp
index 8e949ec..25128ef 100644
--- a/libs/ui/Transform.cpp
+++ b/libs/ui/Transform.cpp
@@ -95,6 +95,14 @@
     return mMatrix[2][1];
 }
 
+float Transform::sx() const {
+    return mMatrix[0][0];
+}
+
+float Transform::sy() const {
+    return mMatrix[1][1];
+}
+
 void Transform::reset() {
     mType = IDENTITY;
     for(size_t i = 0; i < 3; i++) {
diff --git a/libs/ui/include/ui/Region.h b/libs/ui/include/ui/Region.h
index 68b60fc..c5e31c5 100644
--- a/libs/ui/include/ui/Region.h
+++ b/libs/ui/include/ui/Region.h
@@ -89,11 +89,13 @@
 
             // these translate rhs first
             Region&     translateSelf(int dx, int dy);
+            Region&     scaleSelf(int sx, int sy);
             Region&     orSelf(const Region& rhs, int dx, int dy);
             Region&     xorSelf(const Region& rhs, int dx, int dy);
             Region&     andSelf(const Region& rhs, int dx, int dy);
             Region&     subtractSelf(const Region& rhs, int dx, int dy);
 
+
             // these translate rhs first
     const   Region      translate(int dx, int dy) const WARN_UNUSED;
     const   Region      merge(const Region& rhs, int dx, int dy) const WARN_UNUSED;
diff --git a/libs/ui/include/ui/Transform.h b/libs/ui/include/ui/Transform.h
index 42dca75..900a5c4 100644
--- a/libs/ui/include/ui/Transform.h
+++ b/libs/ui/include/ui/Transform.h
@@ -65,6 +65,8 @@
     const vec3& operator [] (size_t i) const;  // returns column i
     float   tx() const;
     float   ty() const;
+    float   sx() const;
+    float   sy() const;
 
     // modify the transform
     void        reset();
diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp
index 0c9e04b..bea4f91 100644
--- a/services/inputflinger/InputDispatcher.cpp
+++ b/services/inputflinger/InputDispatcher.cpp
@@ -489,7 +489,7 @@
         if (motionEntry->action == AMOTION_EVENT_ACTION_DOWN
                 && (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER)
                 && mInputTargetWaitCause == INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY
-                && mInputTargetWaitApplicationHandle != nullptr) {
+                && mInputTargetWaitApplicationToken != nullptr) {
             int32_t displayId = motionEntry->displayId;
             int32_t x = int32_t(motionEntry->pointerCoords[0].
                     getAxisValue(AMOTION_EVENT_AXIS_X));
@@ -497,8 +497,8 @@
                     getAxisValue(AMOTION_EVENT_AXIS_Y));
             sp<InputWindowHandle> touchedWindowHandle = findTouchedWindowAtLocked(displayId, x, y);
             if (touchedWindowHandle != nullptr
-                    && touchedWindowHandle->inputApplicationHandle
-                            != mInputTargetWaitApplicationHandle) {
+                    && touchedWindowHandle->getApplicationToken()
+                            != mInputTargetWaitApplicationToken) {
                 // User touched a different application than the one we are waiting on.
                 // Flag the event, and start pruning the input queue.
                 mNextUnblockedEvent = motionEntry;
@@ -819,7 +819,8 @@
             sp<InputWindowHandle> focusedWindowHandle =
                     getValueByKey(mFocusedWindowHandlesByDisplay, getTargetDisplayId(entry));
             if (focusedWindowHandle != nullptr) {
-                commandEntry->inputChannel = focusedWindowHandle->getInputChannel();
+                commandEntry->inputChannel =
+                    getInputChannelLocked(focusedWindowHandle->getToken());
             }
             commandEntry->keyEntry = entry;
             entry->refCount += 1;
@@ -1010,7 +1011,7 @@
             mInputTargetWaitStartTime = currentTime;
             mInputTargetWaitTimeoutTime = LONG_LONG_MAX;
             mInputTargetWaitTimeoutExpired = false;
-            mInputTargetWaitApplicationHandle.clear();
+            mInputTargetWaitApplicationToken.clear();
         }
     } else {
         if (mInputTargetWaitCause != INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY) {
@@ -1033,13 +1034,13 @@
             mInputTargetWaitStartTime = currentTime;
             mInputTargetWaitTimeoutTime = currentTime + timeout;
             mInputTargetWaitTimeoutExpired = false;
-            mInputTargetWaitApplicationHandle.clear();
+            mInputTargetWaitApplicationToken.clear();
 
             if (windowHandle != nullptr) {
-                mInputTargetWaitApplicationHandle = windowHandle->inputApplicationHandle;
+                mInputTargetWaitApplicationToken = windowHandle->getApplicationToken();
             }
-            if (mInputTargetWaitApplicationHandle == nullptr && applicationHandle != nullptr) {
-                mInputTargetWaitApplicationHandle = applicationHandle;
+            if (mInputTargetWaitApplicationToken == nullptr && applicationHandle != nullptr) {
+                mInputTargetWaitApplicationToken = applicationHandle->getApplicationToken();
             }
         }
     }
@@ -1117,7 +1118,7 @@
 
     // Reset input target wait timeout.
     mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_NONE;
-    mInputTargetWaitApplicationHandle.clear();
+    mInputTargetWaitApplicationToken.clear();
 }
 
 /**
@@ -1666,11 +1667,13 @@
 
     const InputWindowInfo* windowInfo = windowHandle->getInfo();
     InputTarget& target = inputTargets.editTop();
-    target.inputChannel = windowInfo->inputChannel;
+    target.inputChannel = getInputChannelLocked(windowHandle->getToken());
     target.flags = targetFlags;
     target.xOffset = - windowInfo->frameLeft;
     target.yOffset = - windowInfo->frameTop;
-    target.scaleFactor = windowInfo->scaleFactor;
+    target.globalScaleFactor = windowInfo->globalScaleFactor;
+    target.windowXScale = windowInfo->windowXScale;
+    target.windowYScale = windowInfo->windowYScale;
     target.pointerIds = pointerIds;
 }
 
@@ -1691,7 +1694,7 @@
             target.xOffset = 0;
             target.yOffset = 0;
             target.pointerIds.clear();
-            target.scaleFactor = 1.0f;
+            target.globalScaleFactor = 1.0f;
         }
     } else {
         // If there is no monitor channel registered or all monitor channel unregistered,
@@ -1773,7 +1776,8 @@
     }
 
     // If the window's connection is not registered then keep waiting.
-    ssize_t connectionIndex = getConnectionIndexLocked(windowHandle->getInputChannel());
+    ssize_t connectionIndex = getConnectionIndexLocked(
+            getInputChannelLocked(windowHandle->getToken()));
     if (connectionIndex < 0) {
         return StringPrintf("Waiting because the %s window's input channel is not "
                 "registered with the input dispatcher.  The window may be in the process "
@@ -1910,11 +1914,13 @@
         const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget) {
 #if DEBUG_DISPATCH_CYCLE
     ALOGD("channel '%s' ~ prepareDispatchCycle - flags=0x%08x, "
-            "xOffset=%f, yOffset=%f, scaleFactor=%f, "
-            "pointerIds=0x%x",
+            "xOffset=%f, yOffset=%f, globalScaleFactor=%f, "
+            "windowScaleFactor=(%f, %f), pointerIds=0x%x",
             connection->getInputChannelName().c_str(), inputTarget->flags,
             inputTarget->xOffset, inputTarget->yOffset,
-            inputTarget->scaleFactor, inputTarget->pointerIds.value);
+            inputTarget->globalScaleFactor,
+            inputTarget->windowXScale, inputTarget->windowYScale,
+            inputTarget->pointerIds.value);
 #endif
 
     // Skip this event if the connection status is not normal.
@@ -1991,7 +1997,8 @@
     // Enqueue a new dispatch entry onto the outbound queue for this connection.
     DispatchEntry* dispatchEntry = new DispatchEntry(eventEntry, // increments ref
             inputTargetFlags, inputTarget->xOffset, inputTarget->yOffset,
-            inputTarget->scaleFactor);
+            inputTarget->globalScaleFactor, inputTarget->windowXScale,
+            inputTarget->windowYScale);
 
     // Apply target flags and update the connection's input state.
     switch (eventEntry->type) {
@@ -2107,13 +2114,15 @@
             float xOffset, yOffset;
             if ((motionEntry->source & AINPUT_SOURCE_CLASS_POINTER)
                     && !(dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS)) {
-                float scaleFactor = dispatchEntry->scaleFactor;
-                xOffset = dispatchEntry->xOffset * scaleFactor;
-                yOffset = dispatchEntry->yOffset * scaleFactor;
-                if (scaleFactor != 1.0f) {
+                float globalScaleFactor = dispatchEntry->globalScaleFactor;
+                float wxs = dispatchEntry->windowXScale;
+                float wys = dispatchEntry->windowYScale;
+                xOffset = dispatchEntry->xOffset * wxs;
+                yOffset = dispatchEntry->yOffset * wys;
+                if (wxs != 1.0f || wys != 1.0f || globalScaleFactor != 1.0f) {
                     for (uint32_t i = 0; i < motionEntry->pointerCount; i++) {
                         scaledCoords[i] = motionEntry->pointerCoords[i];
-                        scaledCoords[i].scale(scaleFactor);
+                        scaledCoords[i].scale(globalScaleFactor, wxs, wys);
                     }
                     usingCoords = scaledCoords;
                 }
@@ -2371,11 +2380,13 @@
                 const InputWindowInfo* windowInfo = windowHandle->getInfo();
                 target.xOffset = -windowInfo->frameLeft;
                 target.yOffset = -windowInfo->frameTop;
-                target.scaleFactor = windowInfo->scaleFactor;
+                target.globalScaleFactor = windowInfo->globalScaleFactor;
+                target.windowXScale = windowInfo->windowXScale;
+                target.windowYScale = windowInfo->windowYScale;
             } else {
                 target.xOffset = 0;
                 target.yOffset = 0;
-                target.scaleFactor = 1.0f;
+                target.globalScaleFactor = 1.0f;
             }
             target.inputChannel = connection->inputChannel;
             target.flags = InputTarget::FLAG_DISPATCH_AS_IS;
@@ -3004,7 +3015,7 @@
         size_t numWindows = windowHandles.size();
         for (size_t i = 0; i < numWindows; i++) {
             const sp<InputWindowHandle>& windowHandle = windowHandles.itemAt(i);
-            if (windowHandle->getInputChannel() == inputChannel) {
+            if (windowHandle->getToken() == inputChannel->getToken()) {
                 return windowHandle;
             }
         }
@@ -3018,8 +3029,8 @@
         const Vector<sp<InputWindowHandle>> windowHandles = it.second;
         size_t numWindows = windowHandles.size();
         for (size_t i = 0; i < numWindows; i++) {
-            if (windowHandles.itemAt(i)->getInputChannel()->getToken()
-                    == windowHandle->getInputChannel()->getToken()) {
+            if (windowHandles.itemAt(i)->getToken()
+                    == windowHandle->getToken()) {
                 if (windowHandle->getInfo()->displayId != it.first) {
                     ALOGE("Found window %s in display %" PRId32
                             ", but it should belong to display %" PRId32,
@@ -3033,6 +3044,14 @@
     return false;
 }
 
+sp<InputChannel> InputDispatcher::getInputChannelLocked(const sp<IBinder>& token) const {
+    size_t count = mInputChannelsByToken.count(token);
+    if (count == 0) {
+        return nullptr;
+    }
+    return mInputChannelsByToken.at(token);
+}
+
 /**
  * Called from InputManagerService, update window handle list by displayId that can receive input.
  * A window handle contains information about InputChannel, Touch Region, Types, Focused,...
@@ -3061,7 +3080,9 @@
             size_t numWindows = inputWindowHandles.size();
             for (size_t i = 0; i < numWindows; i++) {
                 const sp<InputWindowHandle>& windowHandle = inputWindowHandles.itemAt(i);
-                if (!windowHandle->updateInfo() || windowHandle->getInputChannel() == nullptr) {
+                if (!windowHandle->updateInfo() || getInputChannelLocked(windowHandle->getToken()) == nullptr) {
+                    ALOGE("Window handle %s has no registered input channel",
+                            windowHandle->getName().c_str());
                     continue;
                 }
 
@@ -3097,7 +3118,8 @@
                 ALOGD("Focus left window: %s in display %" PRId32,
                         oldFocusedWindowHandle->getName().c_str(), displayId);
 #endif
-                sp<InputChannel> focusedInputChannel = oldFocusedWindowHandle->getInputChannel();
+                sp<InputChannel> focusedInputChannel = getInputChannelLocked(
+                        oldFocusedWindowHandle->getToken());
                 if (focusedInputChannel != nullptr) {
                     CancelationOptions options(CancelationOptions::CANCEL_NON_POINTER_EVENTS,
                             "focus left window");
@@ -3113,6 +3135,11 @@
 #endif
                 mFocusedWindowHandlesByDisplay[displayId] = newFocusedWindowHandle;
             }
+
+            if (mFocusedDisplayId == displayId) {
+                onFocusChangedLocked(newFocusedWindowHandle);
+            }
+
         }
 
         ssize_t stateIndex = mTouchStatesByDisplay.indexOfKey(displayId);
@@ -3126,7 +3153,7 @@
                             touchedWindow.windowHandle->getName().c_str(), displayId);
 #endif
                     sp<InputChannel> touchedInputChannel =
-                            touchedWindow.windowHandle->getInputChannel();
+                            getInputChannelLocked(touchedWindow.windowHandle->getToken());
                     if (touchedInputChannel != nullptr) {
                         CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS,
                                 "touched window was removed");
@@ -3214,7 +3241,8 @@
             sp<InputWindowHandle> oldFocusedWindowHandle =
                     getValueByKey(mFocusedWindowHandlesByDisplay, mFocusedDisplayId);
             if (oldFocusedWindowHandle != nullptr) {
-                sp<InputChannel> inputChannel = oldFocusedWindowHandle->getInputChannel();
+                sp<InputChannel> inputChannel =
+                    getInputChannelLocked(oldFocusedWindowHandle->getToken());
                 if (inputChannel != nullptr) {
                     CancelationOptions options(
                             CancelationOptions::CANCEL_DISPLAY_UNSPECIFIED_EVENTS,
@@ -3227,6 +3255,8 @@
             // Sanity check
             sp<InputWindowHandle> newFocusedWindowHandle =
                     getValueByKey(mFocusedWindowHandlesByDisplay, displayId);
+            onFocusChangedLocked(newFocusedWindowHandle);
+
             if (newFocusedWindowHandle == nullptr) {
                 ALOGW("Focused display #%" PRId32 " does not have a focused window.", displayId);
                 if (!mFocusedWindowHandlesByDisplay.empty()) {
@@ -3488,7 +3518,7 @@
                     dump += StringPrintf(INDENT3 "%zu: name='%s', displayId=%d, "
                             "paused=%s, hasFocus=%s, hasWallpaper=%s, "
                             "visible=%s, canReceiveKeys=%s, flags=0x%08x, type=0x%08x, layer=%d, "
-                            "frame=[%d,%d][%d,%d], scale=%f, "
+                            "frame=[%d,%d][%d,%d], globalScale=%f, windowScale=%f,%f"
                             "touchableRegion=",
                             i, windowInfo->name.c_str(), windowInfo->displayId,
                             toString(windowInfo->paused),
@@ -3500,7 +3530,8 @@
                             windowInfo->layer,
                             windowInfo->frameLeft, windowInfo->frameTop,
                             windowInfo->frameRight, windowInfo->frameBottom,
-                            windowInfo->scaleFactor);
+                            windowInfo->globalScaleFactor,
+                            windowInfo->windowXScale, windowInfo->windowYScale);
                     dumpRegion(dump, windowInfo->touchableRegion);
                     dump += StringPrintf(", inputFeatures=0x%08x", windowInfo->inputFeatures);
                     dump += StringPrintf(", ownerPid=%d, ownerUid=%d, dispatchingTimeout=%0.3fms\n",
@@ -3667,6 +3698,7 @@
 
         int fd = inputChannel->getFd();
         mConnectionsByFd.add(fd, connection);
+        mInputChannelsByToken[inputChannel->getToken()] = inputChannel;
 
         // Store monitor channel by displayId.
         if (monitor) {
@@ -3715,6 +3747,8 @@
     sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);
     mConnectionsByFd.removeItemsAt(connectionIndex);
 
+    mInputChannelsByToken.erase(inputChannel->getToken());
+
     if (connection->monitor) {
         removeMonitorChannelLocked(inputChannel);
     }
@@ -3782,6 +3816,13 @@
     commandEntry->connection = connection;
 }
 
+void InputDispatcher::onFocusChangedLocked(const sp<InputWindowHandle>& newFocus) {
+    sp<IBinder> token = newFocus != nullptr ? newFocus->getToken() : nullptr;
+    CommandEntry* commandEntry = postCommandLocked(
+            & InputDispatcher::doNotifyFocusChangedLockedInterruptible);
+    commandEntry->token = token;
+}
+
 void InputDispatcher::onANRLocked(
         nsecs_t currentTime, const sp<InputApplicationHandle>& applicationHandle,
         const sp<InputWindowHandle>& windowHandle,
@@ -3812,7 +3853,8 @@
     CommandEntry* commandEntry = postCommandLocked(
             & InputDispatcher::doNotifyANRLockedInterruptible);
     commandEntry->inputApplicationHandle = applicationHandle;
-    commandEntry->inputChannel = windowHandle != nullptr ? windowHandle->getInputChannel() : nullptr;
+    commandEntry->inputChannel = windowHandle != nullptr ?
+            getInputChannelLocked(windowHandle->getToken()) : nullptr;
     commandEntry->reason = reason;
 }
 
@@ -3838,6 +3880,14 @@
     }
 }
 
+void InputDispatcher::doNotifyFocusChangedLockedInterruptible(
+        CommandEntry* commandEntry) {
+    sp<IBinder> token = commandEntry->token;
+    mLock.unlock();
+    mPolicy->notifyFocusChanged(token);
+    mLock.lock();
+}
+
 void InputDispatcher::doNotifyANRLockedInterruptible(
         CommandEntry* commandEntry) {
     mLock.unlock();
@@ -4343,10 +4393,12 @@
 volatile int32_t InputDispatcher::DispatchEntry::sNextSeqAtomic;
 
 InputDispatcher::DispatchEntry::DispatchEntry(EventEntry* eventEntry,
-        int32_t targetFlags, float xOffset, float yOffset, float scaleFactor) :
+        int32_t targetFlags, float xOffset, float yOffset, float globalScaleFactor,
+        float windowXScale, float windowYScale) :
         seq(nextSeq()),
         eventEntry(eventEntry), targetFlags(targetFlags),
-        xOffset(xOffset), yOffset(yOffset), scaleFactor(scaleFactor),
+        xOffset(xOffset), yOffset(yOffset), globalScaleFactor(globalScaleFactor),
+        windowXScale(windowXScale), windowYScale(windowYScale),
         deliveryTime(0), resolvedAction(0), resolvedFlags(0) {
     eventEntry->refCount += 1;
 }
@@ -4847,7 +4899,7 @@
 
 void InputDispatcher::TouchState::removeWindowByToken(const sp<IBinder>& token) {
     for (size_t i = 0; i < windows.size(); i++) {
-        if (windows.itemAt(i).windowHandle->getInputChannel()->getToken() == token) {
+        if (windows.itemAt(i).windowHandle->getToken() == token) {
             windows.removeAt(i);
             return;
         }
diff --git a/services/inputflinger/InputDispatcher.h b/services/inputflinger/InputDispatcher.h
index 5016082..73bcc25 100644
--- a/services/inputflinger/InputDispatcher.h
+++ b/services/inputflinger/InputDispatcher.h
@@ -29,6 +29,7 @@
 #include <utils/Looper.h>
 #include <utils/BitSet.h>
 #include <cutils/atomic.h>
+#include <unordered_map>
 
 #include <stddef.h>
 #include <unistd.h>
@@ -159,7 +160,9 @@
 
     // Scaling factor to apply to MotionEvent as it is delivered.
     // (ignored for KeyEvents)
-    float scaleFactor;
+    float globalScaleFactor;
+    float windowXScale = 1.0f;
+    float windowYScale = 1.0f;
 
     // The subset of pointer ids to include in motion events dispatched to this input target
     // if FLAG_SPLIT is set.
@@ -213,6 +216,7 @@
 
     /* Notifies the system that an input channel is unrecoverably broken. */
     virtual void notifyInputChannelBroken(const sp<IBinder>& token) = 0;
+    virtual void notifyFocusChanged(const sp<IBinder>& token) = 0;
 
     /* Gets the input dispatcher configuration. */
     virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) = 0;
@@ -561,7 +565,9 @@
         int32_t targetFlags;
         float xOffset;
         float yOffset;
-        float scaleFactor;
+        float globalScaleFactor;
+        float windowXScale = 1.0f;
+        float windowYScale = 1.0f;
         nsecs_t deliveryTime; // time when the event was actually delivered
 
         // Set to the resolved action and flags when the event is enqueued.
@@ -569,7 +575,8 @@
         int32_t resolvedFlags;
 
         DispatchEntry(EventEntry* eventEntry,
-                int32_t targetFlags, float xOffset, float yOffset, float scaleFactor);
+                int32_t targetFlags, float xOffset, float yOffset,
+                float globalScaleFactor, float windowXScale, float windowYScale);
         ~DispatchEntry();
 
         inline bool hasForegroundTarget() const {
@@ -622,6 +629,7 @@
         uint32_t seq;
         bool handled;
         sp<InputChannel> inputChannel;
+        sp<IBinder> token;
     };
 
     // Generic queue implementation.
@@ -916,6 +924,13 @@
     // All registered connections mapped by channel file descriptor.
     KeyedVector<int, sp<Connection> > mConnectionsByFd;
 
+    struct IBinderHash {
+        std::size_t operator()(const sp<IBinder>& b) const {
+            return std::hash<IBinder *>{}(b.get());
+        }
+    };
+    std::unordered_map<sp<IBinder>, sp<InputChannel>, IBinderHash> mInputChannelsByToken;
+
     ssize_t getConnectionIndexLocked(const sp<InputChannel>& inputChannel);
 
     // Input channels that will receive a copy of all input events sent to the provided display.
@@ -979,6 +994,7 @@
     // Get window handles by display, return an empty vector if not found.
     Vector<sp<InputWindowHandle>> getWindowHandlesLocked(int32_t displayId) const;
     sp<InputWindowHandle> getWindowHandleLocked(const sp<InputChannel>& inputChannel) const;
+    sp<InputChannel> getInputChannelLocked(const sp<IBinder>& windowToken) const;
     bool hasWindowHandleLocked(const sp<InputWindowHandle>& windowHandle) const;
 
     // Focus tracking for keys, trackball, etc.
@@ -1051,7 +1067,7 @@
     nsecs_t mInputTargetWaitStartTime;
     nsecs_t mInputTargetWaitTimeoutTime;
     bool mInputTargetWaitTimeoutExpired;
-    sp<InputApplicationHandle> mInputTargetWaitApplicationHandle;
+    sp<IBinder> mInputTargetWaitApplicationToken;
 
     // Contains the last window which received a hover event.
     sp<InputWindowHandle> mLastHoverWindowHandle;
@@ -1143,6 +1159,7 @@
             nsecs_t currentTime, const sp<Connection>& connection, uint32_t seq, bool handled);
     void onDispatchCycleBrokenLocked(
             nsecs_t currentTime, const sp<Connection>& connection);
+    void onFocusChangedLocked(const sp<InputWindowHandle>& newFocus);
     void onANRLocked(
             nsecs_t currentTime, const sp<InputApplicationHandle>& applicationHandle,
             const sp<InputWindowHandle>& windowHandle,
@@ -1151,6 +1168,7 @@
     // Outbound policy interactions.
     void doNotifyConfigurationChangedInterruptible(CommandEntry* commandEntry);
     void doNotifyInputChannelBrokenLockedInterruptible(CommandEntry* commandEntry);
+    void doNotifyFocusChangedLockedInterruptible(CommandEntry* commandEntry);
     void doNotifyANRLockedInterruptible(CommandEntry* commandEntry);
     void doInterceptKeyBeforeDispatchingLockedInterruptible(CommandEntry* commandEntry);
     void doDispatchCycleFinishedLockedInterruptible(CommandEntry* commandEntry);
diff --git a/services/inputflinger/InputManager.cpp b/services/inputflinger/InputManager.cpp
index 388423c..15d8070 100644
--- a/services/inputflinger/InputManager.cpp
+++ b/services/inputflinger/InputManager.cpp
@@ -21,9 +21,13 @@
 #include "InputManager.h"
 #include "InputReaderFactory.h"
 
+#include <binder/IPCThreadState.h>
+
 #include <log/log.h>
 #include <unordered_map>
 
+#include <private/android_filesystem_config.h>
+
 namespace android {
 
 InputManager::InputManager(
@@ -83,20 +87,9 @@
     return mDispatcher;
 }
 
-class BinderApplicationHandle : public InputApplicationHandle {
-public:
-    BinderApplicationHandle() = default;
-
-    bool updateInfo() override {
-        return true;
-    }
-};
-
 class BinderWindowHandle : public InputWindowHandle {
 public:
-    BinderWindowHandle(const InputWindowInfo& info) :
-        InputWindowHandle(new BinderApplicationHandle()) {
-
+    BinderWindowHandle(const InputWindowInfo& info) {
         mInfo = info;
     }
 
@@ -118,4 +111,20 @@
     }
 }
 
+// Used by tests only.
+void InputManager::registerInputChannel(const sp<InputChannel>& channel) {
+    IPCThreadState* ipc = IPCThreadState::self();
+    const int uid = ipc->getCallingUid();
+    if (uid != AID_SHELL && uid != AID_ROOT) {
+        ALOGE("Invalid attempt to register input channel over IPC"
+                "from non shell/root entity (PID: %d)", ipc->getCallingPid());
+        return;
+    }
+    mDispatcher->registerInputChannel(channel, false);
+}
+
+void InputManager::unregisterInputChannel(const sp<InputChannel>& channel) {
+    mDispatcher->unregisterInputChannel(channel);
+}
+
 } // namespace android
diff --git a/services/inputflinger/InputManager.h b/services/inputflinger/InputManager.h
index 1173fa1..8f7551e 100644
--- a/services/inputflinger/InputManager.h
+++ b/services/inputflinger/InputManager.h
@@ -35,6 +35,7 @@
 #include <utils/RefBase.h>
 
 namespace android {
+class InputChannel;
 
 /*
  * The input manager is the core of the system event processing.
@@ -91,6 +92,9 @@
 
     virtual void setInputWindows(const Vector<InputWindowInfo>& handles);
 
+    virtual void registerInputChannel(const sp<InputChannel>& channel);
+    virtual void unregisterInputChannel(const sp<InputChannel>& channel);
+
 private:
     sp<InputReaderInterface> mReader;
     sp<InputReaderThread> mReaderThread;
diff --git a/services/inputflinger/host/Android.bp b/services/inputflinger/host/Android.bp
index 0e48f24..cbe0190 100644
--- a/services/inputflinger/host/Android.bp
+++ b/services/inputflinger/host/Android.bp
@@ -62,6 +62,4 @@
     static_libs: [
         "libarect",
     ],
-
-    init_rc: ["inputflinger.rc"],
 }
diff --git a/services/inputflinger/host/InputFlinger.h b/services/inputflinger/host/InputFlinger.h
index 15ca7b3..82ff089 100644
--- a/services/inputflinger/host/InputFlinger.h
+++ b/services/inputflinger/host/InputFlinger.h
@@ -40,6 +40,8 @@
 
     virtual status_t dump(int fd, const Vector<String16>& args);
     void setInputWindows(const Vector<InputWindowInfo>&) {}
+    void registerInputChannel(const sp<InputChannel>&) {}
+    void unregisterInputChannel(const sp<InputChannel>&) {}
 
 private:
     virtual ~InputFlinger();
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index e860db5..26f01b7 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -63,6 +63,9 @@
     virtual void notifyInputChannelBroken(const sp<IBinder>&) {
     }
 
+    virtual void notifyFocusChanged(const sp<IBinder>&) {
+    }
+
     virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) {
         *outConfig = mConfig;
     }
@@ -338,7 +341,6 @@
             const std::string name, int32_t displayId) :
                 mDispatcher(dispatcher), mName(name), mDisplayId(displayId) {
             InputChannel::openInputChannelPair(name, mServerChannel, mClientChannel);
-
             mConsumer = new InputConsumer(mClientChannel);
         }
 
@@ -352,6 +354,7 @@
 
         sp<InputDispatcher> mDispatcher;
         sp<InputChannel> mServerChannel, mClientChannel;
+        sp<IBinder> mToken;
         InputConsumer *mConsumer;
         PreallocatedInputEventFactory mEventFactory;
 
@@ -366,15 +369,17 @@
 
     FakeWindowHandle(const sp<InputApplicationHandle>& inputApplicationHandle,
         const sp<InputDispatcher>& dispatcher, const std::string name, int32_t displayId) :
-            InputWindowHandle(inputApplicationHandle),
             FakeInputReceiver(dispatcher, name, displayId),
             mFocused(false) {
             mServerChannel->setToken(new BBinder());
             mDispatcher->registerInputChannel(mServerChannel, displayId);
+ 
+            inputApplicationHandle->updateInfo();
+            mInfo.applicationInfo = *inputApplicationHandle->getInfo();
     }
 
     virtual bool updateInfo() {
-        mInfo.inputChannel = mServerChannel;
+        mInfo.token = mServerChannel->getToken();
         mInfo.name = mName;
         mInfo.layoutParamsFlags = 0;
         mInfo.layoutParamsType = InputWindowInfo::TYPE_APPLICATION;
@@ -383,7 +388,7 @@
         mInfo.frameTop = 0;
         mInfo.frameRight = WIDTH;
         mInfo.frameBottom = HEIGHT;
-        mInfo.scaleFactor = 1.0;
+        mInfo.globalScaleFactor = 1.0;
         mInfo.addTouchableRegion(Rect(0, 0, WIDTH, HEIGHT));
         mInfo.visible = true;
         mInfo.canReceiveKeys = true;
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 088c256..1007b3d 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -54,6 +54,7 @@
         "libsync",
         "libtimestats_proto",
         "libui",
+        "libinput",
         "libutils",
     ],
     static_libs: [
@@ -183,6 +184,7 @@
         "libdisplayservicehidl",
         "libhidlbase",
         "libhidltransport",
+        "libinput",
         "liblayers_proto",
         "liblog",
         "libsync",
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index f3182be..6ac0901 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -1057,6 +1057,11 @@
         clearSyncPoints();
     }
 
+    if (mCurrentState.inputInfoChanged) {
+        flags |= eInputInfoChanged;
+        mCurrentState.inputInfoChanged = false;
+    }
+
     // Commit the transaction
     commitTransaction(c);
     mCurrentState.callbackHandles = {};
@@ -1928,6 +1933,13 @@
     mDrawingParent = mCurrentParent;
 }
 
+void Layer::setInputInfo(const InputWindowInfo& info) {
+    mCurrentState.inputInfo = info;
+    mCurrentState.modified = true;
+    mCurrentState.inputInfoChanged = true;
+    setTransactionFlags(eTransactionNeeded);
+}
+
 void Layer::writeToProto(LayerProto* layerInfo, LayerVector::StateSet stateSet) {
     const bool useDrawing = stateSet == LayerVector::StateSet::Drawing;
     const LayerVector& children = useDrawing ? mDrawingChildren : mCurrentChildren;
@@ -2055,6 +2067,30 @@
     return mRemovedFromCurrentState;
 }
 
+InputWindowInfo Layer::fillInputInfo(const Rect& screenBounds) {
+    InputWindowInfo info = mDrawingState.inputInfo;
+    info.frameLeft = screenBounds.left + info.surfaceInset;
+    info.frameTop = screenBounds.top + info.surfaceInset;
+    info.frameRight = screenBounds.right - info.surfaceInset;
+    info.frameBottom = screenBounds.bottom - info.surfaceInset;
+
+    ui::Transform t = getTransform();
+    info.windowXScale *= 1.0f / t.sx();
+    info.windowYScale *= 1.0f / t.sy();
+
+    info.touchableRegion.scaleSelf(t.sx(), t.sy());
+
+    info.touchableRegion = info.touchableRegion.translate(
+            screenBounds.left,
+            screenBounds.top);
+    info.visible = isVisible();
+    return info;
+}
+
+bool Layer::hasInput() const {
+    return mDrawingState.inputInfo.token != nullptr;
+}
+
 // ---------------------------------------------------------------------------
 
 }; // namespace android
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index ed51c61..fe8d5a9 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -22,6 +22,7 @@
 #include <gui/BufferQueue.h>
 #include <gui/ISurfaceComposerClient.h>
 #include <gui/LayerState.h>
+#include <input/InputWindow.h>
 #include <layerproto/LayerProtoHeader.h>
 #include <math/vec4.h>
 #include <renderengine/Mesh.h>
@@ -109,6 +110,7 @@
     enum { // flags for doTransaction()
         eDontUpdateGeometryState = 0x00000001,
         eVisibleRegion = 0x00000002,
+        eInputInfoChanged = 0x00000004
     };
 
     struct Geometry {
@@ -166,6 +168,9 @@
 
         half4 color;
 
+        bool inputInfoChanged;
+        InputWindowInfo inputInfo;
+
         // The fields below this point are only used by BufferStateLayer
         Geometry active;
 
@@ -708,6 +713,10 @@
     bool getPremultipledAlpha() const;
 
     bool mPendingHWCDestroy{false};
+    void setInputInfo(const InputWindowInfo& info);
+
+    InputWindowInfo fillInputInfo(const Rect& screenBounds);
+    bool hasInput() const;
 
 protected:
     // -----------------------------------------------------------------------
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 8e694fd..1db8791 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -37,6 +37,8 @@
 
 #include <dvr/vr_flinger.h>
 
+#include <input/IInputFlinger.h>
+
 #include <ui/ColorSpace.h>
 #include <ui/DebugUtils.h>
 #include <ui/DisplayInfo.h>
@@ -554,6 +556,13 @@
     if (window != 0) {
         window->linkToDeath(static_cast<IBinder::DeathRecipient*>(this));
     }
+    sp<IBinder> input(defaultServiceManager()->getService(
+            String16("inputflinger")));
+    if (input == nullptr) {
+        ALOGE("Failed to link to input service");
+    } else {
+        mInputFlinger = interface_cast<IInputFlinger>(input);
+    }
 
     if (mVrFlinger) {
       mVrFlinger->OnBootFinished();
@@ -2573,6 +2582,7 @@
      * (perform the transaction for each of them if needed)
      */
 
+    bool inputChanged = false;
     if (transactionFlags & eTraversalNeeded) {
         mCurrentState.traverseInZOrder([&](Layer* layer) {
             uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded);
@@ -2581,6 +2591,10 @@
             const uint32_t flags = layer->doTransaction(0);
             if (flags & Layer::eVisibleRegion)
                 mVisibleRegionsDirty = true;
+
+            if (flags & Layer::eInputInfoChanged) {
+                inputChanged = true;
+            }
         });
     }
 
@@ -2690,9 +2704,26 @@
 
     commitTransaction();
 
+    if ((inputChanged || mVisibleRegionsDirty) && mInputFlinger) {
+        updateInputWindows();
+    }
+
     updateCursorAsync();
 }
 
+void SurfaceFlinger::updateInputWindows() {
+    ATRACE_CALL();
+
+    Vector<InputWindowInfo> inputHandles;
+
+    mDrawingState.traverseInReverseZOrder([&](Layer* layer) {
+        if (layer->hasInput()) {
+            inputHandles.add(layer->fillInputInfo(layer->computeScreenBounds()));
+        }
+    });
+    mInputFlinger->setInputWindows(inputHandles);
+}
+
 void SurfaceFlinger::updateCursorAsync()
 {
     for (const auto& [token, display] : mDisplays) {
@@ -2800,6 +2831,7 @@
         if (CC_LIKELY(layer->isVisible())) {
             const bool translucent = !layer->isOpaque(s);
             Rect bounds(layer->computeScreenBounds());
+
             visibleRegion.set(bounds);
             ui::Transform tr = layer->getTransform();
             if (!visibleRegion.isEmpty()) {
@@ -3615,7 +3647,10 @@
     if (what & layer_state_t::eSidebandStreamChanged) {
         if (layer->setSidebandStream(s.sidebandStream)) flags |= eTraversalNeeded;
     }
-
+    if (what & layer_state_t::eInputInfoChanged) {
+        layer->setInputInfo(s.inputInfo);
+        flags |= eTraversalNeeded;
+    }
     std::vector<sp<CallbackHandle>> callbackHandles;
     if ((what & layer_state_t::eListenerCallbacksChanged) && (!s.listenerCallbacks.empty())) {
         mTransactionCompletedThread.run();
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index f98dddf..4a14de7 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -98,6 +98,7 @@
 class EventThread;
 class IGraphicBufferConsumer;
 class IGraphicBufferProducer;
+class IInputFlinger;
 class InjectVSyncSource;
 class Layer;
 class Surface;
@@ -531,6 +532,7 @@
     void handleTransaction(uint32_t transactionFlags);
     void handleTransactionLocked(uint32_t transactionFlags);
 
+    void updateInputWindows();
     void updateCursorAsync();
 
     /* handlePageFlip - latch a new buffer if available and compute the dirty
@@ -986,6 +988,8 @@
     std::unique_ptr<Scheduler> mScheduler;
     sp<Scheduler::ConnectionHandle> mAppConnectionHandle;
     sp<Scheduler::ConnectionHandle> mSfConnectionHandle;
+
+    sp<IInputFlinger> mInputFlinger;
 };
 }; // namespace android