resolved conflicts for merge of ca2b552d to master

Change-Id: I2f3693a59042ac5aa2d7bcdc3a504c78dc99a18b
diff --git a/api/current.txt b/api/current.txt
index 7b2b392..64ce71f 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -97,6 +97,7 @@
     field public static final java.lang.String SET_ANIMATION_SCALE = "android.permission.SET_ANIMATION_SCALE";
     field public static final java.lang.String SET_DEBUG_APP = "android.permission.SET_DEBUG_APP";
     field public static final java.lang.String SET_ORIENTATION = "android.permission.SET_ORIENTATION";
+    field public static final java.lang.String SET_POINTER_SPEED = "android.permission.SET_POINTER_SPEED";
     field public static final deprecated java.lang.String SET_PREFERRED_APPLICATIONS = "android.permission.SET_PREFERRED_APPLICATIONS";
     field public static final java.lang.String SET_PROCESS_LIMIT = "android.permission.SET_PROCESS_LIMIT";
     field public static final java.lang.String SET_TIME = "android.permission.SET_TIME";
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index c78b935..893947d 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1809,6 +1809,16 @@
         public static final String SIP_ASK_ME_EACH_TIME = "SIP_ASK_ME_EACH_TIME";
 
         /**
+         * Pointer speed setting.
+         * This is an integer value in a range between -7 and +7, so there are 15 possible values.
+         *   -7 = slowest
+         *    0 = default speed
+         *   +7 = fastest
+         * @hide
+         */
+        public static final String POINTER_SPEED = "pointer_speed";
+
+        /**
          * Settings to backup. This is here so that it's in the same place as the settings
          * keys and easy to update.
          * @hide
@@ -1872,6 +1882,7 @@
             USE_PTP_INTERFACE,
             SIP_CALL_OPTIONS,
             SIP_RECEIVE_CALLS,
+            POINTER_SPEED,
         };
 
         // Settings moved to Settings.Secure
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 4427eb5..ad17edf 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -205,4 +205,9 @@
      * Called by the status bar to notify Views of changes to System UI visiblity.
      */
     void statusBarVisibilityChanged(int visibility);
+
+    /**
+     * Called by the settings application to temporarily set the pointer speed.
+     */
+    void setPointerSpeed(int speed);
 }
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 419578c..110268e 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1098,6 +1098,13 @@
         android:description="@string/permdesc_setOrientation"
         android:protectionLevel="signature" />
 
+    <!-- Allows low-level access to setting the pointer speed.
+         Not for use by normal applications. -->
+    <permission android:name="android.permission.SET_POINTER_SPEED"
+        android:label="@string/permlab_setPointerSpeed"
+        android:description="@string/permdesc_setPointerSpeed"
+        android:protectionLevel="signature" />
+
     <!-- Allows an application to install packages. -->
     <permission android:name="android.permission.INSTALL_PACKAGES"
         android:label="@string/permlab_installPackages"
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index a277c74..8a4b74b 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -711,6 +711,13 @@
         the rotation of the screen at any time. Should never be needed for
         normal applications.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=30] -->
+    <string name="permlab_setPointerSpeed">change pointer speed</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=NONE] -->
+    <string name="permdesc_setPointerSpeed">Allows an application to change
+        the mouse or trackpad pointer speed at any time. Should never be needed for
+        normal applications.</string>
+
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_signalPersistentProcesses">send Linux signals to applications</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index bf06f947..2e2768f 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -125,4 +125,7 @@
     <!-- Default for Settings.Secure.LONG_PRESS_TIMEOUT_MILLIS -->
     <integer name="def_long_press_timeout_millis">500</integer>
 
+    <!-- Default for Settings.System.POINTER_SPEED -->
+    <integer name="def_pointer_speed">0</integer>
+
 </resources>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index b99c8b0..0f5f095 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -1214,6 +1214,9 @@
             loadBooleanSetting(stmt, Settings.System.NOTIFICATIONS_USE_RING_VOLUME,
                     R.bool.def_notifications_use_ring_volume);
 
+            loadIntegerSetting(stmt, Settings.System.POINTER_SPEED,
+                    R.integer.def_pointer_speed);
+
         } finally {
             if (stmt != null) stmt.close();
         }
diff --git a/services/input/EventHub.cpp b/services/input/EventHub.cpp
index af30887..29add52 100644
--- a/services/input/EventHub.cpp
+++ b/services/input/EventHub.cpp
@@ -33,6 +33,7 @@
 
 #include <hardware_legacy/power.h>
 
+#include <cutils/atomic.h>
 #include <cutils/properties.h>
 #include <utils/Log.h>
 #include <utils/Timers.h>
@@ -128,6 +129,7 @@
         mError(NO_INIT), mBuiltInKeyboardId(-1), mNextDeviceId(1),
         mOpeningDevices(0), mClosingDevices(0),
         mOpened(false), mNeedToSendFinishedDeviceScan(false),
+        mNeedToReopenDevices(0), mNeedToScanDevices(false),
         mInputFdIndex(1) {
     acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
 
@@ -393,12 +395,10 @@
     return NAME_NOT_FOUND;
 }
 
-void EventHub::addExcludedDevice(const char* deviceName)
-{
+void EventHub::setExcludedDevices(const Vector<String8>& devices) {
     AutoMutex _l(mLock);
 
-    String8 name(deviceName);
-    mExcludedDevices.push_back(name);
+    mExcludedDevices = devices;
 }
 
 bool EventHub::hasLed(int32_t deviceId, int32_t led) const {
@@ -466,9 +466,11 @@
     LOG_ASSERT(bufferSize >= 1);
 
     if (!mOpened) {
+        android_atomic_acquire_store(0, &mNeedToReopenDevices);
+
         mError = openPlatformInput() ? NO_ERROR : UNKNOWN_ERROR;
         mOpened = true;
-        mNeedToSendFinishedDeviceScan = true;
+        mNeedToScanDevices = true;
     }
 
     struct input_event readBuffer[bufferSize];
@@ -478,6 +480,20 @@
     for (;;) {
         nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
 
+        // Reopen input devices if needed.
+        if (android_atomic_acquire_load(&mNeedToReopenDevices)) {
+            android_atomic_acquire_store(0, &mNeedToReopenDevices);
+
+            LOGI("Reopening all input devices due to a configuration change.");
+
+            AutoMutex _l(mLock);
+            while (mDevices.size() > 1) {
+                closeDeviceAtIndexLocked(mDevices.size() - 1);
+            }
+            mNeedToScanDevices = true;
+            break; // return to the caller before we actually rescan
+        }
+
         // Report any devices that had last been added/removed.
         while (mClosingDevices) {
             Device* device = mClosingDevices;
@@ -495,6 +511,12 @@
             }
         }
 
+        if (mNeedToScanDevices) {
+            mNeedToScanDevices = false;
+            scanDevices();
+            mNeedToSendFinishedDeviceScan = true;
+        }
+
         while (mOpeningDevices != NULL) {
             Device* device = mOpeningDevices;
             LOGV("Reporting device opened: id=%d, name=%s\n",
@@ -696,13 +718,14 @@
     pollfd.revents = 0;
     mFds.push(pollfd);
     mDevices.push(NULL);
+    return true;
+}
 
-    res = scanDir(DEVICE_PATH);
+void EventHub::scanDevices() {
+    int res = scanDir(DEVICE_PATH);
     if(res < 0) {
         LOGE("scan dir failed for %s\n", DEVICE_PATH);
     }
-
-    return true;
 }
 
 // ----------------------------------------------------------------------------
@@ -755,12 +778,10 @@
     }
 
     // Check to see if the device is on our excluded list
-    List<String8>::iterator iter = mExcludedDevices.begin();
-    List<String8>::iterator end = mExcludedDevices.end();
-    for ( ; iter != end; iter++) {
-        const char* test = *iter;
-        if (identifier.name == test) {
-            LOGI("ignoring event id %s driver %s\n", devicePath, test);
+    for (size_t i = 0; i < mExcludedDevices.size(); i++) {
+        const String8& item = mExcludedDevices.itemAt(i);
+        if (identifier.name == item) {
+            LOGI("ignoring event id %s driver %s\n", devicePath, item.string());
             close(fd);
             return -1;
         }
@@ -1223,6 +1244,10 @@
     return 0;
 }
 
+void EventHub::reopenDevices() {
+    android_atomic_release_store(1, &mNeedToReopenDevices);
+}
+
 void EventHub::dump(String8& dump) {
     dump.append("Event Hub State:\n");
 
diff --git a/services/input/EventHub.h b/services/input/EventHub.h
index ca33619..558959b 100644
--- a/services/input/EventHub.h
+++ b/services/input/EventHub.h
@@ -193,9 +193,9 @@
     virtual status_t mapAxis(int32_t deviceId, int scancode,
             AxisInfo* outAxisInfo) const = 0;
 
-    // exclude a particular device from opening
-    // this can be used to ignore input devices for sensors
-    virtual void addExcludedDevice(const char* deviceName) = 0;
+    // Sets devices that are excluded from opening.
+    // This can be used to ignore input devices for sensors.
+    virtual void setExcludedDevices(const Vector<String8>& devices) = 0;
 
     /*
      * Wait for events to become available and returns them.
@@ -230,6 +230,8 @@
     virtual void getVirtualKeyDefinitions(int32_t deviceId,
             Vector<VirtualKeyDefinition>& outVirtualKeys) const = 0;
 
+    virtual void reopenDevices() = 0;
+
     virtual void dump(String8& dump) = 0;
 };
 
@@ -259,7 +261,7 @@
     virtual status_t mapAxis(int32_t deviceId, int scancode,
             AxisInfo* outAxisInfo) const;
 
-    virtual void addExcludedDevice(const char* deviceName);
+    virtual void setExcludedDevices(const Vector<String8>& devices);
 
     virtual int32_t getScanCodeState(int32_t deviceId, int32_t scanCode) const;
     virtual int32_t getKeyCodeState(int32_t deviceId, int32_t keyCode) const;
@@ -276,6 +278,8 @@
     virtual void getVirtualKeyDefinitions(int32_t deviceId,
             Vector<VirtualKeyDefinition>& outVirtualKeys) const;
 
+    virtual void reopenDevices();
+
     virtual void dump(String8& dump);
 
 protected:
@@ -288,6 +292,7 @@
     int closeDevice(const char *devicePath);
     int closeDeviceAtIndexLocked(int index);
     int scanDir(const char *dirname);
+    void scanDevices();
     int readNotify(int nfd);
 
     status_t mError;
@@ -351,7 +356,9 @@
 
     bool mOpened;
     bool mNeedToSendFinishedDeviceScan;
-    List<String8> mExcludedDevices;
+    volatile int32_t mNeedToReopenDevices; // must be modified atomically
+    bool mNeedToScanDevices;
+    Vector<String8> mExcludedDevices;
 
     // device ids that report particular switches.
     int32_t mSwitches[SW_MAX + 1];
diff --git a/services/input/InputReader.cpp b/services/input/InputReader.cpp
index 8c9bad8..2924d3e 100644
--- a/services/input/InputReader.cpp
+++ b/services/input/InputReader.cpp
@@ -38,6 +38,7 @@
 
 #include "InputReader.h"
 
+#include <cutils/atomic.h>
 #include <cutils/log.h>
 #include <ui/Keyboard.h>
 #include <ui/VirtualKeyMap.h>
@@ -260,10 +261,9 @@
         const sp<InputReaderPolicyInterface>& policy,
         const sp<InputDispatcherInterface>& dispatcher) :
         mEventHub(eventHub), mPolicy(policy), mDispatcher(dispatcher),
-        mGlobalMetaState(0), mDisableVirtualKeysTimeout(LLONG_MIN), mNextTimeout(LLONG_MAX) {
-    mPolicy->getReaderConfiguration(&mConfig);
-
-    configureExcludedDevices();
+        mGlobalMetaState(0), mDisableVirtualKeysTimeout(LLONG_MIN), mNextTimeout(LLONG_MAX),
+        mRefreshConfiguration(0) {
+    configure(true /*firstTime*/);
     updateGlobalMetaState();
     updateInputConfiguration();
 }
@@ -275,6 +275,11 @@
 }
 
 void InputReader::loopOnce() {
+    if (android_atomic_acquire_load(&mRefreshConfiguration)) {
+        android_atomic_release_store(0, &mRefreshConfiguration);
+        configure(false /*firstTime*/);
+    }
+
     int32_t timeoutMillis = -1;
     if (mNextTimeout != LLONG_MAX) {
         nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
@@ -495,9 +500,12 @@
     mDispatcher->notifyConfigurationChanged(when);
 }
 
-void InputReader::configureExcludedDevices() {
-    for (size_t i = 0; i < mConfig.excludedDeviceNames.size(); i++) {
-        mEventHub->addExcludedDevice(mConfig.excludedDeviceNames[i]);
+void InputReader::configure(bool firstTime) {
+    mPolicy->getReaderConfiguration(&mConfig);
+    mEventHub->setExcludedDevices(mConfig.excludedDeviceNames);
+
+    if (!firstTime) {
+        mEventHub->reopenDevices();
     }
 }
 
@@ -718,6 +726,10 @@
     } // release device registy reader lock
 }
 
+void InputReader::refreshConfiguration() {
+    android_atomic_release_store(1, &mRefreshConfiguration);
+}
+
 void InputReader::dump(String8& dump) {
     mEventHub->dump(dump);
     dump.append("\n");
diff --git a/services/input/InputReader.h b/services/input/InputReader.h
index 5abf404..1d4ad87 100644
--- a/services/input/InputReader.h
+++ b/services/input/InputReader.h
@@ -145,7 +145,7 @@
             pointerGestureMultitouchMinSpeed(150.0f), // 150 pixels per second
             pointerGestureSwipeTransitionAngleCosine(0.5f), // cosine of 45degrees
             pointerGestureSwipeMaxWidthRatio(0.333f),
-            pointerGestureMovementSpeedRatio(0.5f),
+            pointerGestureMovementSpeedRatio(0.3f),
             pointerGestureZoomSpeedRatio(0.3f) { }
 };
 
@@ -234,6 +234,9 @@
     /* Determine whether physical keys exist for the given framework-domain key codes. */
     virtual bool hasKeys(int32_t deviceId, uint32_t sourceMask,
             size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) = 0;
+
+    /* Reopens and reconfigures all input devices. */
+    virtual void refreshConfiguration() = 0;
 };
 
 
@@ -298,6 +301,8 @@
     virtual bool hasKeys(int32_t deviceId, uint32_t sourceMask,
             size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags);
 
+    virtual void refreshConfiguration();
+
 protected:
     // These methods are protected virtual so they can be overridden and instrumented
     // by test cases.
@@ -339,18 +344,17 @@
     void timeoutExpired(nsecs_t when);
 
     void handleConfigurationChanged(nsecs_t when);
-    void configureExcludedDevices();
 
     // state management for all devices
     Mutex mStateLock;
 
-    int32_t mGlobalMetaState;
+    int32_t mGlobalMetaState; // guarded by mStateLock
     virtual void updateGlobalMetaState();
     virtual int32_t getGlobalMetaState();
 
     virtual void fadePointer();
 
-    InputConfiguration mInputConfiguration;
+    InputConfiguration mInputConfiguration; // guarded by mStateLock
     void updateInputConfiguration();
 
     nsecs_t mDisableVirtualKeysTimeout; // only accessed by reader thread
@@ -358,9 +362,12 @@
     virtual bool shouldDropVirtualKey(nsecs_t now,
             InputDevice* device, int32_t keyCode, int32_t scanCode);
 
-    nsecs_t mNextTimeout; // only accessed by reader thread
+    nsecs_t mNextTimeout; // only accessed by reader thread, not guarded
     virtual void requestTimeoutAtTime(nsecs_t when);
 
+    volatile int32_t mRefreshConfiguration; // atomic
+    void configure(bool firstTime);
+
     // state queries
     typedef int32_t (InputDevice::*GetStateFunc)(uint32_t sourceMask, int32_t code);
     int32_t getState(int32_t deviceId, uint32_t sourceMask, int32_t code,
diff --git a/services/input/tests/InputReader_test.cpp b/services/input/tests/InputReader_test.cpp
index 3a1beb6..00b4222 100644
--- a/services/input/tests/InputReader_test.cpp
+++ b/services/input/tests/InputReader_test.cpp
@@ -629,8 +629,8 @@
         return NAME_NOT_FOUND;
     }
 
-    virtual void addExcludedDevice(const char* deviceName) {
-        mExcludedDevices.add(String8(deviceName));
+    virtual void setExcludedDevices(const Vector<String8>& devices) {
+        mExcludedDevices = devices;
     }
 
     virtual size_t getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
@@ -728,6 +728,9 @@
 
     virtual void dump(String8& dump) {
     }
+
+    virtual void reopenDevices() {
+    }
 };
 
 
diff --git a/services/java/com/android/server/wm/InputManager.java b/services/java/com/android/server/wm/InputManager.java
index d13cc63..3095c37 100644
--- a/services/java/com/android/server/wm/InputManager.java
+++ b/services/java/com/android/server/wm/InputManager.java
@@ -23,10 +23,14 @@
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.content.res.Configuration;
+import android.database.ContentObserver;
 import android.os.Environment;
+import android.os.Handler;
 import android.os.Looper;
 import android.os.MessageQueue;
 import android.os.SystemProperties;
+import android.provider.Settings;
+import android.provider.Settings.SettingNotFoundException;
 import android.util.Slog;
 import android.util.Xml;
 import android.view.InputChannel;
@@ -57,7 +61,7 @@
     private final Callbacks mCallbacks;
     private final Context mContext;
     private final WindowManagerService mWindowManagerService;
-    
+
     private static native void nativeInit(Context context,
             Callbacks callbacks, MessageQueue messageQueue);
     private static native void nativeStart();
@@ -88,6 +92,7 @@
     private static native int[] nativeGetInputDeviceIds();
     private static native boolean nativeTransferTouchFocus(InputChannel fromChannel,
             InputChannel toChannel);
+    private static native void nativeSetPointerSpeed(int speed);
     private static native String nativeDump();
     
     // Input event injection constants defined in InputDispatcher.h.
@@ -131,10 +136,13 @@
         Slog.i(TAG, "Initializing input manager");
         nativeInit(mContext, mCallbacks, looper.getQueue());
     }
-    
+
     public void start() {
         Slog.i(TAG, "Starting input manager");
         nativeStart();
+
+        registerPointerSpeedSettingObserver();
+        updatePointerSpeedFromSettings();
     }
     
     public void setDisplaySize(int displayId, int width, int height) {
@@ -403,6 +411,42 @@
         return nativeTransferTouchFocus(fromChannel, toChannel);
     }
 
+    /**
+     * Set the pointer speed.
+     * @param speed The pointer speed as a value between -7 (slowest) and 7 (fastest)
+     * where 0 is the default speed.
+     */
+    public void setPointerSpeed(int speed) {
+        speed = Math.min(Math.max(speed, -7), 7);
+        nativeSetPointerSpeed(speed);
+    }
+
+    public void updatePointerSpeedFromSettings() {
+        int speed = getPointerSpeedSetting(0);
+        setPointerSpeed(speed);
+    }
+
+    private void registerPointerSpeedSettingObserver() {
+        mContext.getContentResolver().registerContentObserver(
+                Settings.System.getUriFor(Settings.System.POINTER_SPEED), true,
+                new ContentObserver(mWindowManagerService.mH) {
+                    @Override
+                    public void onChange(boolean selfChange) {
+                        updatePointerSpeedFromSettings();
+                    }
+                });
+    }
+
+    private int getPointerSpeedSetting(int defaultValue) {
+        int speed = defaultValue;
+        try {
+            speed = Settings.System.getInt(mContext.getContentResolver(),
+                    Settings.System.POINTER_SPEED);
+        } catch (SettingNotFoundException snfe) {
+        }
+        return speed;
+    }
+
     public void dump(PrintWriter pw) {
         String dumpStr = nativeDump();
         if (dumpStr != null) {
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 080ba35..d95d4c5 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -5951,6 +5951,19 @@
         }
     }
 
+    /**
+     * Temporarily set the pointer speed.  Does not save the new setting.
+     * Used by the settings application.
+     */
+    public void setPointerSpeed(int speed) {
+        if (!checkCallingPermission(android.Manifest.permission.SET_POINTER_SPEED,
+                "setPointerSpeed()")) {
+            throw new SecurityException("Requires SET_POINTER_SPEED permission");
+        }
+
+        mInputManager.setPointerSpeed(speed);
+    }
+
     private WindowState getFocusedWindow() {
         synchronized (mWindowMap) {
             return getFocusedWindowLocked();
diff --git a/services/jni/com_android_server_InputManager.cpp b/services/jni/com_android_server_InputManager.cpp
index 0ee3217..881882f 100644
--- a/services/jni/com_android_server_InputManager.cpp
+++ b/services/jni/com_android_server_InputManager.cpp
@@ -53,6 +53,11 @@
 
 namespace android {
 
+// The exponent used to calculate the pointer speed scaling factor.
+// The scaling factor is calculated as 2 ^ (speed * exponent),
+// where the speed ranges from -7 to + 7 and is supplied by the user.
+static const float POINTER_SPEED_EXPONENT = 1.0f / 3;
+
 static struct {
     jmethodID notifyConfigurationChanged;
     jmethodID notifyLidSwitchChanged;
@@ -176,6 +181,7 @@
     void setFocusedApplication(JNIEnv* env, jobject applicationObj);
     void setInputDispatchMode(bool enabled, bool frozen);
     void setSystemUiVisibility(int32_t visibility);
+    void setPointerSpeed(int32_t speed);
 
     /* --- InputReaderPolicyInterface implementation --- */
 
@@ -225,6 +231,9 @@
         // System UI visibility.
         int32_t systemUiVisibility;
 
+        // Pointer speed.
+        int32_t pointerSpeed;
+
         // Sprite controller singleton, created on first use.
         sp<SpriteController> spriteController;
 
@@ -264,6 +273,7 @@
         mLocked.displayOrientation = ROTATION_0;
 
         mLocked.systemUiVisibility = ASYSTEM_UI_VISIBILITY_STATUS_BAR_VISIBLE;
+        mLocked.pointerSpeed = 0;
     }
 
     sp<EventHub> eventHub = new EventHub();
@@ -427,6 +437,13 @@
     if (!checkAndClearExceptionFromCallback(env, "getTouchSlop")) {
         outConfig->pointerGestureTapSlop = touchSlop;
     }
+
+    { // acquire lock
+        AutoMutex _l(mLock);
+
+        outConfig->pointerVelocityControlParameters.scale = exp2f(mLocked.pointerSpeed
+                * POINTER_SPEED_EXPONENT);
+    } // release lock
 }
 
 sp<PointerControllerInterface> NativeInputManager::obtainPointerController(int32_t deviceId) {
@@ -632,6 +649,17 @@
             : PointerController::INACTIVITY_TIMEOUT_NORMAL);
 }
 
+void NativeInputManager::setPointerSpeed(int32_t speed) {
+    AutoMutex _l(mLock);
+
+    if (mLocked.pointerSpeed != speed) {
+        LOGI("Setting pointer speed to %d.", speed);
+        mLocked.pointerSpeed = speed;
+
+        mInputManager->getReader()->refreshConfiguration();
+    }
+}
+
 bool NativeInputManager::isScreenOn() {
     return android_server_PowerManagerService_isScreenOn();
 }
@@ -1221,6 +1249,15 @@
             transferTouchFocus(fromChannel, toChannel);
 }
 
+static void android_server_InputManager_nativeSetPointerSpeed(JNIEnv* env,
+        jclass clazz, jint speed) {
+    if (checkInputManagerUnitialized(env)) {
+        return;
+    }
+
+    gNativeInputManager->setPointerSpeed(speed);
+}
+
 static jstring android_server_InputManager_nativeDump(JNIEnv* env, jclass clazz) {
     if (checkInputManagerUnitialized(env)) {
         return NULL;
@@ -1277,6 +1314,8 @@
             (void*) android_server_InputManager_nativeGetInputConfiguration },
     { "nativeTransferTouchFocus", "(Landroid/view/InputChannel;Landroid/view/InputChannel;)Z",
             (void*) android_server_InputManager_nativeTransferTouchFocus },
+    { "nativeSetPointerSpeed", "(I)V",
+            (void*) android_server_InputManager_nativeSetPointerSpeed },
     { "nativeDump", "()Ljava/lang/String;",
             (void*) android_server_InputManager_nativeDump },
 };