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

Commit e26d833c authored by Jinsuk Kim's avatar Jinsuk Kim
Browse files

CEC: Keep Playback device awake while it is the active source

Alleviates the user experience issue of having to turn on the device
manually when it goes to standby mode while the device occupies
the display.

Bug: 18882764
Change-Id: I10b239a599a310e47e3c2cb98737e4b0fdb4e435
parent cb8d8e10
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -201,6 +201,14 @@ abstract class HdmiCecLocalDevice {
        return true;
    }

    /**
     * Returns true if the local device allows the system to be put to standby.
     * The default implementation returns true.
     */
    protected boolean canGoToStandby() {
        return true;
    }

    /**
     * Dispatch incoming message.
     *
+41 −18
Original line number Diff line number Diff line
@@ -19,6 +19,8 @@ package com.android.server.hdmi;
import android.hardware.hdmi.HdmiControlManager;
import android.hardware.hdmi.HdmiDeviceInfo;
import android.hardware.hdmi.IHdmiControlCallback;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.os.RemoteException;
import android.os.SystemProperties;
import android.util.Slog;
@@ -34,16 +36,16 @@ final class HdmiCecLocalDevicePlayback extends HdmiCecLocalDevice {

    private boolean mIsActiveSource = false;

    // Used to keep the device awake while it is the active source. For devices that
    // cannot wake up via CEC commands, this address the inconvenience of having to
    // turn them on.
    // Lazily initialized - should call getWakeLock() to get the instance.
    private WakeLock mWakeLock;

    HdmiCecLocalDevicePlayback(HdmiControlService service) {
        super(service, HdmiDeviceInfo.DEVICE_PLAYBACK);
    }

    @Override
    void init() {
        super.init();
        mIsActiveSource = false;
    }

    @Override
    @ServiceThreadOnly
    protected void onAddressAllocated(int logicalAddress, int reason) {
@@ -129,12 +131,37 @@ final class HdmiCecLocalDevicePlayback extends HdmiCecLocalDevice {
        if (connected && mService.isPowerStandbyOrTransient()) {
            mService.wakeUp();
        }
        if (!connected) {
            getWakeLock().release();
        }
    }

    @ServiceThreadOnly
    void markActiveSource() {
    void setActiveSource(boolean on) {
        assertRunOnServiceThread();
        mIsActiveSource = true;
        mIsActiveSource = on;
        if (on) {
            getWakeLock().acquire();
            HdmiLogger.debug("active source: %b. Wake lock acquired", mIsActiveSource);
        } else {
            getWakeLock().release();
            HdmiLogger.debug("Wake lock released");
        }
    }

    @ServiceThreadOnly
    private WakeLock getWakeLock() {
        assertRunOnServiceThread();
        if (mWakeLock == null) {
            mWakeLock = mService.getPowerManager().newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
            mWakeLock.setReferenceCounted(false);
        }
        return mWakeLock;
    }

    @Override
    protected boolean canGoToStandby() {
        return !getWakeLock().isHeld();
    }

    @Override
@@ -148,7 +175,7 @@ final class HdmiCecLocalDevicePlayback extends HdmiCecLocalDevice {

    private void mayResetActiveSource(int physicalAddress) {
        if (physicalAddress != mService.getPhysicalAddress()) {
            mIsActiveSource = false;
            setActiveSource(false);
        }
    }

@@ -163,9 +190,9 @@ final class HdmiCecLocalDevicePlayback extends HdmiCecLocalDevice {
        return true;  // Broadcast message.
    }

    // Samsung model, we tested, sends <RoutingChange> and <RequestActiveSource> consecutively,
    // Then if there is no <ActiveSource> response, it will change the input to
    // the internal source.  To handle this, we'll set ActiveSource aggressively.
    // Samsung model we tested sends <Routing Change> and <Request Active Source>
    // in a row, and then changes the input to the internal source if there is no
    // <Active Source> in response. To handle this, we'll set ActiveSource aggressively.
    @Override
    @ServiceThreadOnly
    protected boolean handleRoutingChange(HdmiCecMessage message) {
@@ -185,11 +212,7 @@ final class HdmiCecLocalDevicePlayback extends HdmiCecLocalDevice {
    }

    private void maySetActiveSource(int physicalAddress) {
        if (physicalAddress == mService.getPhysicalAddress()) {
            mIsActiveSource = true;
        } else {
            mIsActiveSource = false;
        }
        setActiveSource(physicalAddress == mService.getPhysicalAddress());
    }

    private void wakeUpIfActiveSource() {
@@ -226,7 +249,7 @@ final class HdmiCecLocalDevicePlayback extends HdmiCecLocalDevice {
            mService.sendCecCommand(HdmiCecMessageBuilder.buildInactiveSource(
                    mAddress, mService.getPhysicalAddress()));
        }
        mIsActiveSource = false;
        setActiveSource(false);
        checkIfPendingActionsCleared();
    }

+18 −4
Original line number Diff line number Diff line
@@ -277,6 +277,9 @@ public final class HdmiControlService extends SystemService {
    @Nullable
    private TvInputManager mTvInputManager;

    @Nullable
    private PowerManager mPowerManager;

    // Last input port before switching to the MHL port. Should switch back to this port
    // when the mobile device sends the request one touch play with off.
    // Gets invalidated if we go to other port/input.
@@ -353,6 +356,7 @@ public final class HdmiControlService extends SystemService {
        if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
            mTvInputManager = (TvInputManager) getContext().getSystemService(
                    Context.TV_INPUT_SERVICE);
            mPowerManager = (PowerManager) getContext().getSystemService(Context.POWER_SERVICE);
        }
    }

@@ -370,6 +374,10 @@ public final class HdmiControlService extends SystemService {
        mTvInputManager.unregisterCallback(callback);
    }

    PowerManager getPowerManager() {
        return mPowerManager;
    }

    /**
     * Called when the initialization of local devices is complete.
     */
@@ -1859,8 +1867,7 @@ public final class HdmiControlService extends SystemService {
    void wakeUp() {
        assertRunOnServiceThread();
        mWakeUpMessageReceived = true;
        PowerManager pm = (PowerManager) getContext().getSystemService(Context.POWER_SERVICE);
        pm.wakeUp(SystemClock.uptimeMillis());
        mPowerManager.wakeUp(SystemClock.uptimeMillis());
        // PowerManger will send the broadcast Intent.ACTION_SCREEN_ON and after this gets
        // the intent, the sequence will continue at onWakeUp().
    }
@@ -1869,8 +1876,7 @@ public final class HdmiControlService extends SystemService {
    void standby() {
        assertRunOnServiceThread();
        mStandbyMessageReceived = true;
        PowerManager pm = (PowerManager) getContext().getSystemService(Context.POWER_SERVICE);
        pm.goToSleep(SystemClock.uptimeMillis(), PowerManager.GO_TO_SLEEP_REASON_HDMI, 0);
        mPowerManager.goToSleep(SystemClock.uptimeMillis(), PowerManager.GO_TO_SLEEP_REASON_HDMI, 0);
        // PowerManger will send the broadcast Intent.ACTION_SCREEN_OFF and after this gets
        // the intent, the sequence will continue at onStandby().
    }
@@ -1896,6 +1902,7 @@ public final class HdmiControlService extends SystemService {
    @ServiceThreadOnly
    private void onStandby() {
        assertRunOnServiceThread();
        if (!canGoToStandby()) return;
        mPowerStatus = HdmiControlManager.POWER_STATUS_TRANSIENT_TO_STANDBY;
        invokeVendorCommandListenersOnControlStateChanged(false,
                HdmiControlManager.CONTROL_STATE_CHANGED_REASON_STANDBY);
@@ -1916,6 +1923,13 @@ public final class HdmiControlService extends SystemService {
        });
    }

    private boolean canGoToStandby() {
        for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) {
            if (!device.canGoToStandby()) return false;
        }
        return true;
    }

    @ServiceThreadOnly
    private void onLanguageChanged(String language) {
        assertRunOnServiceThread();
+1 −1
Original line number Diff line number Diff line
@@ -82,7 +82,7 @@ final class OneTouchPlayAction extends HdmiCecFeatureAction {
    private void broadcastActiveSource() {
        sendCommand(HdmiCecMessageBuilder.buildActiveSource(getSourceAddress(), getSourcePath()));
        // Because only playback device can create this action, it's safe to cast.
        playback().markActiveSource();
        playback().setActiveSource(true);
    }

    private void queryDevicePowerStatus() {