Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bae98b3d authored by Paul Colta's avatar Paul Colta
Browse files

HDMI: Process buffered <Active Source> faster on TVs

On OTP the <Active Source> message handled by the TV would be buffered
until the connected OTT device would send a <Report PA> message.

If the device wouldn't send <Report PA> by itself, the TV will send a
<Give PA> message only when DeviceDiscoveryAction polling has been
finished and the Physical Address Stage has started.

In this patch, a device info with the known information from <Active
Source> message is added. This helps the buffered message to be
processed sooner by TvInputCallback#onInputAdded call.

Flag: EXEMPT bugfix
Bug: 354848887
Test: atest com.android.server.hdmi
Change-Id: Ibe8f066542b97e4424c02770f238f2026dac192b
parent 3e7db78c
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -17,8 +17,10 @@
package com.android.server.hdmi;

import android.hardware.hdmi.HdmiDeviceInfo;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * Buffer storage to keep incoming messages for later processing. Used to
@@ -83,6 +85,16 @@ final class DelayedMessageBuffer {
        return false;
    }

    List<HdmiCecMessage> getBufferedMessagesWithOpcode(int opcode) {
        List<HdmiCecMessage> messages = new ArrayList<>();
        for (HdmiCecMessage message : mBuffer) {
            if (message.getOpcode() == opcode) {
                messages.add(message);
            }
        }
        return messages;
    }

    void processAllMessages() {
        // Use the copied buffer.
        ArrayList<HdmiCecMessage> copiedBuffer = new ArrayList<>(mBuffer);
+27 −1
Original line number Diff line number Diff line
@@ -217,7 +217,9 @@ public class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
        resetSelectRequestBuffer();
        launchDeviceDiscovery();
        startQueuedActions();
        if (!mDelayedMessageBuffer.isBuffered(Constants.MESSAGE_ACTIVE_SOURCE)) {
        List<HdmiCecMessage> bufferedActiveSource = mDelayedMessageBuffer
                .getBufferedMessagesWithOpcode(Constants.MESSAGE_ACTIVE_SOURCE);
        if (bufferedActiveSource.isEmpty()) {
            if (hasAction(RequestActiveSourceAction.class)) {
                Slog.i(TAG, "RequestActiveSourceAction is in progress. Restarting.");
                removeAction(RequestActiveSourceAction.class);
@@ -236,7 +238,31 @@ public class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
                    }
                }
            }));
        } else {
            addCecDeviceForBufferedActiveSource(bufferedActiveSource.get(0));
        }
    }

    // Add a new CEC device with known information from the buffered <Active Source> message. This
    // helps TvInputCallback#onInputAdded to be called such that the message can be processed and
    // the TV to switch to the new active input.
    @ServiceThreadOnly
    private void addCecDeviceForBufferedActiveSource(HdmiCecMessage bufferedActiveSource) {
        assertRunOnServiceThread();
        if (bufferedActiveSource == null) {
            return;
        }
        int source = bufferedActiveSource.getSource();
        int physicalAddress = HdmiUtils.twoBytesToInt(bufferedActiveSource.getParams());
        List<Integer> deviceTypes = HdmiUtils.getTypeFromAddress(source);
        HdmiDeviceInfo newDevice = HdmiDeviceInfo.cecDeviceBuilder()
                .setLogicalAddress(source)
                .setPhysicalAddress(physicalAddress)
                .setDisplayName(HdmiUtils.getDefaultDeviceName(source))
                .setDeviceType(deviceTypes.get(0))
                .setVendorId(Constants.VENDOR_ID_UNKNOWN)
                .build();
        mService.getHdmiCecNetwork().addCecDevice(newDevice);
    }

    @ServiceThreadOnly
+28 −0
Original line number Diff line number Diff line
@@ -2120,6 +2120,34 @@ public class HdmiCecLocalDeviceTvTest {
        assertThat(mNativeWrapper.getResultMessages()).doesNotContain(giveOsdName);
    }

    @Test
    public void onOneTouchPlay_wakeUp_addCecDevice() {
        assertThat(mHdmiControlService.getHdmiCecNetwork().getDeviceInfoList(false))
                .isEmpty();
        mHdmiCecLocalDeviceTv.mService.getHdmiCecConfig().setIntValue(
                HdmiControlManager.CEC_SETTING_NAME_TV_WAKE_ON_ONE_TOUCH_PLAY,
                HdmiControlManager.TV_WAKE_ON_ONE_TOUCH_PLAY_ENABLED);
        mPowerManager.setInteractive(false);
        mTestLooper.dispatchAll();

        HdmiCecMessage textViewOn = HdmiCecMessageBuilder.buildTextViewOn(ADDR_PLAYBACK_1,
                mTvLogicalAddress);
        HdmiCecMessage activeSource = HdmiCecMessageBuilder.buildActiveSource(ADDR_PLAYBACK_1,
                0x1000);
        assertThat(mHdmiCecLocalDeviceTv.dispatchMessage(textViewOn)).isEqualTo(Constants.HANDLED);
        assertThat(mHdmiCecLocalDeviceTv.dispatchMessage(activeSource)).isEqualTo(
                Constants.HANDLED);
        mTestLooper.dispatchAll();
        assertThat(mPowerManager.isInteractive()).isTrue();

        // FakePowerManagerWrapper#wakeUp() doesn't broadcast Intent.ACTION_SCREEN_ON so we have to
        // manually call this method.
        mHdmiControlService.onWakeUp(WAKE_UP_SCREEN_ON);
        mTestLooper.dispatchAll();
        assertThat(mHdmiControlService.getHdmiCecNetwork().getDeviceInfoList(false))
                .hasSize(1);
    }

    protected static class MockTvDevice extends HdmiCecLocalDeviceTv {
        MockTvDevice(HdmiControlService service) {
            super(service);