Bug 963873 - Replace HashMap with SparseArray in AndroidGamepadManager. r=nalexander
authorMichael Comella <michael.l.comella@gmail.com>
Tue, 16 Jun 2015 15:41:22 -0700
changeset 249180 f79a2670fba4c419ac6fb0230978f24d4edaa51a
parent 249179 6258419da1afde3cb470f79808cdfad0f54063bd
child 249181 0a83b62ea755489978df6ecf6a9b37835373aed3
push id13601
push usermichael.l.comella@gmail.com
push dateWed, 17 Jun 2015 03:28:52 +0000
treeherderfx-team@f79a2670fba4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnalexander
bugs963873
milestone41.0a1
Bug 963873 - Replace HashMap with SparseArray in AndroidGamepadManager. r=nalexander I don't expect to have many devices attached to a Fennec instance so it's unlkely we'll run into the performance issues of SparseArray when adding/removing.
mobile/android/base/AndroidGamepadManager.java
--- a/mobile/android/base/AndroidGamepadManager.java
+++ b/mobile/android/base/AndroidGamepadManager.java
@@ -1,27 +1,27 @@
 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko;
 
 import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.List;
 import java.util.Timer;
 import java.util.TimerTask;
 
 import org.mozilla.gecko.AppConstants.Versions;
 import org.mozilla.gecko.util.GamepadUtils;
 import org.mozilla.gecko.util.ThreadUtils;
 
 import android.content.Context;
 import android.hardware.input.InputManager;
+import android.util.SparseArray;
 import android.view.InputDevice;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 
 
 public class AndroidGamepadManager {
     // This is completely arbitrary.
     private static final float TRIGGER_PRESSED_THRESHOLD = 0.25f;
@@ -124,56 +124,55 @@ public class AndroidGamepadManager {
                 } else {
                     triggerAxes = null;
                 }
             }
         }
     }
 
     private static boolean sStarted;
-    private static HashMap<Integer, Gamepad> sGamepads;
-    private static HashMap<Integer, List<KeyEvent>> sPendingGamepads;
+    private static final SparseArray<Gamepad> sGamepads = new SparseArray<>();
+    private static final SparseArray<List<KeyEvent>> sPendingGamepads = new SparseArray<>();
     private static InputManager.InputDeviceListener sListener;
     private static Timer sPollTimer;
 
     private AndroidGamepadManager() {
     }
 
     public static void startup() {
         ThreadUtils.assertOnUiThread();
         if (!sStarted) {
-            sGamepads = new HashMap<Integer, Gamepad>();
-            sPendingGamepads = new HashMap<Integer, List<KeyEvent>>();
             scanForGamepads();
             addDeviceListener();
             sStarted = true;
         }
     }
 
     public static void shutdown() {
         ThreadUtils.assertOnUiThread();
         if (sStarted) {
             removeDeviceListener();
-            sPendingGamepads = null;
-            sGamepads = null;
+            sPendingGamepads.clear();
+            sGamepads.clear();
             sStarted = false;
         }
     }
 
     public static void gamepadAdded(int deviceId, int serviceId) {
         ThreadUtils.assertOnUiThread();
         if (!sStarted) {
             return;
         }
-        if (!sPendingGamepads.containsKey(deviceId)) {
+
+        final List<KeyEvent> pending = sPendingGamepads.get(deviceId);
+        if (pending == null) {
             removeGamepad(deviceId);
             return;
         }
 
-        List<KeyEvent> pending = sPendingGamepads.get(deviceId);
         sPendingGamepads.remove(deviceId);
         sGamepads.put(deviceId, new Gamepad(serviceId, deviceId));
         // Handle queued KeyEvents
         for (KeyEvent ev : pending) {
             handleKeyEvent(ev);
         }
     }
 
@@ -195,22 +194,22 @@ public class AndroidGamepadManager {
     }
 
     public static boolean handleMotionEvent(MotionEvent ev) {
         ThreadUtils.assertOnUiThread();
         if (!sStarted) {
             return false;
         }
 
-        if (!sGamepads.containsKey(ev.getDeviceId())) {
+        final Gamepad gamepad = sGamepads.get(ev.getDeviceId());
+        if (gamepad == null) {
             // Not a device we care about.
             return false;
         }
 
-        Gamepad gamepad = sGamepads.get(ev.getDeviceId());
         // First check the analog stick axes
         boolean[] valid = new boolean[Axis.values().length];
         float[] axes = new float[Axis.values().length];
         boolean anyValidAxes = false;
         for (Axis axis : Axis.values()) {
             float value = deadZone(ev, axis.axis);
             int i = axis.ordinal();
             if (value != gamepad.axes[i]) {
@@ -249,23 +248,24 @@ public class AndroidGamepadManager {
 
     public static boolean handleKeyEvent(KeyEvent ev) {
         ThreadUtils.assertOnUiThread();
         if (!sStarted) {
             return false;
         }
 
         int deviceId = ev.getDeviceId();
-        if (sPendingGamepads.containsKey(deviceId)) {
+        final List<KeyEvent> pendingGamepad = sPendingGamepads.get(deviceId);
+        if (pendingGamepad != null) {
             // Queue up key events for pending devices.
-            sPendingGamepads.get(deviceId).add(ev);
+            pendingGamepad.add(ev);
             return true;
         }
 
-        if (!sGamepads.containsKey(deviceId)) {
+        if (sGamepads.get(deviceId) == null) {
             InputDevice device = ev.getDevice();
             if (device != null &&
                 (device.getSources() & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD) {
                 // This is a gamepad we haven't seen yet.
                 addGamepad(device);
                 sPendingGamepads.get(deviceId).add(ev);
                 return true;
             }
@@ -331,17 +331,18 @@ public class AndroidGamepadManager {
 
     private static void addDeviceListener() {
         if (Versions.preJB) {
             // Poll known gamepads to see if they've disappeared.
             sPollTimer = new Timer();
             sPollTimer.scheduleAtFixedRate(new TimerTask() {
                     @Override
                     public void run() {
-                        for (Integer deviceId : sGamepads.keySet()) {
+                        for (int i = 0; i < sGamepads.size(); ++i) {
+                            final int deviceId = sGamepads.keyAt(i);
                             if (InputDevice.getDevice(deviceId) == null) {
                                 removeGamepad(deviceId);
                             }
                         }
                     }
                 }, POLL_TIMER_PERIOD, POLL_TIMER_PERIOD);
             return;
         }
@@ -354,23 +355,23 @@ public class AndroidGamepadManager {
                     }
                     if ((device.getSources() & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD) {
                         addGamepad(device);
                     }
                 }
 
                 @Override
                 public void onInputDeviceRemoved(int deviceId) {
-                    if (sPendingGamepads.containsKey(deviceId)) {
+                    if (sPendingGamepads.get(deviceId) != null) {
                         // Got removed before Gecko's ack reached us.
                         // gamepadAdded will deal with it.
                         sPendingGamepads.remove(deviceId);
                         return;
                     }
-                    if (sGamepads.containsKey(deviceId)) {
+                    if (sGamepads.get(deviceId) != null) {
                         removeGamepad(deviceId);
                     }
                 }
 
                 @Override
                 public void onInputDeviceChanged(int deviceId) {
                 }
             };