HDMI: More reliable DSM setting disabling
Wait for ArcTerminationActionFromAvr to finish before giving up the LA 5 during Dynamic Soundbar mode disabling process. Add callback inside ArcTerminationActionFromAvr. Transfer the callback in HdmiCecLocalDeviceAudioSystem#handleRequestArcTermination so it doesn't get lost. Callback is not transfered in the following situation, in HdmiCecLocalDeviceAudioSystem#initArcOnFromAvr ARC termination is interrupted by ARC initialization from AVR. This scenario would occur if user toggles DSM off then on before ARC termination process is completed, then the local device audio system tries establishing ARC connection when logical address allocation finished. In this case, DSM would be enabled and the callback from ARC termination action that retriggers logical address allocation wouldn't be necessary. Bug: 260322563 Test: make && atest com.android.server.hdmi.HdmiControlServiceTest Change-Id: Ib0a8b3a7da79da8cf3f9724a685a55c80760a755
This commit is contained in:
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package com.android.server.hdmi;
|
||||
|
||||
import android.hardware.hdmi.HdmiControlManager;
|
||||
import android.hardware.hdmi.IHdmiControlCallback;
|
||||
import android.hardware.tv.cec.V1_0.SendMessageResult;
|
||||
|
||||
/**
|
||||
@@ -33,6 +35,10 @@ public class ArcTerminationActionFromAvr extends HdmiCecFeatureAction {
|
||||
super(source);
|
||||
}
|
||||
|
||||
ArcTerminationActionFromAvr(HdmiCecLocalDevice source, IHdmiControlCallback callback) {
|
||||
super(source, callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean start() {
|
||||
mState = STATE_WAITING_FOR_INITIATE_ARC_RESPONSE;
|
||||
@@ -47,10 +53,19 @@ public class ArcTerminationActionFromAvr extends HdmiCecFeatureAction {
|
||||
return false;
|
||||
}
|
||||
switch (cmd.getOpcode()) {
|
||||
case Constants.MESSAGE_FEATURE_ABORT:
|
||||
int originalOpcode = cmd.getParams()[0] & 0xFF;
|
||||
if (originalOpcode == Constants.MESSAGE_TERMINATE_ARC) {
|
||||
mState = STATE_ARC_TERMINATED;
|
||||
audioSystem().processArcTermination();
|
||||
finishWithCallback(HdmiControlManager.RESULT_TARGET_NOT_AVAILABLE);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
case Constants.MESSAGE_REPORT_ARC_TERMINATED:
|
||||
mState = STATE_ARC_TERMINATED;
|
||||
audioSystem().processArcTermination();
|
||||
finish();
|
||||
finishWithCallback(HdmiControlManager.RESULT_SUCCESS);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -79,7 +94,7 @@ public class ArcTerminationActionFromAvr extends HdmiCecFeatureAction {
|
||||
audioSystem().setArcStatus(false);
|
||||
}
|
||||
HdmiLogger.debug("Terminate ARC was not successfully sent.");
|
||||
finish();
|
||||
finishWithCallback(HdmiControlManager.RESULT_TARGET_NOT_AVAILABLE);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -88,6 +103,6 @@ public class ArcTerminationActionFromAvr extends HdmiCecFeatureAction {
|
||||
// Disable ARC if TV didn't respond with <Report ARC Terminated> in time.
|
||||
audioSystem().setArcStatus(false);
|
||||
HdmiLogger.debug("handleTerminateArcTimeout");
|
||||
finish();
|
||||
finishWithCallback(HdmiControlManager.RESULT_TIMEOUT);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -458,8 +458,16 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource {
|
||||
HdmiLogger.debug("ARC is not established between TV and AVR device");
|
||||
return Constants.ABORT_NOT_IN_CORRECT_MODE;
|
||||
} else {
|
||||
removeAction(ArcTerminationActionFromAvr.class);
|
||||
addAndStartAction(new ArcTerminationActionFromAvr(this));
|
||||
if (!getActions(ArcTerminationActionFromAvr.class).isEmpty()
|
||||
&& !getActions(ArcTerminationActionFromAvr.class).get(0).mCallbacks.isEmpty()) {
|
||||
IHdmiControlCallback callback =
|
||||
getActions(ArcTerminationActionFromAvr.class).get(0).mCallbacks.get(0);
|
||||
removeAction(ArcTerminationActionFromAvr.class);
|
||||
addAndStartAction(new ArcTerminationActionFromAvr(this, callback));
|
||||
} else {
|
||||
removeAction(ArcTerminationActionFromAvr.class);
|
||||
addAndStartAction(new ArcTerminationActionFromAvr(this));
|
||||
}
|
||||
return Constants.HANDLED;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -878,16 +878,30 @@ public class HdmiControlService extends SystemService {
|
||||
Slog.w(TAG, "Device type doesn't support ARC.");
|
||||
return;
|
||||
}
|
||||
boolean isArcEnabled = false;
|
||||
if (settingValue == SOUNDBAR_MODE_DISABLED && audioSystem != null) {
|
||||
if (audioSystem.isArcEnabled()) {
|
||||
audioSystem.addAndStartAction(new ArcTerminationActionFromAvr(audioSystem));
|
||||
}
|
||||
isArcEnabled = audioSystem.isArcEnabled();
|
||||
if (isSystemAudioActivated()) {
|
||||
audioSystem.terminateSystemAudioMode();
|
||||
}
|
||||
if (isArcEnabled) {
|
||||
if (audioSystem.hasAction(ArcTerminationActionFromAvr.class)) {
|
||||
audioSystem.removeAction(ArcTerminationActionFromAvr.class);
|
||||
}
|
||||
audioSystem.addAndStartAction(new ArcTerminationActionFromAvr(audioSystem,
|
||||
new IHdmiControlCallback.Stub() {
|
||||
@Override
|
||||
public void onComplete(int result) {
|
||||
mAddressAllocated = false;
|
||||
initializeCecLocalDevices(INITIATED_BY_SOUNDBAR_MODE);
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
if (!isArcEnabled) {
|
||||
mAddressAllocated = false;
|
||||
initializeCecLocalDevices(INITIATED_BY_SOUNDBAR_MODE);
|
||||
}
|
||||
mAddressAllocated = false;
|
||||
initializeCecLocalDevices(INITIATED_BY_SOUNDBAR_MODE);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -24,6 +24,8 @@ import static org.mockito.Mockito.spy;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.ContextWrapper;
|
||||
import android.hardware.hdmi.HdmiControlManager;
|
||||
import android.hardware.hdmi.IHdmiControlCallback;
|
||||
import android.hardware.tv.cec.V1_0.SendMessageResult;
|
||||
import android.media.AudioManager;
|
||||
import android.os.Looper;
|
||||
@@ -52,6 +54,7 @@ public class ArcTerminationActionFromAvrTest {
|
||||
private Context mContextSpy;
|
||||
private HdmiCecLocalDeviceAudioSystem mHdmiCecLocalDeviceAudioSystem;
|
||||
private FakePowerManagerWrapper mPowerManager;
|
||||
private TestCallback mCallback;
|
||||
private ArcTerminationActionFromAvr mAction;
|
||||
|
||||
private FakeNativeWrapper mNativeWrapper;
|
||||
@@ -112,7 +115,9 @@ public class ArcTerminationActionFromAvrTest {
|
||||
}
|
||||
};
|
||||
mHdmiCecLocalDeviceAudioSystem.init();
|
||||
mAction = new ArcTerminationActionFromAvr(mHdmiCecLocalDeviceAudioSystem);
|
||||
mCallback = new TestCallback();
|
||||
mAction = new ArcTerminationActionFromAvr(mHdmiCecLocalDeviceAudioSystem,
|
||||
mCallback);
|
||||
|
||||
mLocalDevices.add(mHdmiCecLocalDeviceAudioSystem);
|
||||
hdmiControlService.onBootPhase(PHASE_SYSTEM_SERVICES_READY);
|
||||
@@ -121,6 +126,20 @@ public class ArcTerminationActionFromAvrTest {
|
||||
mTestLooper.dispatchAll();
|
||||
}
|
||||
|
||||
private static class TestCallback extends IHdmiControlCallback.Stub {
|
||||
private final ArrayList<Integer> mCallbackResult = new ArrayList<Integer>();
|
||||
|
||||
@Override
|
||||
public void onComplete(int result) {
|
||||
mCallbackResult.add(result);
|
||||
}
|
||||
|
||||
private int getResult() {
|
||||
assertThat(mCallbackResult.size()).isEqualTo(1);
|
||||
return mCallbackResult.get(0);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSendMessage_sendFailed() {
|
||||
mNativeWrapper.setMessageSendResult(Constants.MESSAGE_TERMINATE_ARC,
|
||||
@@ -133,6 +152,7 @@ public class ArcTerminationActionFromAvrTest {
|
||||
assertThat(mNativeWrapper.getResultMessages()).contains(terminateArc);
|
||||
|
||||
assertThat(mHdmiCecLocalDeviceAudioSystem.isArcEnabled()).isFalse();
|
||||
assertThat(mCallback.getResult()).isEqualTo(HdmiControlManager.RESULT_TARGET_NOT_AVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -149,6 +169,7 @@ public class ArcTerminationActionFromAvrTest {
|
||||
mTestLooper.dispatchAll();
|
||||
|
||||
assertThat(mHdmiCecLocalDeviceAudioSystem.isArcEnabled()).isFalse();
|
||||
assertThat(mCallback.getResult()).isEqualTo(HdmiControlManager.RESULT_TIMEOUT);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -167,5 +188,28 @@ public class ArcTerminationActionFromAvrTest {
|
||||
mTestLooper.dispatchAll();
|
||||
|
||||
assertThat(mHdmiCecLocalDeviceAudioSystem.isArcEnabled()).isFalse();
|
||||
assertThat(mCallback.getResult()).isEqualTo(HdmiControlManager.RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReportArcTerminated_featureAbort() {
|
||||
mHdmiCecLocalDeviceAudioSystem.addAndStartAction(mAction);
|
||||
mTestLooper.dispatchAll();
|
||||
HdmiCecMessage terminateArc = HdmiCecMessageBuilder.buildTerminateArc(
|
||||
Constants.ADDR_AUDIO_SYSTEM, Constants.ADDR_TV);
|
||||
|
||||
assertThat(mNativeWrapper.getResultMessages()).contains(terminateArc);
|
||||
|
||||
HdmiCecMessage arcTerminatedResponse = HdmiCecMessageBuilder.buildFeatureAbortCommand(
|
||||
Constants.ADDR_TV,
|
||||
Constants.ADDR_AUDIO_SYSTEM,
|
||||
Constants.MESSAGE_TERMINATE_ARC,
|
||||
Constants.ABORT_REFUSED);
|
||||
|
||||
mNativeWrapper.onCecMessage(arcTerminatedResponse);
|
||||
mTestLooper.dispatchAll();
|
||||
|
||||
assertThat(mHdmiCecLocalDeviceAudioSystem.isArcEnabled()).isFalse();
|
||||
assertThat(mCallback.getResult()).isEqualTo(HdmiControlManager.RESULT_TARGET_NOT_AVAILABLE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -534,6 +534,25 @@ public class HdmiCecLocalDeviceAudioSystemTest {
|
||||
assertThat(mNativeWrapper.getResultMessages()).contains(expectedMessage);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void handleRequestArcTerminate_callbackIsPreserved() throws Exception {
|
||||
TestCallback callback = new TestCallback();
|
||||
|
||||
mHdmiCecLocalDeviceAudioSystem.setArcStatus(true);
|
||||
assertThat(mHdmiCecLocalDeviceAudioSystem.isArcEnabled()).isTrue();
|
||||
mHdmiCecLocalDeviceAudioSystem.addAndStartAction(
|
||||
new ArcTerminationActionFromAvr(mHdmiCecLocalDeviceAudioSystem, callback));
|
||||
|
||||
HdmiCecMessage message =
|
||||
HdmiCecMessageBuilder.buildRequestArcTermination(ADDR_TV, ADDR_AUDIO_SYSTEM);
|
||||
assertThat(mHdmiCecLocalDeviceAudioSystem.handleRequestArcTermination(message))
|
||||
.isEqualTo(Constants.HANDLED);
|
||||
|
||||
mTestLooper.dispatchAll();
|
||||
assertThat(mHdmiCecLocalDeviceAudioSystem.getActions(
|
||||
ArcTerminationActionFromAvr.class).get(0).mCallbacks.get(0)).isEqualTo(callback);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void handleRequestArcInit_arcIsNotSupported() throws Exception {
|
||||
HdmiCecMessage message =
|
||||
@@ -880,4 +899,13 @@ public class HdmiCecLocalDeviceAudioSystemTest {
|
||||
assertThat(mNativeWrapper.getResultMessages()).doesNotContain(
|
||||
systemAudioModeRequest_fromAudioSystem);
|
||||
}
|
||||
|
||||
private static class TestCallback extends IHdmiControlCallback.Stub {
|
||||
private final ArrayList<Integer> mCallbackResult = new ArrayList<Integer>();
|
||||
|
||||
@Override
|
||||
public void onComplete(int result) {
|
||||
mCallbackResult.add(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1036,6 +1036,7 @@ public class HdmiControlServiceTest {
|
||||
|
||||
@Test
|
||||
public void setSoundbarMode_enabled_addAudioSystemLocalDevice() {
|
||||
mHdmiControlServiceSpy.setPowerStatus(HdmiControlManager.POWER_STATUS_ON);
|
||||
// Initialize the local devices excluding the audio system.
|
||||
mHdmiControlServiceSpy.clearCecLocalDevices();
|
||||
mLocalDevices.remove(mAudioSystemDeviceSpy);
|
||||
@@ -1053,6 +1054,7 @@ public class HdmiControlServiceTest {
|
||||
|
||||
@Test
|
||||
public void setSoundbarMode_disabled_removeAudioSystemLocalDevice() {
|
||||
mHdmiControlServiceSpy.setPowerStatus(HdmiControlManager.POWER_STATUS_ON);
|
||||
// Initialize the local devices excluding the audio system.
|
||||
mHdmiControlServiceSpy.clearCecLocalDevices();
|
||||
mLocalDevices.remove(mAudioSystemDeviceSpy);
|
||||
@@ -1073,6 +1075,10 @@ public class HdmiControlServiceTest {
|
||||
HdmiControlManager.CEC_SETTING_NAME_SOUNDBAR_MODE,
|
||||
HdmiControlManager.SOUNDBAR_MODE_DISABLED);
|
||||
mTestLooper.dispatchAll();
|
||||
|
||||
// Wait for ArcTerminationActionFromAvr timeout for the logical address allocation to start.
|
||||
mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS);
|
||||
mTestLooper.dispatchAll();
|
||||
assertThat(mHdmiControlServiceSpy.audioSystem()).isNull();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user