Merge "Update InputeTestFragment to display keys held down."
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/input/InputTestFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/input/InputTestFragment.java
index 34ea1cf..1ae330f 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/input/InputTestFragment.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/input/InputTestFragment.java
@@ -19,6 +19,7 @@
import static android.hardware.automotive.vehicle.V2_0.SubscribeFlags.EVENTS_FROM_CAR;
import static android.hardware.automotive.vehicle.V2_0.VehicleDisplay.INSTRUMENT_CLUSTER;
import static android.hardware.automotive.vehicle.V2_0.VehicleHwKeyInputAction.ACTION_DOWN;
+import static android.hardware.automotive.vehicle.V2_0.VehicleHwKeyInputAction.ACTION_UP;
import static android.hardware.automotive.vehicle.V2_0.VehicleProperty.HW_KEY_INPUT;
import android.annotation.Nullable;
@@ -34,6 +35,8 @@
import android.hardware.automotive.vehicle.V2_0.VehiclePropertyStatus;
import android.hardware.automotive.vehicle.V2_0.VehiclePropertyType;
import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
import android.os.RemoteException;
import android.text.method.ScrollingMovementMethod;
import android.util.Log;
@@ -57,8 +60,11 @@
import java.util.ArrayList;
import java.util.Collections;
+import java.util.LinkedHashMap;
import java.util.List;
+import java.util.Map;
import java.util.NoSuchElementException;
+import java.util.function.Function;
/**
* Test input event handling to system.
@@ -81,6 +87,74 @@
private IVehicle mVehicle;
+ // Helper class for counting the number of key down vs. key up events received from a single
+ // source.
+ private class KeyDownCounter {
+ KeyDownCounter(Function<Integer, String> keyCodeToStringFunc) {
+ mKeyCodeToStringFunc = keyCodeToStringFunc;
+ }
+
+ public synchronized void count(int keyCode, boolean keyDown) {
+ Integer count = mKeyCodeToCountMap.get(keyCode);
+ if (count == null) {
+ count = 0;
+ }
+ count += keyDown ? 1 : -1;
+ if (count == 0) {
+ mKeyCodeToCountMap.remove(keyCode);
+ } else {
+ mKeyCodeToCountMap.put(keyCode, count);
+ }
+ mMainHandler.post(mRefreshKeysDownTextViewRunnable);
+ }
+
+ public synchronized String toString() {
+ StringBuilder sb = new StringBuilder();
+ for (Map.Entry<Integer, Integer> entry : mKeyCodeToCountMap.entrySet()) {
+ sb.append(" ").append(mKeyCodeToStringFunc.apply(entry.getKey()));
+ if (entry.getValue() != 1) {
+ sb.append("x").append(entry.getValue());
+ }
+ }
+ return sb.toString();
+ }
+
+ // Function to translate keycodes into strings for this source.
+ private final Function<Integer, String> mKeyCodeToStringFunc;
+
+ // LinkedHashMap used for deterministic iteration order.
+ private final Map<Integer, Integer> mKeyCodeToCountMap = new LinkedHashMap<>();
+ }
+
+ // KeyDownCounters for events from EventReaderService and VHAL. Note that they use different
+ // key code mappings.
+ private final KeyDownCounter mEventReaderServiceKeyDownCounter =
+ new KeyDownCounter(k -> KeypressEvent.keycodeToString(k));
+ private final KeyDownCounter mVhalKeyDownCounter =
+ new KeyDownCounter(k -> KeyEvent.keyCodeToString(k));
+
+ private final Handler mMainHandler = new Handler(Looper.getMainLooper());
+
+ private TextView mKeysDownTextView;
+
+ // Runnable posted to mMainHandler by KeyDownCounter to refresh mKeysDownTextView's text.
+ private final Runnable mRefreshKeysDownTextViewRunnable = new Runnable() {
+ @Override
+ public void run() {
+ StringBuilder sb = new StringBuilder("VHAL keys down:");
+ sb.append(mVhalKeyDownCounter.toString());
+
+ if (mEventReaderService == null) {
+ sb.append("\nCould not connect to EventReaderService. Is keventreader running?");
+ } else {
+ sb.append("\nEventReaderService keys down:");
+ sb.append(mEventReaderServiceKeyDownCounter.toString());
+ }
+
+ mKeysDownTextView.setText(sb.toString());
+ }
+ };
+
private EventReaderService mEventReaderService;
private final IEventCallback.Stub mKeypressEventHandler = new IEventCallback.Stub() {
@@ -94,9 +168,7 @@
@Override
public void onEvent(KeypressEvent keypressEvent) throws RemoteException {
Log.d(TAG, "received event " + keypressEvent);
- synchronized (mInputEventsList) {
- mInputEventsList.append(prettyPrint(keypressEvent));
- }
+ mEventReaderServiceKeyDownCounter.count(keypressEvent.keycode, keypressEvent.isKeydown);
}
};
@@ -113,8 +185,25 @@
@Override
public void onPropertyEvent(ArrayList<VehiclePropValue> propValues) throws RemoteException {
- synchronized (mInputEventsList) {
- propValues.forEach(vpv -> mInputEventsList.append(prettyPrint(vpv)));
+ for (VehiclePropValue vpv : propValues) {
+ Log.d(TAG, "received event " + prettyPrint(vpv));
+ if (vpv.prop != HW_KEY_INPUT || vpv.value == null || vpv.value.int32Values == null
+ || vpv.value.int32Values.size() < 2) {
+ continue;
+ }
+ int keycode = vpv.value.int32Values.get(1);
+ switch (vpv.value.int32Values.get(0)) {
+ case ACTION_DOWN:
+ mVhalKeyDownCounter.count(keycode, true);
+ break;
+ case ACTION_UP:
+ mVhalKeyDownCounter.count(keycode, false);
+ break;
+ default:
+ Log.e(TAG, "Unrecognized VehicleHwKeyInputAction: "
+ + vpv.value.int32Values.get(0));
+ break;
+ }
}
}
@@ -125,8 +214,6 @@
public void onPropertySetError(int errorCode, int propId, int areaId) {}
};
- private TextView mInputEventsList;
-
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -164,8 +251,9 @@
@Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.input_test, container, false);
- mInputEventsList = view.findViewById(R.id.events_list);
- mInputEventsList.setMovementMethod(new ScrollingMovementMethod());
+ mKeysDownTextView = view.findViewById(R.id.events_list);
+ mKeysDownTextView.setMovementMethod(new ScrollingMovementMethod());
+ mRefreshKeysDownTextViewRunnable.run();
TextView steeringWheelLabel = new TextView(getActivity() /*context*/);
steeringWheelLabel.setText(R.string.steering_wheel);
diff --git a/tools/keventreader/client/src/com/android/car/keventreader/KeypressEvent.java b/tools/keventreader/client/src/com/android/car/keventreader/KeypressEvent.java
index 34aa992..8f74011 100644
--- a/tools/keventreader/client/src/com/android/car/keventreader/KeypressEvent.java
+++ b/tools/keventreader/client/src/com/android/car/keventreader/KeypressEvent.java
@@ -17,6 +17,7 @@
import android.os.Parcel;
import android.os.Parcelable;
+
import java.util.HashMap;
import java.util.Map;
@@ -628,6 +629,17 @@
}
public String keycodeToString() {
- return KEYCODE_NAME_MAP.getOrDefault(keycode, Integer.toHexString(keycode));
+ return keycodeToString(keycode);
+ }
+
+ /**
+ * Translates a key code from keventreader into a string.
+ * @param keycode Key code from a keventreader KeypressEvent.
+ * @return String String label corresponding to keycode, if available. If not, String with
+ * hexidecimal representation of keycode.
+ */
+ public static String keycodeToString(int keycode) {
+ String ret = KEYCODE_NAME_MAP.get(keycode);
+ return ret != null ? ret : "0x" + Integer.toHexString(keycode);
}
}