Skip KeyEvent input tests for keys which are handled globally.

Bug: 197324044
Test: atest GoogleAtvReferenceRemoteControlTest
Test: atest CtsHardwareTestCases
Change-Id: I9a17c9fb238d11ad88b9da1dcfcdd96ac4dc7d22
(cherry picked from commit 28bfb73625b7f955900416305ffcef5ec2d83bf2)
diff --git a/tests/tests/hardware/src/android/hardware/input/cts/GlobalKeyMapping.java b/tests/tests/hardware/src/android/hardware/input/cts/GlobalKeyMapping.java
new file mode 100644
index 0000000..297031a
--- /dev/null
+++ b/tests/tests/hardware/src/android/hardware/input/cts/GlobalKeyMapping.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+package android.hardware.input.cts;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.XmlResourceParser;
+import android.util.Log;
+import android.view.InputEvent;
+import android.view.KeyEvent;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Loads the global keys from {@code com.android.internal.R.xml.global_keys} the same way like
+ * {@code com.android.server.policy.GlobalKeyManager} does.
+ * TODO(199182608): Make GlobalKeyManager#shouldHandleGlobalKey() a testApi and remove this class
+ */
+public class GlobalKeyMapping {
+    private static final String TAG = GlobalKeyMapping.class.getSimpleName();
+    private static final String TAG_GLOBAL_KEYS = "global_keys";
+    private static final String TAG_KEY = "key";
+    private static final String ATTR_VERSION = "version";
+    private static final String ATTR_KEY_CODE = "keyCode";
+    private static final int GLOBAL_KEY_FILE_VERSION = 1;
+    private static final Set<Integer> GLOBAL_KEYS = new HashSet<>();
+
+
+    public GlobalKeyMapping(Context context) {
+        loadGlobalKeys(context);
+    }
+
+    private void loadGlobalKeys(Context context) {
+        try (XmlResourceParser parser = context.getResources().getXml(
+                Resources.getSystem().getIdentifier("global_keys", "xml", "android"))) {
+            beginDocument(parser, TAG_GLOBAL_KEYS);
+            int version = parser.getAttributeIntValue(null, ATTR_VERSION, 0);
+            if (GLOBAL_KEY_FILE_VERSION == version) {
+                while (true) {
+                    nextElement(parser);
+                    String element = parser.getName();
+                    if (element == null) {
+                        break;
+                    }
+                    if (TAG_KEY.equals(element)) {
+                        String keyCodeName = parser.getAttributeValue(null, ATTR_KEY_CODE);
+                        int keyCode = KeyEvent.keyCodeFromString(keyCodeName);
+                        if (keyCode != KeyEvent.KEYCODE_UNKNOWN) {
+                            GLOBAL_KEYS.add(keyCode);
+                        }
+                    }
+                }
+            }
+        } catch (Resources.NotFoundException e) {
+            Log.w(TAG, "global keys file not found", e);
+        } catch (XmlPullParserException e) {
+            Log.w(TAG, "XML parser exception reading global keys file", e);
+        } catch (IOException e) {
+            Log.w(TAG, "I/O exception reading global keys file", e);
+        }
+    }
+
+    public boolean isGlobalKey(InputEvent e) {
+        if (GLOBAL_KEYS.isEmpty() || !(e instanceof KeyEvent)) {
+            return false;
+        }
+        KeyEvent keyEvent = (KeyEvent) e;
+        return GLOBAL_KEYS.contains(keyEvent.getKeyCode());
+    }
+
+    /** Ported from com.android.internal.util.XmlUtils */
+    private void nextElement(XmlPullParser parser) throws XmlPullParserException, IOException {
+        int type;
+        while ((type = parser.next()) != parser.START_TAG && type != parser.END_DOCUMENT) {
+            // skip
+        }
+    }
+
+    /** Ported from com.android.internal.util.XmlUtils */
+    private void beginDocument(XmlPullParser parser, String firstElementName)
+            throws XmlPullParserException, IOException {
+        int type;
+        while ((type = parser.next()) != parser.START_TAG && type != parser.END_DOCUMENT) {
+            // skip
+        }
+
+        if (type != parser.START_TAG) {
+            throw new XmlPullParserException("No start tag found");
+        }
+
+        if (!parser.getName().equals(firstElementName)) {
+            throw new XmlPullParserException("Unexpected start tag: found " + parser.getName()
+                    + ", expected " + firstElementName);
+        }
+    }
+}
diff --git a/tests/tests/hardware/src/android/hardware/input/cts/tests/InputHidTestCase.java b/tests/tests/hardware/src/android/hardware/input/cts/tests/InputHidTestCase.java
index d40d545..07a080a 100644
--- a/tests/tests/hardware/src/android/hardware/input/cts/tests/InputHidTestCase.java
+++ b/tests/tests/hardware/src/android/hardware/input/cts/tests/InputHidTestCase.java
@@ -31,6 +31,7 @@
 
 import android.hardware.BatteryState;
 import android.hardware.input.InputManager;
+import android.hardware.input.cts.GlobalKeyMapping;
 import android.hardware.lights.Light;
 import android.hardware.lights.LightState;
 import android.hardware.lights.LightsManager;
@@ -72,6 +73,8 @@
     private static final long CALLBACK_TIMEOUT_MILLIS = 5000;
 
     private HidDevice mHidDevice;
+    private final GlobalKeyMapping mGlobalKeyMapping = new GlobalKeyMapping(
+            mInstrumentation.getTargetContext());
     private int mDeviceId;
     private final int mRegisterResourceId;
     private boolean mDelayAfterSetup = false;
@@ -214,17 +217,19 @@
     @Override
     protected void testInputDeviceEvents(int resourceId) {
         List<HidTestData> tests = mParser.getHidTestData(resourceId);
+        // Global keys are handled by the framework and do not reach apps.
+        // The set of global keys is vendor-specific.
+        // Remove tests which contain global keys because we can't test them
+        tests.removeIf(testData -> testData.events.removeIf(mGlobalKeyMapping::isGlobalKey));
 
         for (HidTestData testData: tests) {
             mCurrentTestCase = testData.name;
-
             // Send all of the HID reports
             for (int i = 0; i < testData.reports.size(); i++) {
                 final String report = testData.reports.get(i);
                 mHidDevice.sendHidReport(report);
             }
             verifyEvents(testData.events);
-
         }
     }
 
diff --git a/tests/tests/hardware/src/android/hardware/input/cts/tests/InputTestCase.java b/tests/tests/hardware/src/android/hardware/input/cts/tests/InputTestCase.java
index df24d52..ce9746b 100644
--- a/tests/tests/hardware/src/android/hardware/input/cts/tests/InputTestCase.java
+++ b/tests/tests/hardware/src/android/hardware/input/cts/tests/InputTestCase.java
@@ -54,11 +54,11 @@
     private static final float TOLERANCE = 0.005f;
 
     private final BlockingQueue<InputEvent> mEvents;
+    protected final Instrumentation mInstrumentation = InstrumentationRegistry.getInstrumentation();
 
     private InputListener mInputListener;
     private View mDecorView;
 
-    protected Instrumentation mInstrumentation;
     protected InputJsonParser mParser;
     // Stores the name of the currently running test
     protected String mCurrentTestCase;
@@ -81,7 +81,6 @@
 
     @Before
     public void setUp() throws Exception {
-        mInstrumentation = InstrumentationRegistry.getInstrumentation();
         mActivityRule.getActivity().clearUnhandleKeyCode();
         mDecorView = mActivityRule.getActivity().getWindow().getDecorView();
         mParser = new InputJsonParser(mInstrumentation.getTargetContext());