diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java index 96e7b03ec5a06..6303bdc63c36b 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java @@ -899,10 +899,16 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { @ServiceThreadOnly void startArcAction(boolean enabled) { + startArcAction(enabled, null); + } + + @ServiceThreadOnly + void startArcAction(boolean enabled, IHdmiControlCallback callback) { assertRunOnServiceThread(); HdmiDeviceInfo info = getAvrDeviceInfo(); if (info == null) { Slog.w(TAG, "Failed to start arc action; No AVR device."); + invokeCallback(callback, HdmiControlManager.RESULT_TARGET_NOT_AVAILABLE); return; } if (!canStartArcUpdateAction(info.getLogicalAddress(), enabled)) { @@ -910,19 +916,37 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { if (enabled && !isConnectedToArcPort(info.getPhysicalAddress())) { displayOsd(OSD_MESSAGE_ARC_CONNECTED_INVALID_PORT); } + invokeCallback(callback, HdmiControlManager.RESULT_INCORRECT_MODE); + return; + } + if (enabled && mService.earcBlocksArcConnection()) { + Slog.i(TAG, + "ARC connection blocked because eARC connection is established or being " + + "established."); + invokeCallback(callback, HdmiControlManager.RESULT_INCORRECT_MODE); return; } - // Terminate opposite action and start action if not exist. + // Terminate opposite action and create an action with callback. if (enabled) { removeAction(RequestArcTerminationAction.class); - if (!hasAction(RequestArcInitiationAction.class)) { - addAndStartAction(new RequestArcInitiationAction(this, info.getLogicalAddress())); + if (hasAction(RequestArcInitiationAction.class)) { + RequestArcInitiationAction existingInitiationAction = + getActions(RequestArcInitiationAction.class).get(0); + existingInitiationAction.addCallback(callback); + } else { + addAndStartAction( + new RequestArcInitiationAction(this, info.getLogicalAddress(), callback)); } } else { removeAction(RequestArcInitiationAction.class); - if (!hasAction(RequestArcTerminationAction.class)) { - addAndStartAction(new RequestArcTerminationAction(this, info.getLogicalAddress())); + if (hasAction(RequestArcTerminationAction.class)) { + RequestArcTerminationAction existingTerminationAction = + getActions(RequestArcTerminationAction.class).get(0); + existingTerminationAction.addCallback(callback); + } else { + addAndStartAction( + new RequestArcTerminationAction(this, info.getLogicalAddress(), callback)); } } } @@ -1010,6 +1034,13 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { protected int handleInitiateArc(HdmiCecMessage message) { assertRunOnServiceThread(); + if (mService.earcBlocksArcConnection()) { + Slog.i(TAG, + "ARC connection blocked because eARC connection is established or being " + + "established."); + return Constants.ABORT_NOT_IN_CORRECT_MODE; + } + if (!canStartArcUpdateAction(message.getSource(), true)) { HdmiDeviceInfo avrDeviceInfo = getAvrDeviceInfo(); if (avrDeviceInfo == null) { @@ -1023,9 +1054,8 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { return Constants.ABORT_REFUSED; } - // In case where is started by - // need to clean up RequestArcInitiationAction. - removeAction(RequestArcInitiationAction.class); + // In case where is started by , this message is + // handled in RequestArcInitiationAction as well. SetArcTransmissionStateAction action = new SetArcTransmissionStateAction(this, message.getSource(), true); addAndStartAction(action); @@ -1059,9 +1089,8 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { return Constants.HANDLED; } // Do not check ARC configuration since the AVR might have been already removed. - // Clean up RequestArcTerminationAction in case was started by - // . - removeAction(RequestArcTerminationAction.class); + // In case where is started by , this + // message is handled in RequestArcTerminationAction as well. SetArcTransmissionStateAction action = new SetArcTransmissionStateAction(this, message.getSource(), false); addAndStartAction(action); diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java index 85bd16b2cb2f7..f66f8ea3ba771 100644 --- a/services/core/java/com/android/server/hdmi/HdmiControlService.java +++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java @@ -26,6 +26,7 @@ import static android.hardware.hdmi.HdmiControlManager.SOUNDBAR_MODE_ENABLED; import static com.android.server.hdmi.Constants.ADDR_UNREGISTERED; import static com.android.server.hdmi.Constants.DISABLED; import static com.android.server.hdmi.Constants.ENABLED; +import static com.android.server.hdmi.Constants.HDMI_EARC_STATUS_ARC_PENDING; import static com.android.server.hdmi.Constants.OPTION_MHL_ENABLE; import static com.android.server.hdmi.Constants.OPTION_MHL_INPUT_SWITCHING; import static com.android.server.hdmi.Constants.OPTION_MHL_POWER_CHARGE; @@ -392,7 +393,7 @@ public class HdmiControlService extends SystemService { // and the eARC HAL is present. @GuardedBy("mLock") @VisibleForTesting - protected boolean mEarcSupported; + private boolean mEarcSupported; // Set to true while the eARC feature is enabled. @GuardedBy("mLock") @@ -725,7 +726,7 @@ public class HdmiControlService extends SystemService { if (isEarcEnabled()) { initializeEarc(INITIATED_BY_BOOT_UP); } else { - setEarcEnabledInHal(false); + setEarcEnabledInHal(false, false); } } @@ -3236,6 +3237,9 @@ public class HdmiControlService extends SystemService { } private void invokeCallback(IHdmiControlCallback callback, int result) { + if (callback == null) { + return; + } try { callback.onComplete(result); } catch (RemoteException e) { @@ -3518,7 +3522,7 @@ public class HdmiControlService extends SystemService { } initializeEarc(startReason); } else { - setEarcEnabledInHal(false); + setEarcEnabledInHal(false, false); } } // TODO: Initialize MHL local devices. @@ -4414,8 +4418,17 @@ public class HdmiControlService extends SystemService { private void initializeEarc(int initiatedBy) { Slog.i(TAG, "eARC initialized, reason = " + initiatedBy); - setEarcEnabledInHal(true); initializeEarcLocalDevice(initiatedBy); + + if (initiatedBy == INITIATED_BY_ENABLE_EARC) { + // Since ARC and eARC cannot be connected simultaneously, we need to terminate ARC + // before even enabling eARC. + setEarcEnabledInHal(true, true); + } else { + // On boot, wake-up, and hotplug in, eARC will always be attempted before ARC. + // So there is no need to explicitly terminate ARC before enabling eARC. + setEarcEnabledInHal(true, false); + } } @ServiceThreadOnly @@ -4464,13 +4477,14 @@ public class HdmiControlService extends SystemService { @ServiceThreadOnly private void onEnableEarc() { + // This will terminate ARC as well. initializeEarc(INITIATED_BY_ENABLE_EARC); } @ServiceThreadOnly private void onDisableEarc() { disableEarcLocalDevice(); - setEarcEnabledInHal(false); + setEarcEnabledInHal(false, false); clearEarcLocalDevice(); } @@ -4504,12 +4518,28 @@ public class HdmiControlService extends SystemService { @ServiceThreadOnly @VisibleForTesting - protected void setEarcEnabledInHal(boolean enabled) { + protected void setEarcEnabledInHal(boolean enabled, boolean terminateArcFirst) { assertRunOnServiceThread(); - mEarcController.setEarcEnabled(enabled); - mCecController.setHpdSignalType( - enabled ? Constants.HDMI_HPD_TYPE_STATUS_BIT : Constants.HDMI_HPD_TYPE_PHYSICAL, - mEarcPortId); + if (terminateArcFirst) { + startArcAction(false, new IHdmiControlCallback.Stub() { + @Override + public void onComplete(int result) throws RemoteException { + // Independently of the result (i.e. independently of whether the ARC RX device + // responded with or not), we always end up terminating ARC in + // the HAL. As soon as we do that, we can enable eARC in the HAL. + mEarcController.setEarcEnabled(enabled); + mCecController.setHpdSignalType( + enabled ? Constants.HDMI_HPD_TYPE_STATUS_BIT + : Constants.HDMI_HPD_TYPE_PHYSICAL, + mEarcPortId); + } + }); + } else { + mEarcController.setEarcEnabled(enabled); + mCecController.setHpdSignalType( + enabled ? Constants.HDMI_HPD_TYPE_STATUS_BIT : Constants.HDMI_HPD_TYPE_PHYSICAL, + mEarcPortId); + } } @ServiceThreadOnly @@ -4540,4 +4570,21 @@ public class HdmiControlService extends SystemService { mEarcLocalDevice.handleEarcCapabilitiesReported(rawCapabilities); } } + + protected boolean earcBlocksArcConnection() { + if (mEarcLocalDevice == null) { + return false; + } + synchronized (mLock) { + return mEarcLocalDevice.mEarcStatus != HDMI_EARC_STATUS_ARC_PENDING; + } + } + + protected void startArcAction(boolean enabled, IHdmiControlCallback callback) { + if (!isTvDeviceEnabled()) { + invokeCallback(callback, HdmiControlManager.RESULT_INCORRECT_MODE); + } else { + tv().startArcAction(enabled, callback); + } + } } diff --git a/services/core/java/com/android/server/hdmi/HdmiEarcLocalDeviceTx.java b/services/core/java/com/android/server/hdmi/HdmiEarcLocalDeviceTx.java index c7c7702b871a1..abb8439092acd 100644 --- a/services/core/java/com/android/server/hdmi/HdmiEarcLocalDeviceTx.java +++ b/services/core/java/com/android/server/hdmi/HdmiEarcLocalDeviceTx.java @@ -18,6 +18,7 @@ package com.android.server.hdmi; import static com.android.server.hdmi.Constants.HDMI_EARC_STATUS_ARC_PENDING; import static com.android.server.hdmi.Constants.HDMI_EARC_STATUS_EARC_CONNECTED; +import static com.android.server.hdmi.Constants.HDMI_EARC_STATUS_EARC_PENDING; import static com.android.server.hdmi.Constants.HDMI_EARC_STATUS_IDLE; import android.hardware.hdmi.HdmiDeviceInfo; @@ -69,23 +70,36 @@ public class HdmiEarcLocalDeviceTx extends HdmiEarcLocalDevice { HdmiEarcLocalDeviceTx(HdmiControlService service) { super(service, HdmiDeviceInfo.DEVICE_TV); + synchronized (mLock) { + mEarcStatus = HDMI_EARC_STATUS_EARC_PENDING; + } mReportCapsHandler = new Handler(service.getServiceLooper()); mReportCapsRunnable = new ReportCapsRunnable(); } protected void handleEarcStateChange(@Constants.EarcStatus int status) { + int oldEarcStatus; synchronized (mLock) { HdmiLogger.debug(TAG, "eARC state change [old:%b new %b]", mEarcStatus, status); + oldEarcStatus = mEarcStatus; mEarcStatus = status; } mReportCapsHandler.removeCallbacksAndMessages(null); if (status == HDMI_EARC_STATUS_IDLE) { notifyEarcStatusToAudioService(false, new ArrayList<>()); + mService.startArcAction(false, null); } else if (status == HDMI_EARC_STATUS_ARC_PENDING) { notifyEarcStatusToAudioService(false, new ArrayList<>()); + mService.startArcAction(true, null); + } else if (status == HDMI_EARC_STATUS_EARC_PENDING + && oldEarcStatus == HDMI_EARC_STATUS_ARC_PENDING) { + mService.startArcAction(false, null); } else if (status == HDMI_EARC_STATUS_EARC_CONNECTED) { + if (oldEarcStatus == HDMI_EARC_STATUS_ARC_PENDING) { + mService.startArcAction(false, null); + } mReportCapsHandler.postDelayed(mReportCapsRunnable, REPORT_CAPS_MAX_DELAY_MS); } } diff --git a/services/core/java/com/android/server/hdmi/RequestArcAction.java b/services/core/java/com/android/server/hdmi/RequestArcAction.java index 3d9a2905f4fbc..54c8c00b88892 100644 --- a/services/core/java/com/android/server/hdmi/RequestArcAction.java +++ b/services/core/java/com/android/server/hdmi/RequestArcAction.java @@ -16,7 +16,9 @@ package com.android.server.hdmi; +import android.hardware.hdmi.HdmiControlManager; import android.hardware.hdmi.HdmiDeviceInfo; +import android.hardware.hdmi.IHdmiControlCallback; /** * Base feature action class for <Request ARC Initiation>/<Request ARC Termination>. @@ -35,41 +37,19 @@ abstract class RequestArcAction extends HdmiCecFeatureAction { * * @param source {@link HdmiCecLocalDevice} instance * @param avrAddress address of AV receiver. It should be AUDIO_SYSTEM type + * @param callback callback to inform about the status of the action * @throws IllegalArgumentException if device type of sourceAddress and avrAddress * is invalid */ - RequestArcAction(HdmiCecLocalDevice source, int avrAddress) { - super(source); + RequestArcAction(HdmiCecLocalDevice source, int avrAddress, IHdmiControlCallback callback) { + super(source, callback); HdmiUtils.verifyAddressType(getSourceAddress(), HdmiDeviceInfo.DEVICE_TV); HdmiUtils.verifyAddressType(avrAddress, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM); mAvrAddress = avrAddress; } - @Override - boolean processCommand(HdmiCecMessage cmd) { - if (mState != STATE_WATING_FOR_REQUEST_ARC_REQUEST_RESPONSE - || !HdmiUtils.checkCommandSource(cmd, mAvrAddress, TAG)) { - return false; - } - int opcode = cmd.getOpcode(); - switch (opcode) { - // Handles only here and, both and - // are handled in HdmiControlService itself because both can be - // received without or . - case Constants.MESSAGE_FEATURE_ABORT: - int originalOpcode = cmd.getParams()[0] & 0xFF; - if (originalOpcode == Constants.MESSAGE_REQUEST_ARC_TERMINATION) { - disableArcTransmission(); - finish(); - return true; - } else if (originalOpcode == Constants.MESSAGE_REQUEST_ARC_INITIATION) { - tv().disableArc(); - finish(); - return true; - } - return false; - } - return false; + RequestArcAction(HdmiCecLocalDevice source, int avrAddress) { + this(source, avrAddress, null); } protected final void disableArcTransmission() { @@ -86,6 +66,6 @@ abstract class RequestArcAction extends HdmiCecFeatureAction { } HdmiLogger.debug("[T] RequestArcAction."); disableArcTransmission(); - finish(); + finishWithCallback(HdmiControlManager.RESULT_TIMEOUT); } } diff --git a/services/core/java/com/android/server/hdmi/RequestArcInitiationAction.java b/services/core/java/com/android/server/hdmi/RequestArcInitiationAction.java index 3b7f1dd0d9715..db21a33ae3253 100644 --- a/services/core/java/com/android/server/hdmi/RequestArcInitiationAction.java +++ b/services/core/java/com/android/server/hdmi/RequestArcInitiationAction.java @@ -16,6 +16,8 @@ package com.android.server.hdmi; +import android.hardware.hdmi.HdmiControlManager; +import android.hardware.hdmi.IHdmiControlCallback; import android.hardware.tv.cec.V1_0.SendMessageResult; /** @@ -35,6 +37,16 @@ final class RequestArcInitiationAction extends RequestArcAction { super(source, avrAddress); } + /** + * @Constructor + * + * For more details look at {@link RequestArcAction#RequestArcAction}. + */ + RequestArcInitiationAction(HdmiCecLocalDevice source, int avrAddress, + IHdmiControlCallback callback) { + super(source, avrAddress, callback); + } + @Override boolean start() { // Seq #38 @@ -49,10 +61,34 @@ final class RequestArcInitiationAction extends RequestArcAction { if (error != SendMessageResult.SUCCESS) { // Turn off ARC status if fails. tv().disableArc(); - finish(); + finishWithCallback(HdmiControlManager.RESULT_TARGET_NOT_AVAILABLE); } } }); return true; } + + @Override + boolean processCommand(HdmiCecMessage cmd) { + if (mState != STATE_WATING_FOR_REQUEST_ARC_REQUEST_RESPONSE + || !HdmiUtils.checkCommandSource(cmd, mAvrAddress, TAG)) { + return false; + } + int opcode = cmd.getOpcode(); + switch (opcode) { + case Constants.MESSAGE_FEATURE_ABORT: + int originalOpcode = cmd.getParams()[0] & 0xFF; + if (originalOpcode == Constants.MESSAGE_REQUEST_ARC_INITIATION) { + tv().disableArc(); + finishWithCallback(HdmiControlManager.RESULT_TARGET_NOT_AVAILABLE); + return true; + } + return false; + case Constants.MESSAGE_INITIATE_ARC: + finishWithCallback(HdmiControlManager.RESULT_SUCCESS); + // This message still needs to be handled in HdmiCecLocalDeviceTv as well. + return false; + } + return false; + } } diff --git a/services/core/java/com/android/server/hdmi/RequestArcTerminationAction.java b/services/core/java/com/android/server/hdmi/RequestArcTerminationAction.java index 8b5a293102331..85128b69b5788 100644 --- a/services/core/java/com/android/server/hdmi/RequestArcTerminationAction.java +++ b/services/core/java/com/android/server/hdmi/RequestArcTerminationAction.java @@ -16,6 +16,8 @@ package com.android.server.hdmi; +import android.hardware.hdmi.HdmiControlManager; +import android.hardware.hdmi.IHdmiControlCallback; import android.hardware.tv.cec.V1_0.SendMessageResult; /** @@ -35,6 +37,16 @@ final class RequestArcTerminationAction extends RequestArcAction { super(source, avrAddress); } + /** + * @Constructor + * + * @see RequestArcAction#RequestArcAction + */ + RequestArcTerminationAction(HdmiCecLocalDevice source, int avrAddress, + IHdmiControlCallback callback) { + super(source, avrAddress, callback); + } + @Override boolean start() { mState = STATE_WATING_FOR_REQUEST_ARC_REQUEST_RESPONSE; @@ -49,10 +61,34 @@ final class RequestArcTerminationAction extends RequestArcAction { // If failed to send , start "Disabled" ARC // transmission action. disableArcTransmission(); - finish(); + finishWithCallback(HdmiControlManager.RESULT_TARGET_NOT_AVAILABLE); } } }); return true; } + + @Override + boolean processCommand(HdmiCecMessage cmd) { + if (mState != STATE_WATING_FOR_REQUEST_ARC_REQUEST_RESPONSE + || !HdmiUtils.checkCommandSource(cmd, mAvrAddress, TAG)) { + return false; + } + int opcode = cmd.getOpcode(); + switch (opcode) { + case Constants.MESSAGE_FEATURE_ABORT: + int originalOpcode = cmd.getParams()[0] & 0xFF; + if (originalOpcode == Constants.MESSAGE_REQUEST_ARC_TERMINATION) { + disableArcTransmission(); + finishWithCallback(HdmiControlManager.RESULT_TARGET_NOT_AVAILABLE); + return true; + } + return false; + case Constants.MESSAGE_TERMINATE_ARC: + finishWithCallback(HdmiControlManager.RESULT_SUCCESS); + // This message still needs to be handled in HdmiCecLocalDeviceTv as well. + return false; + } + return false; + } } diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java index 5246107685543..5dd29fda794d0 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java @@ -39,6 +39,7 @@ import android.content.Context; import android.hardware.hdmi.HdmiControlManager; import android.hardware.hdmi.HdmiDeviceInfo; import android.hardware.hdmi.HdmiPortInfo; +import android.hardware.hdmi.IHdmiControlCallback; import android.hardware.tv.cec.V1_0.SendMessageResult; import android.media.AudioManager; import android.os.Looper; @@ -96,6 +97,7 @@ public class HdmiCecLocalDeviceTvTest { private int mTvPhysicalAddress; private int mTvLogicalAddress; private boolean mWokenUp; + private boolean mEarcBlocksArc; private List mDeviceEventListeners = new ArrayList<>(); private class DeviceEventListener { @@ -155,6 +157,11 @@ public class HdmiCecLocalDeviceTvTest { return false; } + @Override + boolean isPowerStandbyOrTransient() { + return false; + } + @Override AudioManager getAudioManager() { return mAudioManager; @@ -164,6 +171,11 @@ public class HdmiCecLocalDeviceTvTest { void invokeDeviceEventListeners(HdmiDeviceInfo device, int status) { mDeviceEventListeners.add(new DeviceEventListener(device, status)); } + + @Override + protected boolean earcBlocksArcConnection() { + return mEarcBlocksArc; + } }; mHdmiControlService.setIoLooper(mMyLooper); @@ -175,16 +187,18 @@ public class HdmiCecLocalDeviceTvTest { mHdmiControlService.setHdmiMhlController(HdmiMhlControllerStub.create(mHdmiControlService)); HdmiPortInfo[] hdmiPortInfos = new HdmiPortInfo[2]; hdmiPortInfos[0] = - new HdmiPortInfo(1, HdmiPortInfo.PORT_INPUT, 0x1000, true, false, false); + new HdmiPortInfo(1, HdmiPortInfo.PORT_INPUT, 0x1000, true, false, false, false); hdmiPortInfos[1] = - new HdmiPortInfo(2, HdmiPortInfo.PORT_INPUT, 0x2000, true, false, true); + new HdmiPortInfo(2, HdmiPortInfo.PORT_INPUT, 0x2000, true, false, true, true); mNativeWrapper.setPortInfo(hdmiPortInfos); mHdmiControlService.initService(); mHdmiControlService.onBootPhase(PHASE_SYSTEM_SERVICES_READY); mPowerManager = new FakePowerManagerWrapper(context); mHdmiControlService.setPowerManager(mPowerManager); mTvPhysicalAddress = 0x0000; + mEarcBlocksArc = false; mNativeWrapper.setPhysicalAddress(mTvPhysicalAddress); + mHdmiControlService.setEarcEnabled(HdmiControlManager.EARC_FEATURE_DISABLED); mTestLooper.dispatchAll(); mHdmiCecLocalDeviceTv = mHdmiControlService.tv(); mTvLogicalAddress = mHdmiCecLocalDeviceTv.getDeviceInfo().getLogicalAddress(); @@ -196,6 +210,20 @@ public class HdmiCecLocalDeviceTvTest { mNativeWrapper.clearResultMessages(); } + private static class TestCallback extends IHdmiControlCallback.Stub { + private final ArrayList mCallbackResult = new ArrayList(); + + @Override + public void onComplete(int result) { + mCallbackResult.add(result); + } + + private int getResult() { + assertThat(mCallbackResult.size()).isEqualTo(1); + return mCallbackResult.get(0); + } + } + @Test public void initialPowerStateIsStandby() { assertThat(mHdmiCecLocalDeviceTv.getPowerStatus()).isEqualTo( @@ -426,9 +454,10 @@ public class HdmiCecLocalDeviceTvTest { public void startArcAction_enable_portDoesNotSupportArc() { // Emulate Audio device on port 0x1000 (does not support ARC) mNativeWrapper.setPortConnectionStatus(1, true); - HdmiCecMessage hdmiCecMessage = HdmiCecMessageBuilder.buildReportPhysicalAddressCommand( - ADDR_AUDIO_SYSTEM, 0x1000, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM); - mNativeWrapper.onCecMessage(hdmiCecMessage); + HdmiCecMessage reportPhysicalAddress = + HdmiCecMessageBuilder.buildReportPhysicalAddressCommand( + ADDR_AUDIO_SYSTEM, 0x1000, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM); + mNativeWrapper.onCecMessage(reportPhysicalAddress); mHdmiCecLocalDeviceTv.startArcAction(true); HdmiCecMessage requestArcInitiation = HdmiCecMessageBuilder.buildRequestArcInitiation( @@ -445,9 +474,10 @@ public class HdmiCecLocalDeviceTvTest { public void startArcAction_disable_portDoesNotSupportArc() { // Emulate Audio device on port 0x1000 (does not support ARC) mNativeWrapper.setPortConnectionStatus(1, true); - HdmiCecMessage hdmiCecMessage = HdmiCecMessageBuilder.buildReportPhysicalAddressCommand( - ADDR_AUDIO_SYSTEM, 0x1000, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM); - mNativeWrapper.onCecMessage(hdmiCecMessage); + HdmiCecMessage reportPhysicalAddress = + HdmiCecMessageBuilder.buildReportPhysicalAddressCommand( + ADDR_AUDIO_SYSTEM, 0x1000, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM); + mNativeWrapper.onCecMessage(reportPhysicalAddress); mHdmiCecLocalDeviceTv.startArcAction(false); HdmiCecMessage requestArcInitiation = HdmiCecMessageBuilder.buildRequestArcInitiation( @@ -464,9 +494,10 @@ public class HdmiCecLocalDeviceTvTest { public void startArcAction_enable_portSupportsArc() { // Emulate Audio device on port 0x2000 (supports ARC) mNativeWrapper.setPortConnectionStatus(2, true); - HdmiCecMessage hdmiCecMessage = HdmiCecMessageBuilder.buildReportPhysicalAddressCommand( - ADDR_AUDIO_SYSTEM, 0x2000, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM); - mNativeWrapper.onCecMessage(hdmiCecMessage); + HdmiCecMessage reportPhysicalAddress = + HdmiCecMessageBuilder.buildReportPhysicalAddressCommand( + ADDR_AUDIO_SYSTEM, 0x2000, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM); + mNativeWrapper.onCecMessage(reportPhysicalAddress); mTestLooper.dispatchAll(); mHdmiCecLocalDeviceTv.startArcAction(true); @@ -485,9 +516,10 @@ public class HdmiCecLocalDeviceTvTest { public void startArcAction_disable_portSupportsArc() { // Emulate Audio device on port 0x2000 (supports ARC) mNativeWrapper.setPortConnectionStatus(2, true); - HdmiCecMessage hdmiCecMessage = HdmiCecMessageBuilder.buildReportPhysicalAddressCommand( - ADDR_AUDIO_SYSTEM, 0x2000, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM); - mNativeWrapper.onCecMessage(hdmiCecMessage); + HdmiCecMessage reportPhysicalAddress = + HdmiCecMessageBuilder.buildReportPhysicalAddressCommand( + ADDR_AUDIO_SYSTEM, 0x2000, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM); + mNativeWrapper.onCecMessage(reportPhysicalAddress); mTestLooper.dispatchAll(); mHdmiCecLocalDeviceTv.startArcAction(false); @@ -522,9 +554,10 @@ public class HdmiCecLocalDeviceTvTest { public void handleInitiateArc_portDoesNotSupportArc() { // Emulate Audio device on port 0x1000 (does not support ARC) mNativeWrapper.setPortConnectionStatus(1, true); - HdmiCecMessage hdmiCecMessage = HdmiCecMessageBuilder.buildReportPhysicalAddressCommand( - ADDR_AUDIO_SYSTEM, 0x1000, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM); - mNativeWrapper.onCecMessage(hdmiCecMessage); + HdmiCecMessage reportPhysicalAddress = + HdmiCecMessageBuilder.buildReportPhysicalAddressCommand( + ADDR_AUDIO_SYSTEM, 0x1000, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM); + mNativeWrapper.onCecMessage(reportPhysicalAddress); HdmiCecMessage requestArcInitiation = HdmiCecMessageBuilder.buildInitiateArc( ADDR_AUDIO_SYSTEM, @@ -544,9 +577,10 @@ public class HdmiCecLocalDeviceTvTest { public void handleInitiateArc_portSupportsArc() { // Emulate Audio device on port 0x2000 (supports ARC) mNativeWrapper.setPortConnectionStatus(2, true); - HdmiCecMessage hdmiCecMessage = HdmiCecMessageBuilder.buildReportPhysicalAddressCommand( - ADDR_AUDIO_SYSTEM, 0x2000, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM); - mNativeWrapper.onCecMessage(hdmiCecMessage); + HdmiCecMessage reportPhysicalAddress = + HdmiCecMessageBuilder.buildReportPhysicalAddressCommand( + ADDR_AUDIO_SYSTEM, 0x2000, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM); + mNativeWrapper.onCecMessage(reportPhysicalAddress); mTestLooper.dispatchAll(); HdmiCecMessage requestArcInitiation = HdmiCecMessageBuilder.buildInitiateArc( @@ -574,6 +608,66 @@ public class HdmiCecLocalDeviceTvTest { assertThat(mNativeWrapper.getResultMessages()).contains(reportArcInitiated); } + @Test + public void handleTerminateArc_noAudioDevice() { + HdmiCecMessage terminateArc = HdmiCecMessageBuilder.buildTerminateArc( + ADDR_AUDIO_SYSTEM, + ADDR_TV); + + mNativeWrapper.onCecMessage(terminateArc); + mTestLooper.dispatchAll(); + + HdmiCecMessage reportArcTerminated = HdmiCecMessageBuilder.buildReportArcTerminated( + ADDR_TV, + ADDR_AUDIO_SYSTEM); + assertThat(mNativeWrapper.getResultMessages()).contains(reportArcTerminated); + } + + @Test + public void handleTerminateArc_portDoesNotSupportArc() { + // Emulate Audio device on port 0x1000 (does not support ARC) + mNativeWrapper.setPortConnectionStatus(1, true); + HdmiCecMessage reportPhysicalAddress = + HdmiCecMessageBuilder.buildReportPhysicalAddressCommand( + ADDR_AUDIO_SYSTEM, 0x1000, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM); + mNativeWrapper.onCecMessage(reportPhysicalAddress); + + HdmiCecMessage terminateArc = HdmiCecMessageBuilder.buildTerminateArc( + ADDR_AUDIO_SYSTEM, + ADDR_TV); + + mNativeWrapper.onCecMessage(terminateArc); + mTestLooper.dispatchAll(); + + HdmiCecMessage reportArcTerminated = HdmiCecMessageBuilder.buildReportArcTerminated( + ADDR_TV, + ADDR_AUDIO_SYSTEM); + assertThat(mNativeWrapper.getResultMessages()).contains(reportArcTerminated); + } + + @Test + public void handleTerminateArc_portSupportsArc() { + // Emulate Audio device on port 0x2000 (supports ARC) + mNativeWrapper.setPortConnectionStatus(2, true); + HdmiCecMessage reportPhysicalAddress = + HdmiCecMessageBuilder.buildReportPhysicalAddressCommand( + ADDR_AUDIO_SYSTEM, 0x2000, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM); + mNativeWrapper.onCecMessage(reportPhysicalAddress); + mTestLooper.dispatchAll(); + + HdmiCecMessage terminateArc = HdmiCecMessageBuilder.buildTerminateArc( + ADDR_AUDIO_SYSTEM, + ADDR_TV); + + mNativeWrapper.onCecMessage(terminateArc); + mTestLooper.dispatchAll(); + + HdmiCecMessage reportArcTerminated = HdmiCecMessageBuilder.buildReportArcTerminated( + ADDR_TV, + ADDR_AUDIO_SYSTEM); + assertThat(mNativeWrapper.getResultMessages()).contains(reportArcTerminated); + } + @Test public void supportsRecordTvScreen() { HdmiCecMessage recordTvScreen = HdmiCecMessage.build(ADDR_RECORDER_1, mTvLogicalAddress, @@ -595,9 +689,10 @@ public class HdmiCecLocalDeviceTvTest { HdmiControlManager.SYSTEM_AUDIO_CONTROL_ENABLED); // Emulate Audio device on port 0x1000 (does not support ARC) mNativeWrapper.setPortConnectionStatus(1, true); - HdmiCecMessage hdmiCecMessage = HdmiCecMessageBuilder.buildReportPhysicalAddressCommand( - ADDR_AUDIO_SYSTEM, 0x1000, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM); - mNativeWrapper.onCecMessage(hdmiCecMessage); + HdmiCecMessage reportPhysicalAddress = + HdmiCecMessageBuilder.buildReportPhysicalAddressCommand( + ADDR_AUDIO_SYSTEM, 0x1000, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM); + mNativeWrapper.onCecMessage(reportPhysicalAddress); mTestLooper.dispatchAll(); HdmiCecFeatureAction systemAudioAutoInitiationAction = @@ -636,9 +731,9 @@ public class HdmiCecLocalDeviceTvTest { public void hotplugDetectionAction_discoversDeviceAfterMessageReceived() { // Playback 1 sends a message before ACKing a poll mNativeWrapper.setPollAddressResponse(ADDR_PLAYBACK_1, SendMessageResult.NACK); - HdmiCecMessage hdmiCecMessage = HdmiCecMessageBuilder.buildActiveSource( + HdmiCecMessage activeSource = HdmiCecMessageBuilder.buildActiveSource( ADDR_PLAYBACK_1, ADDR_TV); - mNativeWrapper.onCecMessage(hdmiCecMessage); + mNativeWrapper.onCecMessage(activeSource); mTestLooper.dispatchAll(); // Playback 1 begins ACKing polls, allowing detection by HotplugDetectionAction @@ -812,12 +907,12 @@ public class HdmiCecLocalDeviceTvTest { mTestLooper.dispatchAll(); // [Not in correct mode] not sent - HdmiCecMessage featureAbortMessage = HdmiCecMessageBuilder.buildFeatureAbortCommand( + HdmiCecMessage featureAbort = HdmiCecMessageBuilder.buildFeatureAbortCommand( ADDR_TV, ADDR_PLAYBACK_1, Constants.MESSAGE_SET_AUDIO_VOLUME_LEVEL, Constants.ABORT_NOT_IN_CORRECT_MODE); - assertThat(mNativeWrapper.getResultMessages()).doesNotContain(featureAbortMessage); + assertThat(mNativeWrapper.getResultMessages()).doesNotContain(featureAbort); // uses volume range [0, 100]; STREAM_MUSIC uses range [0, 25] verify(mAudioManager).setStreamVolume(eq(AudioManager.STREAM_MUSIC), eq(5), anyInt()); @@ -838,12 +933,12 @@ public class HdmiCecLocalDeviceTvTest { mTestLooper.dispatchAll(); // [Not in correct mode] sent - HdmiCecMessage featureAbortMessage = HdmiCecMessageBuilder.buildFeatureAbortCommand( + HdmiCecMessage featureAbort = HdmiCecMessageBuilder.buildFeatureAbortCommand( ADDR_TV, ADDR_PLAYBACK_1, Constants.MESSAGE_SET_AUDIO_VOLUME_LEVEL, Constants.ABORT_NOT_IN_CORRECT_MODE); - assertThat(mNativeWrapper.getResultMessages()).contains(featureAbortMessage); + assertThat(mNativeWrapper.getResultMessages()).contains(featureAbort); // AudioManager not notified of volume change verify(mAudioManager, never()).setStreamVolume(eq(AudioManager.STREAM_MUSIC), anyInt(), @@ -853,11 +948,11 @@ public class HdmiCecLocalDeviceTvTest { @Test public void tvSendRequestArcTerminationOnSleep() { // Emulate Audio device on port 0x2000 (supports ARC) - mNativeWrapper.setPortConnectionStatus(2, true); - HdmiCecMessage hdmiCecMessage = HdmiCecMessageBuilder.buildReportPhysicalAddressCommand( - ADDR_AUDIO_SYSTEM, 0x2000, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM); - mNativeWrapper.onCecMessage(hdmiCecMessage); + HdmiCecMessage reportPhysicalAddress = + HdmiCecMessageBuilder.buildReportPhysicalAddressCommand( + ADDR_AUDIO_SYSTEM, 0x2000, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM); + mNativeWrapper.onCecMessage(reportPhysicalAddress); mTestLooper.dispatchAll(); mHdmiCecLocalDeviceTv.startArcAction(true); @@ -898,4 +993,560 @@ public class HdmiCecLocalDeviceTvTest { assertThat(mNativeWrapper.getResultMessages()).contains(requestArcTermination); } + @Test + public void startArcAction_enable_earcBlocksArc() { + mHdmiControlService.setEarcEnabled(HdmiControlManager.EARC_FEATURE_ENABLED); + mTestLooper.dispatchAll(); + + mEarcBlocksArc = true; + + // Emulate Audio device on port 0x2000 (supports ARC and eARC) + mNativeWrapper.setPortConnectionStatus(2, true); + HdmiCecMessage reportPhysicalAddress = + HdmiCecMessageBuilder.buildReportPhysicalAddressCommand( + ADDR_AUDIO_SYSTEM, 0x2000, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM); + mNativeWrapper.onCecMessage(reportPhysicalAddress); + mTestLooper.dispatchAll(); + + mHdmiCecLocalDeviceTv.startArcAction(true); + mTestLooper.dispatchAll(); + HdmiCecMessage requestArcInitiation = HdmiCecMessageBuilder.buildRequestArcInitiation( + ADDR_TV, + ADDR_AUDIO_SYSTEM); + HdmiCecMessage requestArcTermination = HdmiCecMessageBuilder.buildRequestArcTermination( + ADDR_TV, + ADDR_AUDIO_SYSTEM); + assertThat(mNativeWrapper.getResultMessages()).doesNotContain(requestArcInitiation); + assertThat(mNativeWrapper.getResultMessages()).doesNotContain(requestArcTermination); + } + + @Test + public void startArcAction_enable_earcDoesNotBlockArc() { + mHdmiControlService.setEarcEnabled(HdmiControlManager.EARC_FEATURE_ENABLED); + mTestLooper.dispatchAll(); + + mEarcBlocksArc = false; + + // Emulate Audio device on port 0x2000 (supports ARC and eARC) + mNativeWrapper.setPortConnectionStatus(2, true); + HdmiCecMessage reportPhysicalAddress = + HdmiCecMessageBuilder.buildReportPhysicalAddressCommand( + ADDR_AUDIO_SYSTEM, 0x2000, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM); + mNativeWrapper.onCecMessage(reportPhysicalAddress); + mTestLooper.dispatchAll(); + + mHdmiCecLocalDeviceTv.startArcAction(true); + mTestLooper.dispatchAll(); + HdmiCecMessage requestArcInitiation = HdmiCecMessageBuilder.buildRequestArcInitiation( + ADDR_TV, + ADDR_AUDIO_SYSTEM); + HdmiCecMessage requestArcTermination = HdmiCecMessageBuilder.buildRequestArcTermination( + ADDR_TV, + ADDR_AUDIO_SYSTEM); + assertThat(mNativeWrapper.getResultMessages()).contains(requestArcInitiation); + assertThat(mNativeWrapper.getResultMessages()).doesNotContain(requestArcTermination); + } + + @Test + public void startArcAction_disable_earcBlocksArc() { + mHdmiControlService.setEarcEnabled(HdmiControlManager.EARC_FEATURE_ENABLED); + mTestLooper.dispatchAll(); + + mEarcBlocksArc = true; + + // Emulate Audio device on port 0x2000 (supports ARC and eARC) + mNativeWrapper.setPortConnectionStatus(2, true); + HdmiCecMessage reportPhysicalAddress = + HdmiCecMessageBuilder.buildReportPhysicalAddressCommand( + ADDR_AUDIO_SYSTEM, 0x2000, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM); + mNativeWrapper.onCecMessage(reportPhysicalAddress); + mTestLooper.dispatchAll(); + + mHdmiCecLocalDeviceTv.startArcAction(false); + mTestLooper.dispatchAll(); + HdmiCecMessage requestArcInitiation = HdmiCecMessageBuilder.buildRequestArcInitiation( + ADDR_TV, + ADDR_AUDIO_SYSTEM); + HdmiCecMessage requestArcTermination = HdmiCecMessageBuilder.buildRequestArcTermination( + ADDR_TV, + ADDR_AUDIO_SYSTEM); + assertThat(mNativeWrapper.getResultMessages()).doesNotContain(requestArcInitiation); + assertThat(mNativeWrapper.getResultMessages()).contains(requestArcTermination); + } + + @Test + public void handleInitiateArc_earcBlocksArc() { + mHdmiControlService.setEarcEnabled(HdmiControlManager.EARC_FEATURE_ENABLED); + mTestLooper.dispatchAll(); + + mEarcBlocksArc = true; + + // Emulate Audio device on port 0x2000 (supports ARC and eARC) + mNativeWrapper.setPortConnectionStatus(2, true); + HdmiCecMessage reportPhysicalAddress = + HdmiCecMessageBuilder.buildReportPhysicalAddressCommand( + ADDR_AUDIO_SYSTEM, 0x2000, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM); + mNativeWrapper.onCecMessage(reportPhysicalAddress); + mTestLooper.dispatchAll(); + + HdmiCecMessage requestArcInitiation = HdmiCecMessageBuilder.buildInitiateArc( + ADDR_AUDIO_SYSTEM, + ADDR_TV); + + mNativeWrapper.onCecMessage(requestArcInitiation); + mTestLooper.dispatchAll(); + + HdmiCecMessage featureAbort = HdmiCecMessageBuilder.buildFeatureAbortCommand( + ADDR_TV, + ADDR_AUDIO_SYSTEM, + Constants.MESSAGE_INITIATE_ARC, + Constants.ABORT_NOT_IN_CORRECT_MODE); + assertThat(mNativeWrapper.getResultMessages()).contains(featureAbort); + } + + @Test + public void handleInitiateArc_earcDoesNotBlockArc() { + mHdmiControlService.setEarcEnabled(HdmiControlManager.EARC_FEATURE_ENABLED); + mTestLooper.dispatchAll(); + + mEarcBlocksArc = false; + + // Emulate Audio device on port 0x2000 (supports ARC and eARC) + mNativeWrapper.setPortConnectionStatus(2, true); + HdmiCecMessage reportPhysicalAddress = + HdmiCecMessageBuilder.buildReportPhysicalAddressCommand( + ADDR_AUDIO_SYSTEM, 0x2000, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM); + mNativeWrapper.onCecMessage(reportPhysicalAddress); + mTestLooper.dispatchAll(); + + HdmiCecMessage requestArcInitiation = HdmiCecMessageBuilder.buildInitiateArc( + ADDR_AUDIO_SYSTEM, + ADDR_TV); + + mNativeWrapper.onCecMessage(requestArcInitiation); + mTestLooper.dispatchAll(); + + HdmiCecMessage reportArcInitiated = HdmiCecMessageBuilder.buildReportArcInitiated( + ADDR_TV, + ADDR_AUDIO_SYSTEM); + // should only be sent after SAD querying is done + assertThat(mNativeWrapper.getResultMessages()).doesNotContain(reportArcInitiated); + + // Finish querying SADs + assertThat(mNativeWrapper.getResultMessages()).contains(SAD_QUERY); + mNativeWrapper.clearResultMessages(); + mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS); + mTestLooper.dispatchAll(); + assertThat(mNativeWrapper.getResultMessages()).contains(SAD_QUERY); + mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS); + mTestLooper.dispatchAll(); + + assertThat(mNativeWrapper.getResultMessages()).contains(reportArcInitiated); + } + + @Test + public void handleTerminateArc_earcBlocksArc() { + mHdmiControlService.setEarcEnabled(HdmiControlManager.EARC_FEATURE_ENABLED); + mTestLooper.dispatchAll(); + + mEarcBlocksArc = true; + + // Emulate Audio device on port 0x2000 (supports ARC and eARC) + mNativeWrapper.setPortConnectionStatus(2, true); + HdmiCecMessage reportPhysicalAddress = + HdmiCecMessageBuilder.buildReportPhysicalAddressCommand( + ADDR_AUDIO_SYSTEM, 0x2000, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM); + mNativeWrapper.onCecMessage(reportPhysicalAddress); + mTestLooper.dispatchAll(); + + HdmiCecMessage terminateArc = HdmiCecMessageBuilder.buildTerminateArc( + ADDR_AUDIO_SYSTEM, + ADDR_TV); + + mNativeWrapper.onCecMessage(terminateArc); + mTestLooper.dispatchAll(); + + HdmiCecMessage reportArcTerminated = HdmiCecMessageBuilder.buildReportArcTerminated( + ADDR_TV, + ADDR_AUDIO_SYSTEM); + assertThat(mNativeWrapper.getResultMessages()).contains(reportArcTerminated); + } + + @Test + public void startArcAction_initiation_noAvr() { + TestCallback callback = new TestCallback(); + + mHdmiCecLocalDeviceTv.startArcAction(true, callback); + mTestLooper.dispatchAll(); + + assertThat(callback.getResult()).isEqualTo(HdmiControlManager.RESULT_TARGET_NOT_AVAILABLE); + } + + @Test + public void startArcAction_initiation_portNotConnected() { + // Emulate Audio device on port 0x2000 (supports ARC) + HdmiCecMessage reportPhysicalAddress = + HdmiCecMessageBuilder.buildReportPhysicalAddressCommand( + ADDR_AUDIO_SYSTEM, 0x2000, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM); + mNativeWrapper.onCecMessage(reportPhysicalAddress); + mTestLooper.dispatchAll(); + // Emulate port disconnect + mNativeWrapper.setPortConnectionStatus(2, false); + + TestCallback callback = new TestCallback(); + + mHdmiCecLocalDeviceTv.startArcAction(true, callback); + mTestLooper.dispatchAll(); + + assertThat(callback.getResult()).isEqualTo(HdmiControlManager.RESULT_INCORRECT_MODE); + } + + @Test + public void startArcAction_initiation_portDoesNotSupportArc() { + // Emulate Audio device on port 0x1000 (Doesn´t support ARC) + mNativeWrapper.setPortConnectionStatus(1, true); + HdmiCecMessage reportPhysicalAddress = + HdmiCecMessageBuilder.buildReportPhysicalAddressCommand( + ADDR_AUDIO_SYSTEM, 0x1000, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM); + mNativeWrapper.onCecMessage(reportPhysicalAddress); + mTestLooper.dispatchAll(); + + TestCallback callback = new TestCallback(); + + mHdmiCecLocalDeviceTv.startArcAction(true, callback); + mTestLooper.dispatchAll(); + + assertThat(callback.getResult()).isEqualTo(HdmiControlManager.RESULT_INCORRECT_MODE); + } + + @Test + public void startArcAction_initiation_indirectPhysicalAddress() { + // Emulate Audio device on port 0x2000 (Supports ARC) + mNativeWrapper.setPortConnectionStatus(2, true); + HdmiCecMessage reportPhysicalAddress = + HdmiCecMessageBuilder.buildReportPhysicalAddressCommand( + ADDR_AUDIO_SYSTEM, 0x2320, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM); + mNativeWrapper.onCecMessage(reportPhysicalAddress); + mTestLooper.dispatchAll(); + + TestCallback callback = new TestCallback(); + + mHdmiCecLocalDeviceTv.startArcAction(true, callback); + mTestLooper.dispatchAll(); + + assertThat(callback.getResult()).isEqualTo(HdmiControlManager.RESULT_INCORRECT_MODE); + } + + @Test + public void startArcAction_initiation_earcBlocksArc() { + // Emulate Audio device on port 0x2000 (Supports ARC) + mNativeWrapper.setPortConnectionStatus(2, true); + HdmiCecMessage reportPhysicalAddress = + HdmiCecMessageBuilder.buildReportPhysicalAddressCommand( + ADDR_AUDIO_SYSTEM, 0x2000, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM); + mNativeWrapper.onCecMessage(reportPhysicalAddress); + mTestLooper.dispatchAll(); + + mEarcBlocksArc = true; + + TestCallback callback = new TestCallback(); + + mHdmiCecLocalDeviceTv.startArcAction(true, callback); + mTestLooper.dispatchAll(); + + assertThat(callback.getResult()).isEqualTo(HdmiControlManager.RESULT_INCORRECT_MODE); + } + + @Test + public void startArcAction_initiation_messageNotAcked() { + // Emulate Audio device on port 0x2000 (Supports ARC) + mNativeWrapper.setPortConnectionStatus(2, true); + HdmiCecMessage reportPhysicalAddress = + HdmiCecMessageBuilder.buildReportPhysicalAddressCommand( + ADDR_AUDIO_SYSTEM, 0x2000, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM); + mNativeWrapper.onCecMessage(reportPhysicalAddress); + mTestLooper.dispatchAll(); + + mNativeWrapper.setMessageSendResult( + Constants.MESSAGE_REQUEST_ARC_INITIATION, SendMessageResult.NACK); + mTestLooper.dispatchAll(); + + TestCallback callback = new TestCallback(); + + mHdmiCecLocalDeviceTv.startArcAction(true, callback); + mTestLooper.dispatchAll(); + + HdmiCecMessage requestArcInitiation = HdmiCecMessageBuilder.buildRequestArcInitiation( + ADDR_TV, + ADDR_AUDIO_SYSTEM); + assertThat(mNativeWrapper.getResultMessages()).contains(requestArcInitiation); + assertThat(callback.getResult()).isEqualTo(HdmiControlManager.RESULT_TARGET_NOT_AVAILABLE); + } + + @Test + public void startArcAction_initiation_timeout() { + // Emulate Audio device on port 0x2000 (Supports ARC) + mNativeWrapper.setPortConnectionStatus(2, true); + HdmiCecMessage reportPhysicalAddress = + HdmiCecMessageBuilder.buildReportPhysicalAddressCommand( + ADDR_AUDIO_SYSTEM, 0x2000, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM); + mNativeWrapper.onCecMessage(reportPhysicalAddress); + mTestLooper.dispatchAll(); + + TestCallback callback = new TestCallback(); + + mHdmiCecLocalDeviceTv.startArcAction(true, callback); + mTestLooper.dispatchAll(); + + HdmiCecMessage requestArcInitiation = HdmiCecMessageBuilder.buildRequestArcInitiation( + ADDR_TV, + ADDR_AUDIO_SYSTEM); + assertThat(mNativeWrapper.getResultMessages()).contains(requestArcInitiation); + mTestLooper.moveTimeForward(TIMEOUT_MS); + mTestLooper.dispatchAll(); + assertThat(callback.getResult()).isEqualTo(HdmiControlManager.RESULT_TIMEOUT); + } + + @Test + public void startArcAction_initiation_featureAbort() { + // Emulate Audio device on port 0x2000 (Supports ARC) + mNativeWrapper.setPortConnectionStatus(2, true); + HdmiCecMessage reportPhysicalAddress = + HdmiCecMessageBuilder.buildReportPhysicalAddressCommand( + ADDR_AUDIO_SYSTEM, 0x2000, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM); + mNativeWrapper.onCecMessage(reportPhysicalAddress); + mTestLooper.dispatchAll(); + + TestCallback callback = new TestCallback(); + + mHdmiCecLocalDeviceTv.startArcAction(true, callback); + mTestLooper.dispatchAll(); + + HdmiCecMessage requestArcInitiation = HdmiCecMessageBuilder.buildRequestArcInitiation( + ADDR_TV, + ADDR_AUDIO_SYSTEM); + assertThat(mNativeWrapper.getResultMessages()).contains(requestArcInitiation); + + HdmiCecMessage featureAbort = HdmiCecMessageBuilder.buildFeatureAbortCommand( + ADDR_AUDIO_SYSTEM, + ADDR_TV, + Constants.MESSAGE_REQUEST_ARC_INITIATION, + Constants.ABORT_NOT_IN_CORRECT_MODE); + mNativeWrapper.onCecMessage(featureAbort); + mTestLooper.dispatchAll(); + + assertThat(callback.getResult()).isEqualTo(HdmiControlManager.RESULT_TARGET_NOT_AVAILABLE); + } + + @Test + public void startArcAction_initiation_success() { + // Emulate Audio device on port 0x2000 (Supports ARC) + mNativeWrapper.setPortConnectionStatus(2, true); + HdmiCecMessage reportPhysicalAddress = + HdmiCecMessageBuilder.buildReportPhysicalAddressCommand( + ADDR_AUDIO_SYSTEM, 0x2000, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM); + mNativeWrapper.onCecMessage(reportPhysicalAddress); + mTestLooper.dispatchAll(); + + TestCallback callback = new TestCallback(); + + mHdmiCecLocalDeviceTv.startArcAction(true, callback); + mTestLooper.dispatchAll(); + + HdmiCecMessage requestArcInitiation = HdmiCecMessageBuilder.buildRequestArcInitiation( + ADDR_TV, + ADDR_AUDIO_SYSTEM); + assertThat(mNativeWrapper.getResultMessages()).contains(requestArcInitiation); + + HdmiCecMessage initiateArc = HdmiCecMessageBuilder.buildInitiateArc( + ADDR_AUDIO_SYSTEM, + ADDR_TV); + mNativeWrapper.onCecMessage(initiateArc); + mTestLooper.dispatchAll(); + + assertThat(callback.getResult()).isEqualTo(HdmiControlManager.RESULT_SUCCESS); + } + + @Test + public void startArcAction_termination_noAvr() { + TestCallback callback = new TestCallback(); + + mHdmiCecLocalDeviceTv.startArcAction(false, callback); + mTestLooper.dispatchAll(); + + assertThat(callback.getResult()).isEqualTo(HdmiControlManager.RESULT_TARGET_NOT_AVAILABLE); + } + + @Test + public void startArcAction_termination_portDoesNotSupportArc() { + // Emulate Audio device on port 0x1000 (Doesn´t support ARC) + mNativeWrapper.setPortConnectionStatus(1, true); + HdmiCecMessage reportPhysicalAddress = + HdmiCecMessageBuilder.buildReportPhysicalAddressCommand( + ADDR_AUDIO_SYSTEM, 0x1000, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM); + mNativeWrapper.onCecMessage(reportPhysicalAddress); + mTestLooper.dispatchAll(); + + TestCallback callback = new TestCallback(); + + mHdmiCecLocalDeviceTv.startArcAction(false, callback); + mTestLooper.dispatchAll(); + + assertThat(callback.getResult()).isEqualTo(HdmiControlManager.RESULT_INCORRECT_MODE); + } + + @Test + public void startArcAction_termination_messageNotAcked() { + // Emulate Audio device on port 0x2000 (Supports ARC) + mNativeWrapper.setPortConnectionStatus(2, true); + HdmiCecMessage reportPhysicalAddress = + HdmiCecMessageBuilder.buildReportPhysicalAddressCommand( + ADDR_AUDIO_SYSTEM, 0x2000, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM); + mNativeWrapper.onCecMessage(reportPhysicalAddress); + mTestLooper.dispatchAll(); + + mNativeWrapper.setMessageSendResult( + Constants.MESSAGE_REQUEST_ARC_TERMINATION, SendMessageResult.NACK); + mTestLooper.dispatchAll(); + + TestCallback callback = new TestCallback(); + + mHdmiCecLocalDeviceTv.startArcAction(false, callback); + mTestLooper.dispatchAll(); + + HdmiCecMessage requestArcTermination = HdmiCecMessageBuilder.buildRequestArcTermination( + ADDR_TV, + ADDR_AUDIO_SYSTEM); + assertThat(mNativeWrapper.getResultMessages()).contains(requestArcTermination); + assertThat(callback.getResult()).isEqualTo(HdmiControlManager.RESULT_TARGET_NOT_AVAILABLE); + } + + @Test + public void startArcAction_termination_timeout() { + // Emulate Audio device on port 0x2000 (Supports ARC) + mNativeWrapper.setPortConnectionStatus(2, true); + HdmiCecMessage reportPhysicalAddress = + HdmiCecMessageBuilder.buildReportPhysicalAddressCommand( + ADDR_AUDIO_SYSTEM, 0x2000, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM); + mNativeWrapper.onCecMessage(reportPhysicalAddress); + mTestLooper.dispatchAll(); + + TestCallback callback = new TestCallback(); + + mHdmiCecLocalDeviceTv.startArcAction(false, callback); + mTestLooper.dispatchAll(); + + HdmiCecMessage requestArcTermination = HdmiCecMessageBuilder.buildRequestArcTermination( + ADDR_TV, + ADDR_AUDIO_SYSTEM); + assertThat(mNativeWrapper.getResultMessages()).contains(requestArcTermination); + mTestLooper.moveTimeForward(TIMEOUT_MS); + mTestLooper.dispatchAll(); + assertThat(callback.getResult()).isEqualTo(HdmiControlManager.RESULT_TIMEOUT); + } + + @Test + public void startArcAction_termination_featureAbort() { + // Emulate Audio device on port 0x2000 (Supports ARC) + mNativeWrapper.setPortConnectionStatus(2, true); + HdmiCecMessage reportPhysicalAddress = + HdmiCecMessageBuilder.buildReportPhysicalAddressCommand( + ADDR_AUDIO_SYSTEM, 0x2000, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM); + mNativeWrapper.onCecMessage(reportPhysicalAddress); + mTestLooper.dispatchAll(); + + TestCallback callback = new TestCallback(); + + mHdmiCecLocalDeviceTv.startArcAction(false, callback); + mTestLooper.dispatchAll(); + + HdmiCecMessage requestArcTermination = HdmiCecMessageBuilder.buildRequestArcTermination( + ADDR_TV, + ADDR_AUDIO_SYSTEM); + assertThat(mNativeWrapper.getResultMessages()).contains(requestArcTermination); + + HdmiCecMessage featureAbort = HdmiCecMessageBuilder.buildFeatureAbortCommand( + ADDR_AUDIO_SYSTEM, + ADDR_TV, + Constants.MESSAGE_REQUEST_ARC_TERMINATION, + Constants.ABORT_NOT_IN_CORRECT_MODE); + mNativeWrapper.onCecMessage(featureAbort); + mTestLooper.dispatchAll(); + + assertThat(callback.getResult()).isEqualTo(HdmiControlManager.RESULT_TARGET_NOT_AVAILABLE); + } + + @Test + public void startArcAction_termination_success() { + // Emulate Audio device on port 0x2000 (Supports ARC) + mNativeWrapper.setPortConnectionStatus(2, true); + HdmiCecMessage reportPhysicalAddress = + HdmiCecMessageBuilder.buildReportPhysicalAddressCommand( + ADDR_AUDIO_SYSTEM, 0x2000, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM); + mNativeWrapper.onCecMessage(reportPhysicalAddress); + mTestLooper.dispatchAll(); + + TestCallback callback = new TestCallback(); + + mHdmiCecLocalDeviceTv.startArcAction(false, callback); + mTestLooper.dispatchAll(); + + HdmiCecMessage requestArcTermination = HdmiCecMessageBuilder.buildRequestArcTermination( + ADDR_TV, + ADDR_AUDIO_SYSTEM); + assertThat(mNativeWrapper.getResultMessages()).contains(requestArcTermination); + + HdmiCecMessage terminateArc = HdmiCecMessageBuilder.buildTerminateArc( + ADDR_AUDIO_SYSTEM, + ADDR_TV); + mNativeWrapper.onCecMessage(terminateArc); + mTestLooper.dispatchAll(); + + assertThat(callback.getResult()).isEqualTo(HdmiControlManager.RESULT_SUCCESS); + } + + @Test + public void enableEarc_terminateArc() { + // Emulate Audio device on port 0x2000 (supports ARC and eARC) + mNativeWrapper.setPortConnectionStatus(2, true); + HdmiCecMessage reportPhysicalAddress = + HdmiCecMessageBuilder.buildReportPhysicalAddressCommand( + ADDR_AUDIO_SYSTEM, 0x2000, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM); + mNativeWrapper.onCecMessage(reportPhysicalAddress); + mTestLooper.dispatchAll(); + + HdmiCecMessage initiateArc = HdmiCecMessageBuilder.buildInitiateArc( + ADDR_AUDIO_SYSTEM, + ADDR_TV); + + mNativeWrapper.onCecMessage(initiateArc); + mTestLooper.dispatchAll(); + + HdmiCecMessage reportArcInitiated = HdmiCecMessageBuilder.buildReportArcInitiated( + ADDR_TV, + ADDR_AUDIO_SYSTEM); + // should only be sent after SAD querying is done + assertThat(mNativeWrapper.getResultMessages()).doesNotContain(reportArcInitiated); + + // Finish querying SADs + assertThat(mNativeWrapper.getResultMessages()).contains(SAD_QUERY); + mNativeWrapper.clearResultMessages(); + mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS); + mTestLooper.dispatchAll(); + assertThat(mNativeWrapper.getResultMessages()).contains(SAD_QUERY); + mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS); + mTestLooper.dispatchAll(); + + assertThat(mNativeWrapper.getResultMessages()).contains(reportArcInitiated); + mNativeWrapper.clearResultMessages(); + + mHdmiControlService.setEarcEnabled(HdmiControlManager.EARC_FEATURE_ENABLED); + mTestLooper.dispatchAll(); + + HdmiCecMessage requestArcTermination = HdmiCecMessageBuilder.buildRequestArcTermination( + ADDR_TV, + ADDR_AUDIO_SYSTEM); + + assertThat(mNativeWrapper.getResultMessages()).contains(requestArcTermination); + } } diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java index 2b555a07a50fd..aa49a6222390f 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java @@ -30,9 +30,11 @@ import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertTrue; import static junit.framework.TestCase.assertEquals; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; @@ -143,6 +145,7 @@ public class HdmiControlServiceTest { mHdmiControlServiceSpy.setPowerManager(mPowerManager); mHdmiControlServiceSpy.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC); mHdmiControlServiceSpy.setAudioManager(mAudioManager); + mHdmiControlServiceSpy.setEarcSupported(true); mTestLooper.dispatchAll(); } @@ -1087,7 +1090,6 @@ public class HdmiControlServiceTest { @Test public void disableEarc_clearEarcLocalDevice() { - mHdmiControlServiceSpy.setEarcSupported(true); mHdmiControlServiceSpy.clearEarcLocalDevice(); mHdmiControlServiceSpy.addEarcLocalDevice( new HdmiEarcLocalDeviceTx(mHdmiControlServiceSpy)); @@ -1100,7 +1102,6 @@ public class HdmiControlServiceTest { @Test public void disableCec_doNotClearEarcLocalDevice() { - mHdmiControlServiceSpy.setEarcSupported(true); mHdmiControlServiceSpy.clearEarcLocalDevice(); mHdmiControlServiceSpy.addEarcLocalDevice( new HdmiEarcLocalDeviceTx(mHdmiControlServiceSpy)); @@ -1113,7 +1114,6 @@ public class HdmiControlServiceTest { @Test public void enableCec_initializeCecLocalDevices() { - mHdmiControlServiceSpy.setEarcSupported(true); Mockito.clearInvocations(mHdmiControlServiceSpy); mHdmiControlServiceSpy.setCecEnabled(HdmiControlManager.HDMI_CEC_CONTROL_DISABLED); mTestLooper.dispatchAll(); @@ -1125,7 +1125,6 @@ public class HdmiControlServiceTest { @Test public void enableEarc_initializeEarcLocalDevices() { - mHdmiControlServiceSpy.setEarcSupported(true); Mockito.clearInvocations(mHdmiControlServiceSpy); mHdmiControlServiceSpy.setEarcEnabled(HdmiControlManager.EARC_FEATURE_DISABLED); mTestLooper.dispatchAll(); @@ -1137,7 +1136,6 @@ public class HdmiControlServiceTest { @Test public void disableCec_DoNotInformHalAboutEarc() { - mHdmiControlServiceSpy.setEarcSupported(true); mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue( HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED, HdmiControlManager.HDMI_CEC_CONTROL_ENABLED); @@ -1147,7 +1145,7 @@ public class HdmiControlServiceTest { HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED, HdmiControlManager.HDMI_CEC_CONTROL_DISABLED); mTestLooper.dispatchAll(); - verify(mHdmiControlServiceSpy, times(0)).setEarcEnabledInHal(anyBoolean()); + verify(mHdmiControlServiceSpy, times(0)).setEarcEnabledInHal(anyBoolean(), anyBoolean()); } @Test @@ -1155,15 +1153,14 @@ public class HdmiControlServiceTest { mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue( HdmiControlManager.SETTING_NAME_EARC_ENABLED, HdmiControlManager.EARC_FEATURE_ENABLED); - mHdmiControlServiceSpy.setEarcSupported(true); mTestLooper.dispatchAll(); Mockito.clearInvocations(mHdmiControlServiceSpy); mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue( HdmiControlManager.SETTING_NAME_EARC_ENABLED, HdmiControlManager.EARC_FEATURE_DISABLED); mTestLooper.dispatchAll(); - verify(mHdmiControlServiceSpy, times(1)).setEarcEnabledInHal(false); - verify(mHdmiControlServiceSpy, times(0)).setEarcEnabledInHal(true); + verify(mHdmiControlServiceSpy, times(1)).setEarcEnabledInHal(false, false); + verify(mHdmiControlServiceSpy, times(0)).setEarcEnabledInHal(eq(true), anyBoolean()); } @Test @@ -1171,14 +1168,13 @@ public class HdmiControlServiceTest { mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue( HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED, HdmiControlManager.HDMI_CEC_CONTROL_DISABLED); - mHdmiControlServiceSpy.setEarcSupported(true); mTestLooper.dispatchAll(); Mockito.clearInvocations(mHdmiControlServiceSpy); mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue( HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED, HdmiControlManager.HDMI_CEC_CONTROL_ENABLED); mTestLooper.dispatchAll(); - verify(mHdmiControlServiceSpy, times(0)).setEarcEnabledInHal(anyBoolean()); + verify(mHdmiControlServiceSpy, times(0)).setEarcEnabledInHal(anyBoolean(), anyBoolean()); } @Test @@ -1186,15 +1182,14 @@ public class HdmiControlServiceTest { mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue( HdmiControlManager.SETTING_NAME_EARC_ENABLED, HdmiControlManager.EARC_FEATURE_DISABLED); - mHdmiControlServiceSpy.setEarcSupported(true); mTestLooper.dispatchAll(); Mockito.clearInvocations(mHdmiControlServiceSpy); mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue( HdmiControlManager.SETTING_NAME_EARC_ENABLED, HdmiControlManager.EARC_FEATURE_ENABLED); mTestLooper.dispatchAll(); - verify(mHdmiControlServiceSpy, times(1)).setEarcEnabledInHal(true); - verify(mHdmiControlServiceSpy, times(0)).setEarcEnabledInHal(false); + verify(mHdmiControlServiceSpy, times(1)).setEarcEnabledInHal(true, true); + verify(mHdmiControlServiceSpy, times(0)).setEarcEnabledInHal(eq(false), anyBoolean()); } @Test @@ -1202,13 +1197,15 @@ public class HdmiControlServiceTest { mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue( HdmiControlManager.SETTING_NAME_EARC_ENABLED, HdmiControlManager.EARC_FEATURE_ENABLED); - mHdmiControlServiceSpy.setEarcSupported(true); + mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue( + HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED, + HdmiControlManager.HDMI_CEC_CONTROL_DISABLED); mTestLooper.dispatchAll(); Mockito.clearInvocations(mHdmiControlServiceSpy); mHdmiControlServiceSpy.initService(); mTestLooper.dispatchAll(); - verify(mHdmiControlServiceSpy, times(1)).setEarcEnabledInHal(true); - verify(mHdmiControlServiceSpy, times(0)).setEarcEnabledInHal(false); + verify(mHdmiControlServiceSpy, times(1)).setEarcEnabledInHal(true, false); + verify(mHdmiControlServiceSpy, times(0)).setEarcEnabledInHal(eq(false), anyBoolean()); } @Test @@ -1216,13 +1213,12 @@ public class HdmiControlServiceTest { mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue( HdmiControlManager.SETTING_NAME_EARC_ENABLED, HdmiControlManager.EARC_FEATURE_DISABLED); - mHdmiControlServiceSpy.setEarcSupported(true); mTestLooper.dispatchAll(); Mockito.clearInvocations(mHdmiControlServiceSpy); mHdmiControlServiceSpy.initService(); mTestLooper.dispatchAll(); - verify(mHdmiControlServiceSpy, times(1)).setEarcEnabledInHal(false); - verify(mHdmiControlServiceSpy, times(0)).setEarcEnabledInHal(true); + verify(mHdmiControlServiceSpy, times(1)).setEarcEnabledInHal(false, false); + verify(mHdmiControlServiceSpy, times(0)).setEarcEnabledInHal(eq(true), anyBoolean()); } @Test @@ -1230,13 +1226,12 @@ public class HdmiControlServiceTest { mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue( HdmiControlManager.SETTING_NAME_EARC_ENABLED, HdmiControlManager.EARC_FEATURE_ENABLED); - mHdmiControlServiceSpy.setEarcSupported(true); mTestLooper.dispatchAll(); Mockito.clearInvocations(mHdmiControlServiceSpy); mHdmiControlServiceSpy.onWakeUp(WAKE_UP_SCREEN_ON); mTestLooper.dispatchAll(); - verify(mHdmiControlServiceSpy, times(1)).setEarcEnabledInHal(true); - verify(mHdmiControlServiceSpy, times(0)).setEarcEnabledInHal(false); + verify(mHdmiControlServiceSpy, times(1)).setEarcEnabledInHal(true, false); + verify(mHdmiControlServiceSpy, times(0)).setEarcEnabledInHal(eq(false), anyBoolean()); } @Test @@ -1244,13 +1239,106 @@ public class HdmiControlServiceTest { mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue( HdmiControlManager.SETTING_NAME_EARC_ENABLED, HdmiControlManager.EARC_FEATURE_DISABLED); - mHdmiControlServiceSpy.setEarcSupported(true); mTestLooper.dispatchAll(); Mockito.clearInvocations(mHdmiControlServiceSpy); mHdmiControlServiceSpy.onWakeUp(WAKE_UP_SCREEN_ON); mTestLooper.dispatchAll(); - verify(mHdmiControlServiceSpy, times(1)).setEarcEnabledInHal(false); - verify(mHdmiControlServiceSpy, times(0)).setEarcEnabledInHal(true); + verify(mHdmiControlServiceSpy, times(1)).setEarcEnabledInHal(false, false); + verify(mHdmiControlServiceSpy, times(0)).setEarcEnabledInHal(eq(true), anyBoolean()); + } + + @Test + public void earcIdle_blocksArcConnection() { + mHdmiControlServiceSpy.clearEarcLocalDevice(); + HdmiEarcLocalDeviceTx localDeviceTx = new HdmiEarcLocalDeviceTx(mHdmiControlServiceSpy); + localDeviceTx.handleEarcStateChange(Constants.HDMI_EARC_STATUS_IDLE); + mHdmiControlServiceSpy.addEarcLocalDevice(localDeviceTx); + assertThat(mHdmiControlServiceSpy.earcBlocksArcConnection()).isTrue(); + } + + @Test + public void earcPending_blocksArcConnection() { + mHdmiControlServiceSpy.clearEarcLocalDevice(); + HdmiEarcLocalDeviceTx localDeviceTx = new HdmiEarcLocalDeviceTx(mHdmiControlServiceSpy); + localDeviceTx.handleEarcStateChange(Constants.HDMI_EARC_STATUS_EARC_PENDING); + mHdmiControlServiceSpy.addEarcLocalDevice(localDeviceTx); + assertThat(mHdmiControlServiceSpy.earcBlocksArcConnection()).isTrue(); + } + + @Test + public void earcEnabled_blocksArcConnection() { + mHdmiControlServiceSpy.clearEarcLocalDevice(); + HdmiEarcLocalDeviceTx localDeviceTx = new HdmiEarcLocalDeviceTx(mHdmiControlServiceSpy); + localDeviceTx.handleEarcStateChange(Constants.HDMI_EARC_STATUS_EARC_CONNECTED); + mHdmiControlServiceSpy.addEarcLocalDevice(localDeviceTx); + assertThat(mHdmiControlServiceSpy.earcBlocksArcConnection()).isTrue(); + } + + @Test + public void arcPending_doesNotBlockArcConnection() { + mHdmiControlServiceSpy.clearEarcLocalDevice(); + HdmiEarcLocalDeviceTx localDeviceTx = new HdmiEarcLocalDeviceTx(mHdmiControlServiceSpy); + localDeviceTx.handleEarcStateChange(Constants.HDMI_EARC_STATUS_ARC_PENDING); + mHdmiControlServiceSpy.addEarcLocalDevice(localDeviceTx); + assertThat(mHdmiControlServiceSpy.earcBlocksArcConnection()).isFalse(); + } + + @Test + public void earcStatusBecomesIdle_terminateArc() { + mHdmiControlServiceSpy.clearEarcLocalDevice(); + HdmiEarcLocalDeviceTx localDeviceTx = new HdmiEarcLocalDeviceTx(mHdmiControlServiceSpy); + mHdmiControlServiceSpy.addEarcLocalDevice(localDeviceTx); + localDeviceTx.handleEarcStateChange(Constants.HDMI_EARC_STATUS_IDLE); + verify(mHdmiControlServiceSpy, times(1)).startArcAction(eq(false), any()); + } + + @Test + public void earcStatusBecomesEnabled_doNothing() { + mHdmiControlServiceSpy.clearEarcLocalDevice(); + HdmiEarcLocalDeviceTx localDeviceTx = new HdmiEarcLocalDeviceTx(mHdmiControlServiceSpy); + mHdmiControlServiceSpy.addEarcLocalDevice(localDeviceTx); + localDeviceTx.handleEarcStateChange(Constants.HDMI_EARC_STATUS_EARC_CONNECTED); + verify(mHdmiControlServiceSpy, times(0)).startArcAction(anyBoolean(), any()); + } + + @Test + public void earcStatusBecomesPending_doNothing() { + mHdmiControlServiceSpy.clearEarcLocalDevice(); + HdmiEarcLocalDeviceTx localDeviceTx = new HdmiEarcLocalDeviceTx(mHdmiControlServiceSpy); + mHdmiControlServiceSpy.addEarcLocalDevice(localDeviceTx); + localDeviceTx.handleEarcStateChange(Constants.HDMI_EARC_STATUS_EARC_PENDING); + verify(mHdmiControlServiceSpy, times(0)).startArcAction(anyBoolean(), any()); + } + + @Test + public void earcStatusBecomesNotEnabled_initiateArc() { + mHdmiControlServiceSpy.clearEarcLocalDevice(); + HdmiEarcLocalDeviceTx localDeviceTx = new HdmiEarcLocalDeviceTx(mHdmiControlServiceSpy); + mHdmiControlServiceSpy.addEarcLocalDevice(localDeviceTx); + localDeviceTx.handleEarcStateChange(Constants.HDMI_EARC_STATUS_ARC_PENDING); + verify(mHdmiControlServiceSpy, times(1)).startArcAction(eq(true), any()); + } + + @Test + public void earcStateWasArcPending_becomesEarcPending_terminateArc() { + mHdmiControlServiceSpy.clearEarcLocalDevice(); + HdmiEarcLocalDeviceTx localDeviceTx = new HdmiEarcLocalDeviceTx(mHdmiControlServiceSpy); + mHdmiControlServiceSpy.addEarcLocalDevice(localDeviceTx); + localDeviceTx.handleEarcStateChange(Constants.HDMI_EARC_STATUS_ARC_PENDING); + mTestLooper.dispatchAll(); + localDeviceTx.handleEarcStateChange(Constants.HDMI_EARC_STATUS_EARC_PENDING); + verify(mHdmiControlServiceSpy, times(1)).startArcAction(eq(false), any()); + } + + @Test + public void earcStateWasArcPending_becomesEarcEnabled_terminateArc() { + mHdmiControlServiceSpy.clearEarcLocalDevice(); + HdmiEarcLocalDeviceTx localDeviceTx = new HdmiEarcLocalDeviceTx(mHdmiControlServiceSpy); + mHdmiControlServiceSpy.addEarcLocalDevice(localDeviceTx); + localDeviceTx.handleEarcStateChange(Constants.HDMI_EARC_STATUS_ARC_PENDING); + mTestLooper.dispatchAll(); + localDeviceTx.handleEarcStateChange(Constants.HDMI_EARC_STATUS_EARC_CONNECTED); + verify(mHdmiControlServiceSpy, times(1)).startArcAction(eq(false), any()); } protected static class MockPlaybackDevice extends HdmiCecLocalDevicePlayback {