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

Commit ae30f181 authored by Paul Colta's avatar Paul Colta Committed by Paul Colța
Browse files

HDMICEC: TV send <Active Source> if <Request Active Source> times out

If there is no source device responding to the <Request Active Source> message sent by the TV within 2 seconds, the TV will broadcast <Active Source>.

Test: atest HdmiCecLocalDeviceTvTest
Bug: 238417516
Bug: 161955781
Change-Id: I301c4540f47b9aeaaa4c95fe748f902ad2fd5814
parent b53fbe73
Loading
Loading
Loading
Loading
+16 −4
Original line number Diff line number Diff line
@@ -191,9 +191,16 @@ public final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
        launchDeviceDiscovery();
        startQueuedActions();
        if (!mDelayedMessageBuffer.isBuffered(Constants.MESSAGE_ACTIVE_SOURCE)) {
            mService.sendCecCommand(
                    HdmiCecMessageBuilder.buildRequestActiveSource(
                            getDeviceInfo().getLogicalAddress()));
            addAndStartAction(new RequestActiveSourceAction(this, new IHdmiControlCallback.Stub() {
                @Override
                public void onComplete(int result) {
                    if (result != HdmiControlManager.RESULT_SUCCESS) {
                        mService.sendCecCommand(HdmiCecMessageBuilder.buildActiveSource(
                                getDeviceInfo().getLogicalAddress(),
                                getDeviceInfo().getPhysicalAddress()));
                    }
                }
            }));
        }
    }

@@ -1333,8 +1340,13 @@ public final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
        removeAction(TimerRecordingAction.class);
        removeAction(NewDeviceAction.class);
        removeAction(AbsoluteVolumeAudioStatusAction.class);
        // Remove pending actions.
        removeAction(RequestActiveSourceAction.class);

        // Keep SAM enabled if eARC is enabled, unless we're going to Standby.
        if (initiatedByCec || !mService.isEarcEnabled()){
            disableSystemAudioIfExist();
        }
        disableArcIfExist();

        super.disableDevice(initiatedByCec, callback);
+66 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.server.hdmi;

import android.hardware.hdmi.HdmiControlManager;
import android.hardware.hdmi.IHdmiControlCallback;
import android.util.Slog;

/**
 * Feature action that sends <Request Active Source> message and waits for <Active Source>.
 */
public class RequestActiveSourceAction extends HdmiCecFeatureAction {
    private static final String TAG = "RequestActiveSourceAction";

    // State to wait for the <Active Source> message.
    private static final int STATE_WAIT_FOR_ACTIVE_SOURCE = 1;

    RequestActiveSourceAction(HdmiCecLocalDevice source, IHdmiControlCallback callback) {
        super(source, callback);
    }

    @Override
    boolean start() {
        Slog.v(TAG, "RequestActiveSourceAction started.");

        sendCommand(HdmiCecMessageBuilder.buildRequestActiveSource(getSourceAddress()));

        mState = STATE_WAIT_FOR_ACTIVE_SOURCE;
        addTimer(mState, HdmiConfig.TIMEOUT_MS);
        return true;
    }

    @Override
    boolean processCommand(HdmiCecMessage cmd) {
        // The action finishes successfully if the <Active Source> message is received.
        // {@link HdmiCecLocalDevice#onMessage} handles this message, so false is returned.
        if (cmd.getOpcode() == Constants.MESSAGE_ACTIVE_SOURCE) {
            finishWithCallback(HdmiControlManager.RESULT_SUCCESS);
        }
        return false;
    }

    @Override
    void handleTimerEvent(int state) {
        if (mState != state) {
            return;
        }
        if (mState == STATE_WAIT_FOR_ACTIVE_SOURCE) {
            finishWithCallback(HdmiControlManager.RESULT_TIMEOUT);
        }
    }
}
+43 −0
Original line number Diff line number Diff line
@@ -1680,4 +1680,47 @@ public class HdmiCecLocalDeviceTvTest {
        assertThat(mHdmiControlService.isSystemAudioActivated()).isTrue();

    }

    @Test
    public void onAddressAllocated_startRequestActiveSourceAction_playbackActiveSource() {
        HdmiCecMessage requestActiveSource =
                HdmiCecMessageBuilder.buildRequestActiveSource(ADDR_TV);
        HdmiCecMessage activeSourceFromPlayback =
                HdmiCecMessageBuilder.buildActiveSource(ADDR_PLAYBACK_1, 0x1000);
        HdmiCecMessage activeSourceFromTv =
                HdmiCecMessageBuilder.buildActiveSource(ADDR_TV, 0x0000);

        mHdmiControlService.getHdmiCecNetwork().clearLocalDevices();
        mNativeWrapper.setPollAddressResponse(ADDR_PLAYBACK_1, SendMessageResult.SUCCESS);
        mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
        mTestLooper.dispatchAll();

        assertThat(mNativeWrapper.getResultMessages()).contains(requestActiveSource);
        mNativeWrapper.clearResultMessages();
        mNativeWrapper.onCecMessage(activeSourceFromPlayback);
        mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS);
        mTestLooper.dispatchAll();

        assertThat(mNativeWrapper.getResultMessages()).doesNotContain(activeSourceFromTv);
    }

    @Test
    public void onAddressAllocated_startRequestActiveSourceAction_noActiveSource() {
        HdmiCecMessage requestActiveSource =
                HdmiCecMessageBuilder.buildRequestActiveSource(ADDR_TV);
        HdmiCecMessage activeSourceFromTv =
                HdmiCecMessageBuilder.buildActiveSource(ADDR_TV, 0x0000);

        mHdmiControlService.getHdmiCecNetwork().clearLocalDevices();
        mNativeWrapper.setPollAddressResponse(ADDR_PLAYBACK_1, SendMessageResult.SUCCESS);
        mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
        mTestLooper.dispatchAll();

        assertThat(mNativeWrapper.getResultMessages()).contains(requestActiveSource);
        mNativeWrapper.clearResultMessages();
        mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS);
        mTestLooper.dispatchAll();

        assertThat(mNativeWrapper.getResultMessages()).contains(activeSourceFromTv);
    }
}