Don't remove devices on onHotplug()

This CL affects TV panels and Audio Systems only.
Before HdmiCecNetwork existed: devices were removed when
HotplugDetectionAction detected a hotplug out, and TIF was informed.
Before this CL: devices were removed from the CEC network onHotplug,
but the listener to inform TIF wasn't invoked. This was causing
multiple issues.
After: on TV panels and Audio Systems, only remove devices when
HotplugDetectionAction detects a hotplug out,
just like before HdmiCecNetwork existed.

Test: atest
Bug:213417037

Change-Id: I4181b4650b70101da44fd205e4df9eb566f74496
Merged-In: I4181b4650b70101da44fd205e4df9eb566f74496
This commit is contained in:
Nathalie Le Clair
2022-03-23 09:02:20 +01:00
parent c8adf1f70e
commit c188a56888
8 changed files with 167 additions and 8 deletions

View File

@@ -22,6 +22,8 @@ import android.hardware.hdmi.HdmiDeviceInfo;
* Callback interface definition for HDMI client to get informed of * Callback interface definition for HDMI client to get informed of
* the CEC logical device status change event. * the CEC logical device status change event.
* *
* Only to be used on TV panel and Audio System devices (b/226317598).
*
* @hide * @hide
*/ */
oneway interface IHdmiDeviceEventListener { oneway interface IHdmiDeviceEventListener {

View File

@@ -127,6 +127,7 @@ public class HdmiCecLocalDevicePlayback extends HdmiCecLocalDeviceSource {
// We'll not invalidate the active source on the hotplug event to pass CETC 11.2.2-2 ~ 3. // We'll not invalidate the active source on the hotplug event to pass CETC 11.2.2-2 ~ 3.
if (!connected) { if (!connected) {
getWakeLock().release(); getWakeLock().release();
mService.getHdmiCecNetwork().removeDevicesConnectedToPort(portId);
} }
} }

View File

@@ -1218,6 +1218,11 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
@ServiceThreadOnly @ServiceThreadOnly
void onHotplug(int portId, boolean connected) { void onHotplug(int portId, boolean connected) {
assertRunOnServiceThread(); assertRunOnServiceThread();
if (!connected) {
mService.getHdmiCecNetwork().removeCecSwitches(portId);
}
// Turning System Audio Mode off when the AVR is unlugged or standby. // Turning System Audio Mode off when the AVR is unlugged or standby.
// When the device is not unplugged but reawaken from standby, we check if the System // When the device is not unplugged but reawaken from standby, we check if the System
// Audio Control Feature is enabled or not then decide if turning SAM on/off accordingly. // Audio Control Feature is enabled or not then decide if turning SAM on/off accordingly.

View File

@@ -698,7 +698,7 @@ public class HdmiCecNetwork {
return mCecSwitches; return mCecSwitches;
} }
void removeDevicesConnectedToPort(int portId) { void removeCecSwitches(int portId) {
Iterator<Integer> it = mCecSwitches.iterator(); Iterator<Integer> it = mCecSwitches.iterator();
while (it.hasNext()) { while (it.hasNext()) {
int path = it.next(); int path = it.next();
@@ -707,6 +707,11 @@ public class HdmiCecNetwork {
it.remove(); it.remove();
} }
} }
}
void removeDevicesConnectedToPort(int portId) {
removeCecSwitches(portId);
List<Integer> toRemove = new ArrayList<>(); List<Integer> toRemove = new ArrayList<>();
for (int i = 0; i < mDeviceInfos.size(); i++) { for (int i = 0; i < mDeviceInfos.size(); i++) {
int key = mDeviceInfos.keyAt(i); int key = mDeviceInfos.keyAt(i);

View File

@@ -1251,10 +1251,6 @@ public class HdmiControlService extends SystemService {
device.onHotplug(portId, connected); device.onHotplug(portId, connected);
} }
if (!connected) {
mHdmiCecNetwork.removeDevicesConnectedToPort(portId);
}
announceHotplugEvent(portId, connected); announceHotplugEvent(portId, connected);
} }

View File

@@ -36,9 +36,9 @@ import java.util.List;
final class HotplugDetectionAction extends HdmiCecFeatureAction { final class HotplugDetectionAction extends HdmiCecFeatureAction {
private static final String TAG = "HotPlugDetectionAction"; private static final String TAG = "HotPlugDetectionAction";
private static final int POLLING_INTERVAL_MS = 5000; public static final int POLLING_INTERVAL_MS = 5000;
private static final int TIMEOUT_COUNT = 3; public static final int TIMEOUT_COUNT = 3;
private static final int AVR_COUNT_MAX = 3; public static final int AVR_COUNT_MAX = 3;
// State in which waits for next polling // State in which waits for next polling
private static final int STATE_WAIT_FOR_NEXT_POLLING = 1; private static final int STATE_WAIT_FOR_NEXT_POLLING = 1;

View File

@@ -1789,4 +1789,32 @@ public class HdmiCecLocalDevicePlaybackTest {
assertThat(mNativeWrapper.getResultMessages()).doesNotContain(featureAbortPressed); assertThat(mNativeWrapper.getResultMessages()).doesNotContain(featureAbortPressed);
assertThat(mNativeWrapper.getResultMessages()).doesNotContain(featureAbortReleased); assertThat(mNativeWrapper.getResultMessages()).doesNotContain(featureAbortReleased);
} }
@Test
public void onHotplugClearsDevices() {
mHdmiControlService.getHdmiCecNetwork().clearDeviceList();
assertThat(mHdmiControlService.getHdmiCecNetwork().getDeviceInfoList(false))
.isEmpty();
// Add a device to the network and assert that this device is included in the list of
// devices.
HdmiDeviceInfo infoPlayback = new HdmiDeviceInfo(
Constants.ADDR_PLAYBACK_3,
0x1000,
PORT_1,
HdmiDeviceInfo.DEVICE_PLAYBACK,
0x1000,
"Playback 3",
HdmiControlManager.POWER_STATUS_ON);
mHdmiControlService.getHdmiCecNetwork().addCecDevice(infoPlayback);
mTestLooper.dispatchAll();
assertThat(mHdmiControlService.getHdmiCecNetwork().getDeviceInfoList(false))
.hasSize(1);
// HAL detects a hotplug out. Assert that this device gets removed from the list of devices.
mHdmiControlService.onHotplug(PORT_1, false);
mTestLooper.dispatchAll();
assertThat(mHdmiControlService.getHdmiCecNetwork().getDeviceInfoList(false))
.isEmpty();
}
} }

View File

@@ -56,12 +56,14 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations; import org.mockito.MockitoAnnotations;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List;
@SmallTest @SmallTest
@RunWith(JUnit4.class) @RunWith(JUnit4.class)
/** Tests for {@link HdmiCecLocalDeviceTv} class. */ /** Tests for {@link HdmiCecLocalDeviceTv} class. */
public class HdmiCecLocalDeviceTvTest { public class HdmiCecLocalDeviceTvTest {
private static final int TIMEOUT_MS = HdmiConfig.TIMEOUT_MS + 1; private static final int TIMEOUT_MS = HdmiConfig.TIMEOUT_MS + 1;
private static final int PORT_1 = 1;
private HdmiControlService mHdmiControlService; private HdmiControlService mHdmiControlService;
private HdmiCecController mHdmiCecController; private HdmiCecController mHdmiCecController;
@@ -73,6 +75,25 @@ public class HdmiCecLocalDeviceTvTest {
private int mTvPhysicalAddress; private int mTvPhysicalAddress;
private int mTvLogicalAddress; private int mTvLogicalAddress;
private boolean mWokenUp; private boolean mWokenUp;
private List<DeviceEventListener> mDeviceEventListeners = new ArrayList<>();
private class DeviceEventListener {
private HdmiDeviceInfo mDevice;
private int mStatus;
DeviceEventListener(HdmiDeviceInfo device, int status) {
this.mDevice = device;
this.mStatus = status;
}
int getStatus() {
return mStatus;
}
HdmiDeviceInfo getDeviceInfo() {
return mDevice;
}
}
@Mock @Mock
private IPowerManager mIPowerManagerMock; private IPowerManager mIPowerManagerMock;
@@ -124,6 +145,11 @@ public class HdmiCecLocalDeviceTvTest {
AudioManager getAudioManager() { AudioManager getAudioManager() {
return mAudioManager; return mAudioManager;
} }
@Override
void invokeDeviceEventListeners(HdmiDeviceInfo device, int status) {
mDeviceEventListeners.add(new DeviceEventListener(device, status));
}
}; };
mHdmiCecLocalDeviceTv = new HdmiCecLocalDeviceTv(mHdmiControlService); mHdmiCecLocalDeviceTv = new HdmiCecLocalDeviceTv(mHdmiControlService);
@@ -596,4 +622,100 @@ public class HdmiCecLocalDeviceTvTest {
verify(mAudioManager, never()).setStreamVolume(anyInt(), anyInt(), anyInt()); verify(mAudioManager, never()).setStreamVolume(anyInt(), anyInt(), anyInt());
} }
@Test
public void hotplugDetectionActionClearsDevices() {
mHdmiControlService.getHdmiCecNetwork().clearDeviceList();
assertThat(mHdmiControlService.getHdmiCecNetwork().getDeviceInfoList(false))
.isEmpty();
// Add a device to the network and assert that this device is included in the list of
// devices.
HdmiDeviceInfo infoPlayback = new HdmiDeviceInfo(
Constants.ADDR_PLAYBACK_2,
0x1000,
PORT_1,
HdmiDeviceInfo.DEVICE_PLAYBACK,
0x1000,
"Playback 2",
HdmiControlManager.POWER_STATUS_ON);
mHdmiControlService.getHdmiCecNetwork().addCecDevice(infoPlayback);
mTestLooper.dispatchAll();
assertThat(mHdmiControlService.getHdmiCecNetwork().getDeviceInfoList(false))
.hasSize(1);
mDeviceEventListeners.clear();
assertThat(mDeviceEventListeners.size()).isEqualTo(0);
// HAL detects a hotplug out. Assert that this device stays in the list of devices.
mHdmiControlService.onHotplug(PORT_1, false);
assertThat(mHdmiControlService.getHdmiCecNetwork().getDeviceInfoList(false))
.hasSize(1);
assertThat(mDeviceEventListeners).isEmpty();
mTestLooper.dispatchAll();
// Make the device not acknowledge the poll message sent by the HotplugDetectionAction.
// Assert that this device is removed from the list of devices.
mNativeWrapper.setPollAddressResponse(Constants.ADDR_PLAYBACK_2, SendMessageResult.NACK);
for (int pollCount = 0; pollCount < HotplugDetectionAction.TIMEOUT_COUNT; pollCount++) {
mTestLooper.moveTimeForward(HotplugDetectionAction.POLLING_INTERVAL_MS);
mTestLooper.dispatchAll();
}
assertThat(mHdmiControlService.getHdmiCecNetwork().getDeviceInfoList(false))
.isEmpty();
assertThat(mDeviceEventListeners.size()).isEqualTo(1);
assertThat(mDeviceEventListeners.get(0).getStatus())
.isEqualTo(HdmiControlManager.DEVICE_EVENT_REMOVE_DEVICE);
HdmiDeviceInfo removedDeviceInfo = mDeviceEventListeners.get(0).getDeviceInfo();
assertThat(removedDeviceInfo.getPortId()).isEqualTo(PORT_1);
assertThat(removedDeviceInfo.getLogicalAddress()).isEqualTo(Constants.ADDR_PLAYBACK_2);
assertThat(removedDeviceInfo.getPhysicalAddress()).isEqualTo(0x1000);
assertThat(removedDeviceInfo.getDeviceType()).isEqualTo(HdmiDeviceInfo.DEVICE_PLAYBACK);
}
@Test
public void hotplugDetectionActionClearsDevices_AudioSystem() {
mHdmiControlService.getHdmiCecNetwork().clearDeviceList();
assertThat(mHdmiControlService.getHdmiCecNetwork().getDeviceInfoList(false))
.isEmpty();
// Add a device to the network and assert that this device is included in the list of
// devices.
HdmiDeviceInfo infoAudioSystem = new HdmiDeviceInfo(
ADDR_AUDIO_SYSTEM,
0x1000,
PORT_1,
HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM,
0x1000,
"Audio System",
HdmiControlManager.POWER_STATUS_ON);
mHdmiControlService.getHdmiCecNetwork().addCecDevice(infoAudioSystem);
mTestLooper.dispatchAll();
assertThat(mHdmiControlService.getHdmiCecNetwork().getDeviceInfoList(false))
.hasSize(1);
mDeviceEventListeners.clear();
assertThat(mDeviceEventListeners.size()).isEqualTo(0);
// HAL detects a hotplug out. Assert that this device stays in the list of devices.
mHdmiControlService.onHotplug(PORT_1, false);
assertThat(mHdmiControlService.getHdmiCecNetwork().getDeviceInfoList(false))
.hasSize(1);
assertThat(mDeviceEventListeners).isEmpty();
mTestLooper.dispatchAll();
// Make the device not acknowledge the poll message sent by the HotplugDetectionAction.
// Assert that this device is removed from the list of devices.
mNativeWrapper.setPollAddressResponse(ADDR_AUDIO_SYSTEM, SendMessageResult.NACK);
for (int pollCount = 0; pollCount < HotplugDetectionAction.TIMEOUT_COUNT; pollCount++) {
mTestLooper.moveTimeForward(HotplugDetectionAction.POLLING_INTERVAL_MS);
mTestLooper.dispatchAll();
}
assertThat(mHdmiControlService.getHdmiCecNetwork().getDeviceInfoList(false))
.isEmpty();
assertThat(mDeviceEventListeners.size()).isEqualTo(1);
assertThat(mDeviceEventListeners.get(0).getStatus())
.isEqualTo(HdmiControlManager.DEVICE_EVENT_REMOVE_DEVICE);
HdmiDeviceInfo removedDeviceInfo = mDeviceEventListeners.get(0).getDeviceInfo();
assertThat(removedDeviceInfo.getPortId()).isEqualTo(PORT_1);
assertThat(removedDeviceInfo.getLogicalAddress()).isEqualTo(Constants.ADDR_AUDIO_SYSTEM);
assertThat(removedDeviceInfo.getPhysicalAddress()).isEqualTo(0x1000);
assertThat(removedDeviceInfo.getDeviceType()).isEqualTo(HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
}
} }