HDMICEC: Instrumentation to register listeners

Use instrumentation tests to register vendor command listeners instead
of an app that uses HDMI_CEC permission.

Test: atest android.hdmicec.cts.common.HdmiCecVendorCommandsTest
Bug: 177061176

Change-Id: Idc9f363158c8756536b13f7d837738b511edbf63
diff --git a/hostsidetests/hdmicec/app/src/android/hdmicec/app/HdmiCecVendorCommandListener.java b/hostsidetests/hdmicec/app/src/android/hdmicec/app/HdmiCecVendorCommandListener.java
deleted file mode 100644
index c8a323a..0000000
--- a/hostsidetests/hdmicec/app/src/android/hdmicec/app/HdmiCecVendorCommandListener.java
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright (C) 2020 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.hdmicec.app;
-
-import android.app.Activity;
-import android.hardware.hdmi.HdmiClient;
-import android.hardware.hdmi.HdmiControlManager;
-import android.hardware.hdmi.HdmiDeviceInfo;
-import android.os.Bundle;
-import android.util.Log;
-
-/**
- * An application to register vendor command listeners. This can be used to test the vendor command
- * listener registration APIs. Actions supported are:
- *
- * <p>
- *
- * <p>1. android.hdmicec.app.VENDOR_LISTENER_WITH_ID: Registers a vendor command listener with
- * vendor ID
- *
- * <p>Usage: <code>START_COMMAND -a android.hdmicec.app.VENDOR_LISTENER_WITH_ID</code>
- *
- * <p>
- *
- * <p>2. android.hdmicec.app.VENDOR_LISTENER_WITHOUT_ID: Registers a vendor command listener without
- * a vendor ID associated with it.
- *
- * <p>Usage: <code>START_COMMAND -a android.hdmicec.app.VENDOR_LISTENER_WITHOUT_ID
- * </code>
- *
- * <p>
- *
- * <p>where START_COMMAND is
- *
- * <p><code>
- * adb shell am start -n "android.hdmicec.app/android.hdmicec.app.HdmiCecVendorCommandListener"
- * </code>
- */
-public class HdmiCecVendorCommandListener extends Activity {
-
-    private static final String TAG = HdmiCecVendorCommandListener.class.getSimpleName();
-    private static final int VENDOR_ID = 0xBADDAD;
-    private HdmiControlManager mHdmiControlManager;
-
-    @Override
-    public void onCreate(Bundle icicle) {
-        super.onCreate(icicle);
-
-        mHdmiControlManager = getSystemService(HdmiControlManager.class);
-        if (mHdmiControlManager == null) {
-            Log.i(TAG, "Failed to get HdmiControlManager");
-            return;
-        }
-        HdmiClient client = mHdmiControlManager.getClient(HdmiDeviceInfo.DEVICE_TV);
-        if (client == null) {
-            client = mHdmiControlManager.getClient(HdmiDeviceInfo.DEVICE_PLAYBACK);
-            if (client == null) {
-                Log.i(TAG, "Failed to get HDMI client");
-                return;
-            }
-        }
-
-        String action = getIntent().getAction();
-        switch (action) {
-            case "android.hdmicec.app.VENDOR_LISTENER_WITH_ID":
-                HdmiControlManager.VendorCommandListener vendorCommandListenerWithId =
-                        new VendorCommandTestListener(VENDOR_ID);
-                client.setVendorCommandListener(vendorCommandListenerWithId, VENDOR_ID);
-                break;
-            case "android.hdmicec.app.VENDOR_LISTENER_WITHOUT_ID":
-                HdmiControlManager.VendorCommandListener vendorCommandListener =
-                        new VendorCommandTestListener();
-                client.setVendorCommandListener(vendorCommandListener);
-                break;
-            default:
-                Log.w(TAG, "Unknown intent!" + action);
-        }
-    }
-
-    private static class VendorCommandTestListener
-            implements HdmiControlManager.VendorCommandListener {
-
-        int mVendorId = 0xFFFFFF;
-
-        VendorCommandTestListener(int vendorId) {
-            mVendorId = vendorId;
-        }
-
-        VendorCommandTestListener() {}
-
-        @Override
-        public void onReceived(
-                int sourceAddress, int destAddress, byte[] params, boolean hasVendorId) {
-            if (hasVendorId) {
-                int receivedVendorId =
-                        ((params[0] & 0xFF) << 16) + ((params[1] & 0xFF) << 8) + (params[2] & 0xFF);
-
-                if (mVendorId == receivedVendorId) {
-                    Log.i(TAG, "Received vendor command with correct vendor ID");
-                } else {
-                    Log.i(TAG, "Received vendor command with wrong vendor ID");
-                }
-            } else {
-                Log.i(TAG, "Received vendor command without vendor ID");
-            }
-        }
-
-        @Override
-        public void onControlStateChanged(boolean enabled, int reason) {}
-    }
-}
diff --git a/hostsidetests/hdmicec/app/src/android/hdmicec/app/HdmiControlManagerHelper.java b/hostsidetests/hdmicec/app/src/android/hdmicec/app/HdmiControlManagerHelper.java
index 7a05c13..fbc07ae 100755
--- a/hostsidetests/hdmicec/app/src/android/hdmicec/app/HdmiControlManagerHelper.java
+++ b/hostsidetests/hdmicec/app/src/android/hdmicec/app/HdmiControlManagerHelper.java
@@ -18,11 +18,9 @@
 
 import static android.Manifest.permission.HDMI_CEC;
 
-import android.app.Activity;
 import android.content.Context;
 import android.hardware.hdmi.HdmiClient;
 import android.hardware.hdmi.HdmiControlManager;
-import android.hardware.hdmi.HdmiPlaybackClient;
 import android.hardware.hdmi.HdmiTvClient;
 import android.util.Log;
 import android.view.KeyEvent;
@@ -44,6 +42,12 @@
 public final class HdmiControlManagerHelper {
     private static final String LOGICAL_ADDR = "ARG_LOGICAL_ADDR";
     private static final String TAG = HdmiControlManagerHelper.class.getSimpleName();
+    private static final int VENDOR_ID = 0xBADDAD;
+    private static final HdmiControlManager.VendorCommandListener vendorCommandListenerWithoutId =
+            new VendorCommandTestListener();
+    private static final HdmiControlManager.VendorCommandListener vendorCommandListenerWithId =
+            new VendorCommandTestListener(VENDOR_ID);
+
     HdmiControlManager mHdmiControlManager;
 
     @Before
@@ -114,4 +118,76 @@
             Log.w(TAG, "Interrupted between keyevents, could not send all keyevents!");
         }
     }
+
+    @Test
+    public void vendorCmdListenerWithId() throws InterruptedException {
+        HdmiClient client = mHdmiControlManager.getPlaybackClient();
+        if (client == null) {
+            client = mHdmiControlManager.getTvClient();
+        }
+
+        if (client == null) {
+            Log.i(TAG, "Could not get a TV/Playback client, cannot register listener");
+            return;
+        }
+
+        client.setVendorCommandListener(vendorCommandListenerWithId, VENDOR_ID);
+        Log.i(TAG, "Registered vendor command listener with ID");
+
+        // Sleep for 20s, 10s waiting for the registration confirmation and 10s waiting for the
+        // callback.
+        TimeUnit.SECONDS.sleep(20);
+    }
+
+    @Test
+    public void vendorCmdListenerWithoutId() throws InterruptedException {
+        HdmiClient client = mHdmiControlManager.getPlaybackClient();
+        if (client == null) {
+            client = mHdmiControlManager.getTvClient();
+        }
+
+        if (client == null) {
+            Log.i(TAG, "Could not get a TV/Playback client, cannot register listener");
+            return;
+        }
+
+        client.setVendorCommandListener(vendorCommandListenerWithoutId);
+        Log.i(TAG, "Registered vendor command listener without ID");
+
+        // Sleep for 20s, 10s waiting for the registration confirmation and 10s waiting for the
+        // callback.
+        TimeUnit.SECONDS.sleep(20);
+    }
+
+    private static class VendorCommandTestListener
+            implements HdmiControlManager.VendorCommandListener {
+
+        int mVendorId = 0xFFFFFF;
+
+        VendorCommandTestListener(int vendorId) {
+            mVendorId = vendorId;
+        }
+
+        VendorCommandTestListener() {}
+
+        @Override
+        public void onReceived(
+                int sourceAddress, int destAddress, byte[] params, boolean hasVendorId) {
+            if (hasVendorId) {
+                int receivedVendorId =
+                        ((params[0] & 0xFF) << 16) + ((params[1] & 0xFF) << 8) + (params[2] & 0xFF);
+
+                if (mVendorId == receivedVendorId) {
+                    Log.i(TAG, "Received vendor command with correct vendor ID");
+                } else {
+                    Log.i(TAG, "Received vendor command with wrong vendor ID");
+                }
+            } else {
+                Log.i(TAG, "Received vendor command without vendor ID");
+            }
+        }
+
+        @Override
+        public void onControlStateChanged(boolean enabled, int reason) {}
+    }
 }
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiControlManagerUtility.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiControlManagerUtility.java
index 8e81ab3..691490c 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiControlManagerUtility.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiControlManagerUtility.java
@@ -37,6 +37,12 @@
     /** The method name of the set active source case. */
     private static final String SEND_INTERRUPTED_LONG_PRESS = "interruptedLongPress";
 
+    /** The method name of the set active source case. */
+    private static final String VENDOR_CMD_LISTENER_WITHOUT_ID = "vendorCmdListenerWithoutId";
+
+    /** The method name of the set active source case. */
+    private static final String VENDOR_CMD_LISTENER_WITH_ID = "vendorCmdListenerWithId";
+
     /** The key of the set active source case arguments. */
     private static final String LOGICAL_ADDR = "ARG_LOGICAL_ADDR";
 
@@ -65,4 +71,16 @@
     public static void sendLongPressKeyevent(BaseHostJUnit4Test host) throws DeviceNotAvailableException {
         host.runDeviceTests(TEST_PKG, TEST_CLS, SEND_INTERRUPTED_LONG_PRESS);
     }
+
+    /** Registers a vendor command listener without a vendor ID. */
+    public static void registerVendorCmdListenerWithoutId(BaseHostJUnit4Test host)
+            throws DeviceNotAvailableException {
+        host.runDeviceTests(TEST_PKG, TEST_CLS, VENDOR_CMD_LISTENER_WITHOUT_ID);
+    }
+
+    /** Registers a vendor command listener with vendor ID. */
+    public static void registerVendorCmdListenerWithId(BaseHostJUnit4Test host)
+            throws DeviceNotAvailableException {
+        host.runDeviceTests(TEST_PKG, TEST_CLS, VENDOR_CMD_LISTENER_WITH_ID);
+    }
 }
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/LogHelper.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/LogHelper.java
index 646ce07..2074a49 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/LogHelper.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/LogHelper.java
@@ -59,6 +59,24 @@
         return testString;
     }
 
+    public static void waitForLog(
+            ITestDevice device, String tag, int waitSeconds, String expectedOutput)
+            throws Exception {
+        long timeoutMillis = waitSeconds * 1000;
+        long startTime = System.currentTimeMillis();
+        long endTime = startTime;
+
+        while ((endTime - startTime <= timeoutMillis)) {
+            String testString = getLog(device, tag);
+            if (testString.contains(expectedOutput)) {
+                return;
+            }
+            endTime = System.currentTimeMillis();
+        }
+
+        throw new Exception("Timed out, could not find the log message.");
+    }
+
     public static void assertLog(ITestDevice device, String tag, String ...expectedOutput)
             throws Exception {
         String testString = getLog(device, tag);
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecVendorCommandsTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecVendorCommandsTest.java
index 7b18497..96e026d 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecVendorCommandsTest.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecVendorCommandsTest.java
@@ -21,10 +21,13 @@
 import android.hdmicec.cts.BaseHdmiCecCtsTest;
 import android.hdmicec.cts.CecMessage;
 import android.hdmicec.cts.CecOperand;
+import android.hdmicec.cts.HdmiControlManagerUtility;
 import android.hdmicec.cts.LogicalAddress;
 import android.hdmicec.cts.LogHelper;
 
+import com.android.tradefed.device.DeviceNotAvailableException;
 import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.log.LogUtil.CLog;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
 import org.junit.Rule;
@@ -38,22 +41,21 @@
 
     private static final int INCORRECT_VENDOR_ID = 0x0;
 
-    /** The package name of the APK. */
-    private static final String PACKAGE = "android.hdmicec.app";
-    /** The class name of the main activity in the APK. */
-    private static final String CLASS = "HdmiCecVendorCommandListener";
-    /** The command to launch the main activity. */
-    private static final String START_COMMAND =
-            String.format("am start -W -n %s/%s.%s  ", PACKAGE, PACKAGE, CLASS);
-
     private static final String VENDOR_LISTENER_WITH_ID =
             "-a android.hdmicec.app.VENDOR_LISTENER_WITH_ID";
     private static final String VENDOR_LISTENER_WITHOUT_ID =
             "-a android.hdmicec.app.VENDOR_LISTENER_WITHOUT_ID";
-    /** The command to clear the main activity. */
-    private static final String CLEAR_COMMAND = String.format("pm clear %s", PACKAGE);
 
-    // This has to be the same as the vendor ID used in the HdmiCecVendorCommandListener
+    /** Log confirmation message after listener registration. */
+    private static final String REGISTERED_LISTENER = "Registered vendor command listener";
+
+    /** The TAG that the test class will use. */
+    private static final String TEST_LOG_TAG = "HdmiControlManagerHelper";
+
+    /**
+     * This has to be the same as the vendor ID used in the instrumentation test {@link
+     * HdmiControlManagerHelper#VENDOR_ID}
+     */
     private static final int VENDOR_ID = 0xBADDAD;
 
     @Rule
@@ -108,78 +110,116 @@
         assertThat(CecMessage.getParams(message)).isNotEqualTo(INCORRECT_VENDOR_ID);
     }
 
+    /* The four following tests test the registration of a callback, and if the callback is received
+     * when the DUT receives a <Vendor Command> message.
+     * When there are no listeners registered, the DUT should respond with <Feature Abort>[Refused].
+     * Since the number of listeners registered is not queryable, the case where there are no
+     * listeners registered is not tested.
+     */
+
+    private Thread registerVendorCmdListenerWithId() {
+        return new Thread(
+                new Runnable() {
+                    public void run() {
+                        try {
+                            HdmiControlManagerUtility.registerVendorCmdListenerWithId(
+                                    HdmiCecVendorCommandsTest.this);
+                        } catch (DeviceNotAvailableException dnae) {
+                            CLog.w("HdmiCecVendorcommandstest", "Device not available exception");
+                        }
+                    }
+                });
+    }
+
+    private Thread registerVendorCmdListenerWithoutId() {
+        return new Thread(
+                new Runnable() {
+                    public void run() {
+                        try {
+                            HdmiControlManagerUtility.registerVendorCmdListenerWithoutId(
+                                    HdmiCecVendorCommandsTest.this);
+                        } catch (DeviceNotAvailableException dnae) {
+                            CLog.w("HdmiCecVendorcommandstest", "Device not available exception");
+                        }
+                    }
+                });
+    }
+
     @Test
     public void cecVendorCommandListenerWithVendorIdTest() throws Exception {
         ITestDevice device = getDevice();
-        // Clear activity
-        device.executeShellCommand(CLEAR_COMMAND);
-        // Clear logcat.
-        device.executeAdbCommand("logcat", "-c");
-        // Start the APK and wait for it to complete.
-        device.executeShellCommand(START_COMMAND + VENDOR_LISTENER_WITH_ID);
+        Thread test = registerVendorCmdListenerWithId();
 
-        String params = CecMessage.formatParams(VENDOR_ID);
-        params += CecMessage.formatParams("010203");
-        hdmiCecClient.sendCecMessage(LogicalAddress.TV, CecOperand.VENDOR_COMMAND_WITH_ID, params);
+        test.start();
 
-        LogHelper.assertLog(device, CLASS, "Received vendor command with correct vendor ID");
-        // Clear activity
-        device.executeShellCommand(CLEAR_COMMAND);
+        try {
+            LogHelper.waitForLog(getDevice(), TEST_LOG_TAG, 10, REGISTERED_LISTENER);
+            String params = CecMessage.formatParams(VENDOR_ID);
+            params += CecMessage.formatParams("010203");
+            hdmiCecClient.sendCecMessage(
+                    LogicalAddress.TV, CecOperand.VENDOR_COMMAND_WITH_ID, params);
+
+            LogHelper.assertLog(
+                    device, TEST_LOG_TAG, "Received vendor command with correct vendor ID");
+        } finally {
+            test.join();
+        }
     }
 
     @Test
     public void cecVendorCommandListenerReceivesVendorCommandWithoutId() throws Exception {
         ITestDevice device = getDevice();
-        // Clear activity
-        device.executeShellCommand(CLEAR_COMMAND);
-        // Clear logcat.
-        device.executeAdbCommand("logcat", "-c");
-        // Start the APK and wait for it to complete.
-        device.executeShellCommand(START_COMMAND + VENDOR_LISTENER_WITH_ID);
+        Thread test = registerVendorCmdListenerWithId();
+        test.start();
 
-        String params = CecMessage.formatParams("010203");
-        hdmiCecClient.sendCecMessage(LogicalAddress.TV, CecOperand.VENDOR_COMMAND, params);
+        try {
+            LogHelper.waitForLog(getDevice(), TEST_LOG_TAG, 10, REGISTERED_LISTENER);
 
-        LogHelper.assertLog(device, CLASS, "Received vendor command without vendor ID");
-        // Clear activity
-        device.executeShellCommand(CLEAR_COMMAND);
+            String params = CecMessage.formatParams("010203");
+            hdmiCecClient.sendCecMessage(LogicalAddress.TV, CecOperand.VENDOR_COMMAND, params);
+
+            LogHelper.assertLog(device, TEST_LOG_TAG, "Received vendor command without vendor ID");
+        } finally {
+            test.join();
+        }
     }
 
     @Test
     public void cecVendorCommandListenerWithoutVendorIdTest() throws Exception {
         ITestDevice device = getDevice();
-        // Clear activity
-        device.executeShellCommand(CLEAR_COMMAND);
-        // Clear logcat.
-        device.executeAdbCommand("logcat", "-c");
-        // Start the APK and wait for it to complete.
-        device.executeShellCommand(START_COMMAND + VENDOR_LISTENER_WITHOUT_ID);
+        Thread test = registerVendorCmdListenerWithoutId();
+        test.start();
 
-        String params = CecMessage.formatParams("010203");
-        hdmiCecClient.sendCecMessage(LogicalAddress.TV, CecOperand.VENDOR_COMMAND, params);
+        try {
+            LogHelper.waitForLog(getDevice(), TEST_LOG_TAG, 10, REGISTERED_LISTENER);
 
-        LogHelper.assertLog(device, CLASS, "Received vendor command without vendor ID");
-        // Clear activity
-        device.executeShellCommand(CLEAR_COMMAND);
+            String params = CecMessage.formatParams("010203");
+            hdmiCecClient.sendCecMessage(LogicalAddress.TV, CecOperand.VENDOR_COMMAND, params);
+
+            LogHelper.assertLog(device, TEST_LOG_TAG, "Received vendor command without vendor ID");
+        } finally {
+            test.join();
+        }
     }
 
     @Test
     public void cecVendorCommandListenerWithoutVendorIdDoesNotReceiveTest() throws Exception {
         ITestDevice device = getDevice();
-        // Clear activity
-        device.executeShellCommand(CLEAR_COMMAND);
-        // Clear logcat.
-        device.executeAdbCommand("logcat", "-c");
-        // Start the APK and wait for it to complete.
-        device.executeShellCommand(START_COMMAND + VENDOR_LISTENER_WITHOUT_ID);
+        Thread test = registerVendorCmdListenerWithoutId();
+        test.start();
 
-        String params = CecMessage.formatParams(VENDOR_ID);
-        params += CecMessage.formatParams("010203");
-        hdmiCecClient.sendCecMessage(LogicalAddress.TV, CecOperand.VENDOR_COMMAND_WITH_ID, params);
+        try {
+            LogHelper.waitForLog(getDevice(), TEST_LOG_TAG, 10, REGISTERED_LISTENER);
 
-        LogHelper.assertLogDoesNotContain(
-                device, CLASS, "Received vendor command with correct vendor ID");
-        // Clear activity
-        device.executeShellCommand(CLEAR_COMMAND);
+            String params = CecMessage.formatParams(VENDOR_ID);
+            params += CecMessage.formatParams("010203");
+            hdmiCecClient.sendCecMessage(
+                    LogicalAddress.TV, CecOperand.VENDOR_COMMAND_WITH_ID, params);
+
+            LogHelper.assertLogDoesNotContain(
+                    device, TEST_LOG_TAG, "Received vendor command with correct vendor ID");
+        } finally {
+            test.join();
+        }
     }
 }