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

Commit 00da8510 authored by Paul Colta's avatar Paul Colta
Browse files

HDMICEC: Disable CecController after the process of going to standby is completed

Move CecController disabling in a callback which is invoked after local
device's standby has finished.

This change helps to make sure the <Standby> message is broadcasted before
the HAL is disabled.

Bug: 253535259
Test: atest com.android.server.hdmi && atest CtsHdmiCecHostTestCases
Change-Id: I82f7dccf2a943166aa028159bf36b197d8dab08b
parent d1886c8e
Loading
Loading
Loading
Loading
+25 −1
Original line number Diff line number Diff line
@@ -174,6 +174,14 @@ abstract class HdmiCecLocalDevice extends HdmiLocalDevice {
                }
            };

    /**
     * A callback interface used by local devices use to indicate that they have finished their part
     * of the standby process.
     */
    interface StandbyCompletedCallback {
        void onStandbyCompleted();
    }

    /**
     * A callback interface to get notified when all pending action is cleared. It can be called
     * when timeout happened.
@@ -1260,8 +1268,14 @@ abstract class HdmiCecLocalDevice extends HdmiLocalDevice {
     *     messages like &lt;Standby&gt;
     * @param standbyAction Intent action that drives the standby process, either {@link
     *     HdmiControlService#STANDBY_SCREEN_OFF} or {@link HdmiControlService#STANDBY_SHUTDOWN}
     * @param callback callback invoked after the standby process for the local device is completed.
     */
    protected void onStandby(boolean initiatedByCec, int standbyAction) {}
    protected void onStandby(boolean initiatedByCec, int standbyAction,
            StandbyCompletedCallback callback) {}

    protected void onStandby(boolean initiatedByCec, int standbyAction) {
        onStandby(initiatedByCec, standbyAction, null);
    }

    /**
     * Called when the initialization of local devices is complete.
@@ -1422,6 +1436,16 @@ abstract class HdmiCecLocalDevice extends HdmiLocalDevice {
        }
    }

    @ServiceThreadOnly
    @VisibleForTesting
    public void invokeStandbyCompletedCallback(StandbyCompletedCallback callback) {
        assertRunOnServiceThread();
        if (callback == null) {
            return;
        }
        callback.onStandbyCompleted();
    }

    void sendUserControlPressedAndReleased(int targetAddress, int cecKeycode) {
        mService.sendCecCommand(
                HdmiCecMessageBuilder.buildUserControlPressed(
+18 −3
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import static android.hardware.hdmi.DeviceFeatures.FEATURE_SUPPORTED;
import static com.android.server.hdmi.Constants.ALWAYS_SYSTEM_AUDIO_CONTROL_ON_POWER_ON;
import static com.android.server.hdmi.Constants.PROPERTY_SYSTEM_AUDIO_CONTROL_ON_POWER_ON;
import static com.android.server.hdmi.Constants.USE_LAST_STATE_SYSTEM_AUDIO_CONTROL_ON_POWER_ON;
import static com.android.server.hdmi.HdmiControlService.SendMessageCallback;

import android.annotation.Nullable;
import android.content.ActivityNotFoundException;
@@ -243,7 +244,8 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource {

    @Override
    @ServiceThreadOnly
    protected void onStandby(boolean initiatedByCec, int standbyAction) {
    protected void onStandby(boolean initiatedByCec, int standbyAction,
            StandbyCompletedCallback callback) {
        assertRunOnServiceThread();
        // Invalidate the internal active source record when goes to standby
        // This set will also update mIsActiveSource
@@ -256,7 +258,7 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource {
                    Constants.PROPERTY_LAST_SYSTEM_AUDIO_CONTROL,
                    isSystemAudioActivated() ? "true" : "false");
        }
        terminateSystemAudioMode();
        terminateSystemAudioMode(callback);
    }

    @Override
@@ -1092,9 +1094,16 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource {
    }

    protected void terminateSystemAudioMode() {
        terminateSystemAudioMode(null);
    }

    // Since this method is not just called during the standby process, the callback should be
    // generalized in the future.
    protected void terminateSystemAudioMode(StandbyCompletedCallback callback) {
        // remove pending initiation actions
        removeAction(SystemAudioInitiationActionFromAvr.class);
        if (!isSystemAudioActivated()) {
            invokeStandbyCompletedCallback(callback);
            return;
        }

@@ -1102,7 +1111,13 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource {
            // send <Set System Audio Mode> [“Off”]
            mService.sendCecCommand(
                    HdmiCecMessageBuilder.buildSetSystemAudioMode(
                            getDeviceInfo().getLogicalAddress(), Constants.ADDR_BROADCAST, false));
                            getDeviceInfo().getLogicalAddress(), Constants.ADDR_BROADCAST, false),
                    new SendMessageCallback() {
                        @Override
                        public void onSendCompleted(int error) {
                            invokeStandbyCompletedCallback(callback);
                        }
                    });
        }
    }

+19 −7
Original line number Diff line number Diff line
@@ -237,9 +237,11 @@ public class HdmiCecLocalDevicePlayback extends HdmiCecLocalDeviceSource {

    @Override
    @ServiceThreadOnly
    protected void onStandby(boolean initiatedByCec, int standbyAction) {
    protected void onStandby(boolean initiatedByCec, int standbyAction,
            StandbyCompletedCallback callback) {
        assertRunOnServiceThread();
        if (!mService.isCecControlEnabled()) {
            invokeStandbyCompletedCallback(callback);
            return;
        }
        boolean wasActiveSource = isActiveSource();
@@ -247,12 +249,20 @@ public class HdmiCecLocalDevicePlayback extends HdmiCecLocalDeviceSource {
        mService.setActiveSource(Constants.ADDR_INVALID, Constants.INVALID_PHYSICAL_ADDRESS,
                "HdmiCecLocalDevicePlayback#onStandby()");
        if (!wasActiveSource) {
            invokeStandbyCompletedCallback(callback);
            return;
        }
        SendMessageCallback sendMessageCallback = new SendMessageCallback() {
            @Override
            public void onSendCompleted(int error) {
                invokeStandbyCompletedCallback(callback);
            }
        };
        if (initiatedByCec) {
            mService.sendCecCommand(
                    HdmiCecMessageBuilder.buildInactiveSource(
                            getDeviceInfo().getLogicalAddress(), mService.getPhysicalAddress()));
                            getDeviceInfo().getLogicalAddress(), mService.getPhysicalAddress()),
                    sendMessageCallback);
            return;
        }
        switch (standbyAction) {
@@ -265,7 +275,8 @@ public class HdmiCecLocalDevicePlayback extends HdmiCecLocalDeviceSource {
                    case HdmiControlManager.POWER_CONTROL_MODE_TV:
                        mService.sendCecCommand(
                                HdmiCecMessageBuilder.buildStandby(
                                        getDeviceInfo().getLogicalAddress(), Constants.ADDR_TV));
                                        getDeviceInfo().getLogicalAddress(), Constants.ADDR_TV),
                                sendMessageCallback);
                        break;
                    case HdmiControlManager.POWER_CONTROL_MODE_TV_AND_AUDIO_SYSTEM:
                        mService.sendCecCommand(
@@ -274,19 +285,19 @@ public class HdmiCecLocalDevicePlayback extends HdmiCecLocalDeviceSource {
                        mService.sendCecCommand(
                                HdmiCecMessageBuilder.buildStandby(
                                        getDeviceInfo().getLogicalAddress(),
                                        Constants.ADDR_AUDIO_SYSTEM));
                                        Constants.ADDR_AUDIO_SYSTEM), sendMessageCallback);
                        break;
                    case HdmiControlManager.POWER_CONTROL_MODE_BROADCAST:
                        mService.sendCecCommand(
                                HdmiCecMessageBuilder.buildStandby(
                                        getDeviceInfo().getLogicalAddress(),
                                        Constants.ADDR_BROADCAST));
                                        Constants.ADDR_BROADCAST), sendMessageCallback);
                        break;
                    case HdmiControlManager.POWER_CONTROL_MODE_NONE:
                        mService.sendCecCommand(
                                HdmiCecMessageBuilder.buildInactiveSource(
                                        getDeviceInfo().getLogicalAddress(),
                                        mService.getPhysicalAddress()));
                                        mService.getPhysicalAddress()), sendMessageCallback);
                        break;
                }
                break;
@@ -294,7 +305,8 @@ public class HdmiCecLocalDevicePlayback extends HdmiCecLocalDeviceSource {
                // ACTION_SHUTDOWN is taken as a signal to power off all the devices.
                mService.sendCecCommand(
                        HdmiCecMessageBuilder.buildStandby(
                                getDeviceInfo().getLogicalAddress(), Constants.ADDR_BROADCAST));
                                getDeviceInfo().getLogicalAddress(), Constants.ADDR_BROADCAST),
                        sendMessageCallback);
                break;
        }
    }
+12 −2
Original line number Diff line number Diff line
@@ -1395,10 +1395,12 @@ public final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {

    @Override
    @ServiceThreadOnly
    protected void onStandby(boolean initiatedByCec, int standbyAction) {
    protected void onStandby(boolean initiatedByCec, int standbyAction,
            StandbyCompletedCallback callback) {
        assertRunOnServiceThread();
        // Seq #11
        if (!mService.isCecControlEnabled()) {
            invokeStandbyCompletedCallback(callback);
            return;
        }
        boolean sendStandbyOnSleep =
@@ -1408,7 +1410,15 @@ public final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
        if (!initiatedByCec && sendStandbyOnSleep) {
            mService.sendCecCommand(
                    HdmiCecMessageBuilder.buildStandby(
                            getDeviceInfo().getLogicalAddress(), Constants.ADDR_BROADCAST));
                            getDeviceInfo().getLogicalAddress(), Constants.ADDR_BROADCAST),
                    new SendMessageCallback() {
                        @Override
                        public void onSendCompleted(int error) {
                            invokeStandbyCompletedCallback(callback);
                        }
                    });
        } else {
            invokeStandbyCompletedCallback(callback);
        }
    }

+22 −8
Original line number Diff line number Diff line
@@ -108,6 +108,7 @@ import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly;
import com.android.server.hdmi.HdmiCecController.AllocateAddressCallback;
import com.android.server.hdmi.HdmiCecLocalDevice.ActiveSource;
import com.android.server.hdmi.HdmiCecLocalDevice.PendingActionClearedCallback;
import com.android.server.hdmi.HdmiCecLocalDevice.StandbyCompletedCallback;

import libcore.util.EmptyArray;

@@ -3719,7 +3720,8 @@ public class HdmiControlService extends SystemService {
        return mMenuLanguage;
    }

    private void disableCecLocalDevices(PendingActionClearedCallback callback) {
    @VisibleForTesting
    protected void disableCecLocalDevices(PendingActionClearedCallback callback) {
        if (mCecController != null) {
            for (HdmiCecLocalDevice device : mHdmiCecNetwork.getLocalDeviceList()) {
                device.disableDevice(mStandbyMessageReceived, callback);
@@ -3747,21 +3749,33 @@ public class HdmiControlService extends SystemService {
     * cleared during standby. In this case, it does not execute the standby flow.
     */
    @ServiceThreadOnly
    private void onPendingActionsCleared(int standbyAction) {
    @VisibleForTesting
    protected void onPendingActionsCleared(int standbyAction) {
        assertRunOnServiceThread();
        Slog.v(TAG, "onPendingActionsCleared");
        int localDevicesCount = getAllCecLocalDevices().size();
        final int[] countStandbyCompletedDevices = new int[1];
        StandbyCompletedCallback callback = new StandbyCompletedCallback() {
            @Override
            public void onStandbyCompleted() {
                if (localDevicesCount < ++countStandbyCompletedDevices[0]) {
                    return;
                }

        if (mPowerStatusController.isPowerStatusTransientToStandby()) {
            mPowerStatusController.setPowerStatus(HdmiControlManager.POWER_STATUS_STANDBY);
            for (HdmiCecLocalDevice device : mHdmiCecNetwork.getLocalDeviceList()) {
                device.onStandby(mStandbyMessageReceived, standbyAction);
                if (isAudioSystemDevice() || !isPowerStandby()) {
                    return;
                }
            if (!isAudioSystemDevice()) {
                mCecController.enableSystemCecControl(false);
                mMhlController.setOption(OPTION_MHL_SERVICE_CONTROL, DISABLED);
            }
        }
        };

        if (mPowerStatusController.isPowerStatusTransientToStandby()) {
            mPowerStatusController.setPowerStatus(HdmiControlManager.POWER_STATUS_STANDBY);
            for (HdmiCecLocalDevice device : mHdmiCecNetwork.getLocalDeviceList()) {
                device.onStandby(mStandbyMessageReceived, standbyAction, callback);
            }
        }
        // Always reset this flag to set up for the next standby
        mStandbyMessageReceived = false;
    }
Loading