Add setting to redirect vibrator to game controller.

Bug: 6334179
Change-Id: I70093e38824ea3e5cf9cf242d1d7b6d26115ed80
diff --git a/services/java/com/android/server/VibratorService.java b/services/java/com/android/server/VibratorService.java
index de25747..7561b0b 100755
--- a/services/java/com/android/server/VibratorService.java
+++ b/services/java/com/android/server/VibratorService.java
@@ -21,6 +21,8 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.PackageManager;
+import android.database.ContentObserver;
+import android.hardware.input.InputManager;
 import android.os.Handler;
 import android.os.IVibratorService;
 import android.os.PowerManager;
@@ -29,18 +31,41 @@
 import android.os.IBinder;
 import android.os.Binder;
 import android.os.SystemClock;
+import android.os.Vibrator;
 import android.os.WorkSource;
+import android.provider.Settings;
+import android.provider.Settings.SettingNotFoundException;
 import android.util.Slog;
+import android.view.InputDevice;
 
+import java.util.ArrayList;
 import java.util.LinkedList;
 import java.util.ListIterator;
 
-public class VibratorService extends IVibratorService.Stub {
+public class VibratorService extends IVibratorService.Stub
+        implements InputManager.InputDeviceListener {
     private static final String TAG = "VibratorService";
 
     private final LinkedList<Vibration> mVibrations;
     private Vibration mCurrentVibration;
     private final WorkSource mTmpWorkSource = new WorkSource();
+    private final Handler mH = new Handler();
+
+    private final Context mContext;
+    private final PowerManager.WakeLock mWakeLock;
+    private InputManager mIm;
+
+    volatile VibrateThread mThread;
+
+    // mInputDeviceVibrators lock should be acquired after mVibrations lock, if both are
+    // to be acquired
+    private final ArrayList<Vibrator> mInputDeviceVibrators = new ArrayList<Vibrator>();
+    private boolean mVibrateInputDevicesSetting; // guarded by mInputDeviceVibrators
+    private boolean mInputDeviceListenerRegistered; // guarded by mInputDeviceVibrators
+
+    native static boolean vibratorExists();
+    native static void vibratorOn(long milliseconds);
+    native static void vibratorOff();
 
     private class Vibration implements IBinder.DeathRecipient {
         private final IBinder mToken;
@@ -112,10 +137,23 @@
         context.registerReceiver(mIntentReceiver, filter);
     }
 
-    public boolean hasVibrator() {
-        return vibratorExists();
+    public void systemReady() {
+        mIm = (InputManager)mContext.getSystemService(Context.INPUT_SERVICE);
+        mContext.getContentResolver().registerContentObserver(
+                Settings.System.getUriFor(Settings.System.VIBRATE_INPUT_DEVICES), true,
+                new ContentObserver(mH) {
+                    @Override
+                    public void onChange(boolean selfChange) {
+                        updateVibrateInputDevicesSetting();
+                    }
+                });
+        updateVibrateInputDevicesSetting();
     }
-    
+
+    public boolean hasVibrator() {
+        return doVibratorExists();
+    }
+
     public void vibrate(long milliseconds, IBinder token) {
         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.VIBRATE)
                 != PackageManager.PERMISSION_GRANTED) {
@@ -131,6 +169,7 @@
             // longer than milliseconds.
             return;
         }
+
         Vibration vib = new Vibration(token, milliseconds, uid);
         synchronized (mVibrations) {
             removeVibrationLocked(token);
@@ -240,7 +279,7 @@
             }
             mThread = null;
         }
-        vibratorOff();
+        doVibratorOff();
         mH.removeCallbacks(mVibrationRunnable);
     }
 
@@ -257,7 +296,7 @@
     // Lock held on mVibrations
     private void startVibrationLocked(final Vibration vib) {
         if (vib.mTimeout != 0) {
-            vibratorOn(vib.mTimeout);
+            doVibratorOn(vib.mTimeout);
             mH.postDelayed(mVibrationRunnable, vib.mTimeout);
         } else {
             // mThread better be null here. doCancelVibrate should always be
@@ -295,6 +334,100 @@
         }
     }
 
+    private void updateVibrateInputDevicesSetting() {
+        synchronized (mInputDeviceVibrators) {
+            mVibrateInputDevicesSetting = false;
+            try {
+                mVibrateInputDevicesSetting = Settings.System.getInt(mContext.getContentResolver(),
+                        Settings.System.VIBRATE_INPUT_DEVICES) > 0;
+            } catch (SettingNotFoundException snfe) {
+            }
+
+            if (mVibrateInputDevicesSetting) {
+                if (!mInputDeviceListenerRegistered) {
+                    mInputDeviceListenerRegistered = true;
+                    mIm.registerInputDeviceListener(this, mH);
+                }
+            } else {
+                if (mInputDeviceListenerRegistered) {
+                    mInputDeviceListenerRegistered = false;
+                    mIm.unregisterInputDeviceListener(this);
+                }
+            }
+
+            updateInputDeviceVibrators();
+        }
+    }
+
+    private void updateInputDeviceVibrators() {
+        synchronized (mVibrations) {
+            doCancelVibrateLocked();
+
+            synchronized (mInputDeviceVibrators) {
+                mInputDeviceVibrators.clear();
+                if (mVibrateInputDevicesSetting) {
+                    int[] ids = mIm.getInputDeviceIds();
+                    for (int i = 0; i < ids.length; i++) {
+                        InputDevice device = mIm.getInputDevice(ids[i]);
+                        Vibrator vibrator = device.getVibrator();
+                        if (vibrator.hasVibrator()) {
+                            mInputDeviceVibrators.add(vibrator);
+                        }
+                    }
+                }
+            }
+
+            startNextVibrationLocked();
+        }
+    }
+
+    @Override
+    public void onInputDeviceAdded(int deviceId) {
+        updateInputDeviceVibrators();
+    }
+
+    @Override
+    public void onInputDeviceChanged(int deviceId) {
+        updateInputDeviceVibrators();
+    }
+
+    @Override
+    public void onInputDeviceRemoved(int deviceId) {
+        updateInputDeviceVibrators();
+    }
+
+    private boolean doVibratorExists() {
+        synchronized (mInputDeviceVibrators) {
+            return !mInputDeviceVibrators.isEmpty() || vibratorExists();
+        }
+    }
+
+    private void doVibratorOn(long millis) {
+        synchronized (mInputDeviceVibrators) {
+            final int vibratorCount = mInputDeviceVibrators.size();
+            if (vibratorCount != 0) {
+                for (int i = 0; i < vibratorCount; i++) {
+                    mInputDeviceVibrators.get(i).vibrate(millis);
+                }
+            } else {
+                vibratorOn(millis);
+            }
+        }
+    }
+
+    private void doVibratorOff() {
+        synchronized (mInputDeviceVibrators) {
+            final int vibratorCount = mInputDeviceVibrators.size();
+            if (vibratorCount != 0) {
+                for (int i = 0; i < vibratorCount; i++) {
+                    mInputDeviceVibrators.get(i).cancel();
+                }
+            } else {
+                vibratorOff();
+            }
+        }
+    }
+
     private class VibrateThread extends Thread {
         final Vibration mVibration;
         boolean mDone;
@@ -350,7 +483,7 @@
                         // duration is saved for delay() at top of loop
                         duration = pattern[index++];
                         if (duration > 0) {
-                            VibratorService.this.vibratorOn(duration);
+                            VibratorService.this.doVibratorOn(duration);
                         }
                     } else {
                         if (repeat < 0) {
@@ -394,15 +527,4 @@
             }
         }
     };
-
-    private Handler mH = new Handler();
-
-    private final Context mContext;
-    private final PowerManager.WakeLock mWakeLock;
-
-    volatile VibrateThread mThread;
-
-    native static boolean vibratorExists();
-    native static void vibratorOn(long milliseconds);
-    native static void vibratorOff();
 }