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

Commit b2596e61 authored by Yuncheol Heo's avatar Yuncheol Heo Committed by Android (Google) Code Review
Browse files

Merge "Handle the power state change."

parents 40d43b27 38db629d
Loading
Loading
Loading
Loading
+103 −0
Original line number Diff line number Diff line
@@ -155,6 +155,18 @@ abstract class HdmiCecLocalDevice {
                return handleSystemAudioModeStatus(message);
            case HdmiCec.MESSAGE_REPORT_AUDIO_STATUS:
                return handleReportAudioStatus(message);
            case HdmiCec.MESSAGE_STANDBY:
                return handleStandby(message);
            case HdmiCec.MESSAGE_TEXT_VIEW_ON:
                return handleTextViewOn(message);
            case HdmiCec.MESSAGE_IMAGE_VIEW_ON:
                return handleImageViewOn(message);
            case HdmiCec.MESSAGE_USER_CONTROL_PRESSED:
                return handleUserControlPressed(message);
            case HdmiCec.MESSAGE_SET_STREAM_PATH:
                return handleSetStreamPath(message);
            case HdmiCec.MESSAGE_GIVE_DEVICE_POWER_STATUS:
                return handleGiveDevicePowerStatus(message);
            default:
                return false;
        }
@@ -275,6 +287,67 @@ abstract class HdmiCecLocalDevice {
        return false;
    }

    @ServiceThreadOnly
    protected boolean handleStandby(HdmiCecMessage message) {
        assertRunOnServiceThread();
        // Seq #12
        if (mService.isControlEnabled() && !isInPresetInstallationMode()
                && mService.isPowerOnOrTransient()) {
            mService.standby();
            return true;
        }
        return false;
    }

    @ServiceThreadOnly
    protected boolean handleUserControlPressed(HdmiCecMessage message) {
        assertRunOnServiceThread();
        final int opCode = message.getOpcode();
        final byte[] params = message.getParams();
        if (mService.isPowerOnOrTransient() && isPowerOffOrToggleCommand(message)) {
            mService.standby();
            return true;
        } else if (mService.isPowerStandbyOrTransient() && isPowerOnOrToggleCommand(message)) {
            mService.wakeUp();
            return true;
        }
        return false;
    }

    private static boolean isPowerOnOrToggleCommand(HdmiCecMessage message) {
        byte[] params = message.getParams();
        return message.getOpcode() == HdmiCec.MESSAGE_USER_CONTROL_PRESSED && params.length == 1
                && (params[0] == HdmiConstants.UI_COMMAND_POWER
                        || params[0] == HdmiConstants.UI_COMMAND_POWER_ON_FUNCTION
                        || params[0] == HdmiConstants.UI_COMMAND_POWER_TOGGLE_FUNCTION);
    }

    private static boolean isPowerOffOrToggleCommand(HdmiCecMessage message) {
        byte[] params = message.getParams();
        return message.getOpcode() == HdmiCec.MESSAGE_USER_CONTROL_PRESSED && params.length == 1
                && (params[0] == HdmiConstants.UI_COMMAND_POWER
                        || params[0] == HdmiConstants.UI_COMMAND_POWER_OFF_FUNCTION
                        || params[0] == HdmiConstants.UI_COMMAND_POWER_TOGGLE_FUNCTION);
    }

    protected boolean handleTextViewOn(HdmiCecMessage message) {
        return false;
    }

    protected boolean handleImageViewOn(HdmiCecMessage message) {
        return false;
    }

    protected boolean handleSetStreamPath(HdmiCecMessage message) {
        return false;
    }

    protected boolean handleGiveDevicePowerStatus(HdmiCecMessage message) {
        mService.sendCecCommand(HdmiCecMessageBuilder.buildReportPowerStatus(
                mAddress, message.getSource(), mService.getPowerStatus()));
        return true;
    }

    @ServiceThreadOnly
    final void handleAddressAllocated(int logicalAddress) {
        assertRunOnServiceThread();
@@ -323,6 +396,10 @@ abstract class HdmiCecLocalDevice {
    @ServiceThreadOnly
    void addAndStartAction(final FeatureAction action) {
        assertRunOnServiceThread();
        if (mService.isPowerStandbyOrTransient()) {
            Slog.w(TAG, "Skip the action during Standby: " + action);
            return;
        }
        mActions.add(action);
        action.start();
    }
@@ -361,6 +438,7 @@ abstract class HdmiCecLocalDevice {
    void removeAction(final FeatureAction action) {
        assertRunOnServiceThread();
        mActions.remove(action);
        checkIfPendingActionsCleared();
    }

    // Remove all actions matched with the given Class type.
@@ -383,8 +461,14 @@ abstract class HdmiCecLocalDevice {
                mActions.remove(action);
            }
        }
        checkIfPendingActionsCleared();
    }

    protected void checkIfPendingActionsCleared() {
        if (mActions.isEmpty()) {
            mService.onPendingActionsCleared();
        }
    }
    protected void assertRunOnServiceThread() {
        if (Looper.myLooper() != mService.getServiceLooper()) {
            throw new IllegalStateException("Should run on service thread.");
@@ -488,4 +572,23 @@ abstract class HdmiCecLocalDevice {
        assertRunOnServiceThread();
        return mService.pathToPortId(newPath);
    }

    /**
     * Called when the system started transition to standby mode.
     *
     * @param initiatedByCec true if this power sequence is initiated
     *         by the reception the CEC messages like <StandBy>
     */
    protected void onTransitionToStandby(boolean initiatedByCec) {
        // If there are no outstanding actions, we'll go to STANDBY state.
        checkIfPendingActionsCleared();
    }

    /**
     * Called when the system goes to standby mode.
     *
     * @param initiatedByCec true if this power sequence is initiated
     *         by the reception the CEC messages like <StandBy>
     */
    protected void onStandBy(boolean initiatedByCec) {}
}
+54 −1
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.server.hdmi;

import android.hardware.hdmi.HdmiCec;
import android.hardware.hdmi.HdmiCecMessage;
import android.hardware.hdmi.IHdmiControlCallback;
import android.os.RemoteException;
import android.util.Slog;
@@ -29,6 +30,8 @@ import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly;
final class HdmiCecLocalDevicePlayback extends HdmiCecLocalDevice {
    private static final String TAG = "HdmiCecLocalDevicePlayback";

    private boolean mIsActiveSource = false;

    HdmiCecLocalDevicePlayback(HdmiControlService service) {
        super(service, HdmiCec.DEVICE_PLAYBACK);
    }
@@ -93,7 +96,57 @@ final class HdmiCecLocalDevicePlayback extends HdmiCecLocalDevice {
    @ServiceThreadOnly
    void onHotplug(int portId, boolean connected) {
        assertRunOnServiceThread();
        // TODO: clear devices connected to the given port id.
        mCecMessageCache.flushAll();
        mIsActiveSource = false;
        if (connected && mService.isPowerStandbyOrTransient()) {
            mService.wakeUp();
        }
    }

    @ServiceThreadOnly
    void markActiveSource() {
        assertRunOnServiceThread();
        mIsActiveSource = true;
    }

    @Override
    @ServiceThreadOnly
    protected boolean handleActiveSource(HdmiCecMessage message) {
        assertRunOnServiceThread();
        int physicalAddress = HdmiUtils.twoBytesToInt(message.getParams());
        if (physicalAddress != mService.getPhysicalAddress()) {
            mIsActiveSource = false;
            if (mService.isPowerOnOrTransient()) {
                mService.standby();
            }
            return true;
        }
        return false;
    }

    @Override
    @ServiceThreadOnly
    protected boolean handleSetStreamPath(HdmiCecMessage message) {
        assertRunOnServiceThread();
        int physicalAddress = HdmiUtils.twoBytesToInt(message.getParams());
        if (physicalAddress == mService.getPhysicalAddress()) {
            if (mService.isPowerStandbyOrTransient()) {
                mService.wakeUp();
            }
            return true;
        }
        return false;
    }

    @Override
    @ServiceThreadOnly
    protected void onTransitionToStandby(boolean initiatedByCec) {
        assertRunOnServiceThread();
        if (!initiatedByCec && mIsActiveSource) {
            mService.sendCecCommand(HdmiCecMessageBuilder.buildInactiveSource(
                    mAddress, mService.getPhysicalAddress()));
        }
        mIsActiveSource = false;
        checkIfPendingActionsCleared();
    }
}
+58 −0
Original line number Diff line number Diff line
@@ -441,6 +441,26 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
        return true;
    }

    @Override
    @ServiceThreadOnly
    protected boolean handleTextViewOn(HdmiCecMessage message) {
        assertRunOnServiceThread();
        if (mService.isPowerStandbyOrTransient()) {
            mService.wakeUp();
        }
        // TODO: Connect to Hardware input manager to invoke TV App with the appropriate channel
        //       that represents the source device.
        return true;
    }

    @Override
    @ServiceThreadOnly
    protected boolean handleImageViewOn(HdmiCecMessage message) {
        assertRunOnServiceThread();
        // Currently, it's the same as <Text View On>.
        return handleTextViewOn(message);
    }

    @ServiceThreadOnly
    private void launchDeviceDiscovery() {
        assertRunOnServiceThread();
@@ -985,4 +1005,42 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
        assertRunOnServiceThread();
        mAutoDeviceOff = enabled;
    }

    @Override
    @ServiceThreadOnly
    protected void onTransitionToStandby(boolean initiatedByCec) {
        assertRunOnServiceThread();
        // Remove any repeated working actions.
        // HotplugDetectionAction will be reinstated during the wake up process.
        // HdmiControlService.onWakeUp() -> initializeLocalDevices() ->
        //     LocalDeviceTv.onAddressAllocated() -> launchDeviceDiscovery().
        removeAction(HotplugDetectionAction.class);
        checkIfPendingActionsCleared();
    }

    @Override
    @ServiceThreadOnly
    protected void onStandBy(boolean initiatedByCec) {
        assertRunOnServiceThread();
        // Seq #11
        if (!mService.isControlEnabled()) {
            return;
        }
        if (!initiatedByCec) {
            mService.sendCecCommand(HdmiCecMessageBuilder.buildStandby(
                    mAddress, HdmiCec.ADDR_BROADCAST));
        }
    }

    @Override
    @ServiceThreadOnly
    protected boolean handleStandby(HdmiCecMessage message) {
        assertRunOnServiceThread();
        // Seq #12
        // Tv accepts directly addressed <Standby> only.
        if (message.getDestination() == mAddress) {
            super.handleStandby(message);
        }
        return false;
    }
}
+38 −0
Original line number Diff line number Diff line
@@ -269,6 +269,18 @@ public class HdmiCecMessageBuilder {
                physicalAddressToParam(physicalAddress));
    }

    /**
     * Build &lt;Inactive Source&gt; command.
     *
     * @param src source address of command
     * @param physicalAddress physical address of the device to become inactive
     * @return newly created {@link HdmiCecMessage}
     */
    static HdmiCecMessage buildInactiveSource(int src, int physicalAddress) {
        return buildCommand(src, HdmiCec.ADDR_BROADCAST, HdmiCec.MESSAGE_INACTIVE_SOURCE,
                physicalAddressToParam(physicalAddress));
    }

    /**
     * Build &lt;Set Stream Path&gt; command.
     *
@@ -312,6 +324,21 @@ public class HdmiCecMessageBuilder {
        return buildCommand(src, dest, HdmiCec.MESSAGE_GIVE_DEVICE_POWER_STATUS);
    }

    /**
     * Build &lt;Report Power Status&gt; command.
     *
     * @param src source address of command
     * @param dest destination address of command
     * @param powerStatus power status of the device
     * @return newly created {@link HdmiCecMessage}
     */
    static HdmiCecMessage buildReportPowerStatus(int src, int dest, int powerStatus) {
        byte[] param = new byte[] {
                (byte) (powerStatus)
        };
        return buildCommand(src, dest, HdmiCec.MESSAGE_REPORT_POWER_STATUS, param);
    }

    /**
     * Build &lt;System Audio Mode Request&gt; command.
     *
@@ -388,6 +415,17 @@ public class HdmiCecMessageBuilder {
        return buildCommand(src, dest, HdmiCec.MESSAGE_GIVE_SYSTEM_AUDIO_MODE_STATUS);
    }

    /**
     * Build &lt;Standby&gt; command.
     *
     * @param src source address of command
     * @param dest destination address of command
     * @return newly created {@link HdmiCecMessage}
     */
    public static HdmiCecMessage buildStandby(int src, int dest) {
        return buildCommand(src, dest, HdmiCec.MESSAGE_STANDBY);
    }

    /***** Please ADD new buildXXX() methods above. ******/

    /**
+2 −0
Original line number Diff line number Diff line
@@ -45,6 +45,8 @@ final class HdmiConstants {
    static final int UI_COMMAND_MUTE = 0x43;
    static final int UI_COMMAND_MUTE_FUNCTION = 0x65;
    static final int UI_COMMAND_RESTORE_VOLUME_FUNCTION = 0x66;
    static final int UI_COMMAND_POWER_TOGGLE_FUNCTION = 0x6B;
    static final int UI_COMMAND_POWER_OFF_FUNCTION = 0x6C;
    static final int UI_COMMAND_POWER_ON_FUNCTION = 0x6D;

    // Bit mask used to get the routing path of the top level device.
Loading