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

Commit 225d55a4 authored by Amy's avatar Amy Committed by shubang
Browse files

Add ActiveSouce handling logic to switch to ARC input

when the new Active is not under the current device.

ag/4958795

Note that this CL only handles automatically switching to ARC.
Switching back to HOME should be handled by SetStreamPath or RoutingChange.

Test: local test.

Bug: 112476228
Change-Id: I211130c9483be7fcfe55b6a57f43d82bcf319737
parent a26b9b94
Loading
Loading
Loading
Loading
+42 −7
Original line number Diff line number Diff line
@@ -256,6 +256,41 @@ final class Constants {
    static final int USE_LAST_STATE_SYSTEM_AUDIO_CONTROL_ON_POWER_ON = 1;
    static final int NEVER_SYSTEM_AUDIO_CONTROL_ON_POWER_ON = 2;

    // Port id to record local active port for Routing Control features
    // They are used to map to corresponding Inputs
    // Current interface is only implemented for specific device.
    // Developers can add more port number and map them to corresponding inputs on demand.
    @IntDef({
        CEC_SWITCH_HOME,
        CEC_SWITCH_HDMI1,
        CEC_SWITCH_HDMI2,
        CEC_SWITCH_HDMI3,
        CEC_SWITCH_HDMI4,
        CEC_SWITCH_HDMI5,
        CEC_SWITCH_HDMI6,
        CEC_SWITCH_HDMI7,
        CEC_SWITCH_HDMI8,
        CEC_SWITCH_ARC,
        CEC_SWITCH_BLUETOOTH,
        CEC_SWITCH_OPTICAL,
        CEC_SWITCH_AUX
    })
    @interface LocalActivePort {}
    static final int CEC_SWITCH_HOME = 0;
    static final int CEC_SWITCH_HDMI1 = 1;
    static final int CEC_SWITCH_HDMI2 = 2;
    static final int CEC_SWITCH_HDMI3 = 3;
    static final int CEC_SWITCH_HDMI4 = 4;
    static final int CEC_SWITCH_HDMI5 = 5;
    static final int CEC_SWITCH_HDMI6 = 6;
    static final int CEC_SWITCH_HDMI7 = 7;
    static final int CEC_SWITCH_HDMI8 = 8;
    static final int CEC_SWITCH_ARC = 17;
    static final int CEC_SWITCH_BLUETOOTH = 18;
    static final int CEC_SWITCH_OPTICAL = 19;
    static final int CEC_SWITCH_AUX = 20;
    static final int CEC_SWITCH_PORT_MAX = 21;

    static final String PROPERTY_PREFERRED_ADDRESS_AUDIO_SYSTEM =
            "persist.sys.hdmi.addr.audiosystem";
    static final String PROPERTY_PREFERRED_ADDRESS_PLAYBACK = "persist.sys.hdmi.addr.playback";
@@ -273,6 +308,13 @@ final class Constants {
    // TODO(OEM): Set this to true to enable 'Set Menu Language' feature. False by default.
    static final String PROPERTY_SET_MENU_LANGUAGE = "ro.hdmi.set_menu_language";

    /**
     * Property to save the ARC port id on system audio device.
     * <p>When ARC is initiated, this port will be used to turn on ARC.
     */
    static final String PROPERTY_SYSTEM_AUDIO_DEVICE_ARC_PORT =
            "ro.hdmi.property_sytem_audio_device_arc_port";

    /**
     * Property to disable muting logic in System Audio Control handling. Default is true.
     *
@@ -330,13 +372,6 @@ final class Constants {
    static final String PROPERTY_SYSTEM_AUDIO_MODE_AUDIO_PORT =
            "persist.sys.hdmi.property_sytem_audio_mode_audio_port";

    /**
     * Property to save the ARC port id on system audio device.
     * <p>When ARC is initiated, this port will be used to turn on ARC.
     */
    static final String PROPERTY_SYSTEM_AUDIO_DEVICE_ARC_PORT =
            "persist.sys.hdmi.property_sytem_audio_device_arc_port";

    /**
     * Property to indicate if a CEC audio device should forward volume keys when system audio mode
     * is off.
+67 −10
Original line number Diff line number Diff line
@@ -20,10 +20,12 @@ import static com.android.server.hdmi.Constants.PROPERTY_SYSTEM_AUDIO_CONTROL_ON
import static com.android.server.hdmi.Constants.USE_LAST_STATE_SYSTEM_AUDIO_CONTROL_ON_POWER_ON;

import android.annotation.Nullable;
import android.content.Intent;
import android.hardware.hdmi.HdmiDeviceInfo;
import android.media.AudioDeviceInfo;
import android.media.AudioManager;
import android.media.AudioSystem;
import android.media.tv.TvContract;
import android.os.SystemProperties;
import android.provider.Settings.Global;

@@ -60,16 +62,8 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource {
    // AVR as audio receiver.
    @ServiceThreadOnly private boolean mArcEstablished = false;

    /**
     * Return value of {@link #getLocalPortFromPhysicalAddress(int)}
     */
    private static final int TARGET_NOT_UNDER_LOCAL_DEVICE = -1;
    private static final int TARGET_SAME_PHYSICAL_ADDRESS = 0;

    // Local active port number used for Routing Control.
    // Default 0 means HOME is the current active path. Temp solution only.
    // TODO(amyjojo): adding system constants for Atom inputs port and TIF mapping.
    private int mLocalActivePath = 0;
    private boolean mArcIntentUsed = SystemProperties
            .get(Constants.PROPERTY_SYSTEM_AUDIO_DEVICE_ARC_PORT, "0").contains("tvinput");

    protected HdmiCecLocalDeviceAudioSystem(HdmiControlService service) {
        super(service, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
@@ -595,4 +589,67 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource {
        assertRunOnServiceThread();
        mAutoDeviceOff = autoDeviceOff;
    }

    @Override
    protected void switchInputOnReceivingNewActivePath(int physicalAddress) {
        int port = getLocalPortFromPhysicalAddress(physicalAddress);
        // Wake up if the new Active Source is the current device or under it
        // or if Arc is enabled.
        if ((isArcEnabled() || port >= 0) && mService.isPowerStandbyOrTransient()) {
            mService.wakeUp();
        }

        if (isArcEnabled() && port < 0) {
            // New active source will trigger arc input switching.
            routeToInputFromPortId(Constants.CEC_SWITCH_ARC);
        } else if (port >= 0) {
            // TODO(amyjojo): Routing Control input swithcing.
        }
    }

    @Override
    protected void routeToInputFromPortId(int portId) {
        if (mArcIntentUsed) {
            routeToTvInputFromPortId(portId);
        } else {
            // TODO(): implement input switching for devices not using TvInput.
        }
    }

    protected void routeToTvInputFromPortId(int portId) {
        if (portId < 0 || portId >= Constants.CEC_SWITCH_PORT_MAX) {
            HdmiLogger.debug("Invalid port number for Tv Input switching.");
            return;
        }
        // TODO(amyjojo): handle if switching to the current input
        if (portId == Constants.CEC_SWITCH_HOME) {
            switchToHomeTvInput();
        } else if (portId == Constants.CEC_SWITCH_ARC) {
            switchToTvInput(SystemProperties.get(Constants.PROPERTY_SYSTEM_AUDIO_DEVICE_ARC_PORT));
            // TODO(amyjojo): check if setParameters is still needed.
            return;
        } else {
            // TODO(amyjojo): map port number parsed from physical address to LocalActivePort id
        }

        setLocalActivePort(portId);
    }

    // For device to switch to specific TvInput with corresponding URI.
    private void switchToTvInput(String uri) {
        mService.getContext().startActivity(new Intent(Intent.ACTION_VIEW,
                TvContract.buildChannelUriForPassthroughInput(uri))
                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
    }

    // For device using TvInput to switch to Home.
    private void switchToHomeTvInput() {
        Intent activityIntent = new Intent(Intent.ACTION_MAIN)
                .addCategory(Intent.CATEGORY_HOME)
                .setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP
                        | Intent.FLAG_ACTIVITY_SINGLE_TOP
                        | Intent.FLAG_ACTIVITY_NEW_TASK
                        | Intent.FLAG_ACTIVITY_NO_ANIMATION);
        mService.getContext().startActivity(activityIntent);
    }
}
+2 −1
Original line number Diff line number Diff line
@@ -277,7 +277,8 @@ final class HdmiCecLocalDevicePlayback extends HdmiCecLocalDeviceSource {
        }
    }

    private void maySendActiveSource(int dest) {
    @Override
    protected void maySendActiveSource(int dest) {
        if (mIsActiveSource) {
            mService.sendCecCommand(HdmiCecMessageBuilder.buildActiveSource(
                    mAddress, mService.getPhysicalAddress()));
+55 −3
Original line number Diff line number Diff line
@@ -21,6 +21,9 @@ import android.hardware.hdmi.IHdmiControlCallback;
import android.os.RemoteException;
import android.util.Slog;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.hdmi.Constants.LocalActivePort;
import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly;

import java.util.List;
@@ -35,6 +38,15 @@ abstract class HdmiCecLocalDeviceSource extends HdmiCecLocalDevice {
    // Indicate if current device is Active Source or not
    private boolean mIsActiveSource = false;

    // Local active port number used for Routing Control.
    // This records the default active port or the previous valid active port.
    // Default is HOME input.
    // Note that we don't save active path here because for source device,
    // new Active Source physical address might not match the local active path
    @GuardedBy("mLock")
    @LocalActivePort
    private int mLocalActivePort = Constants.CEC_SWITCH_HOME;

    protected HdmiCecLocalDeviceSource(HdmiControlService service, int deviceType) {
        super(service, deviceType);
    }
@@ -99,6 +111,7 @@ abstract class HdmiCecLocalDeviceSource extends HdmiCecLocalDevice {
            setActiveSource(activeSource);
        }
        setIsActiveSource(physicalAddress == mService.getPhysicalAddress());
        switchInputOnReceivingNewActivePath(physicalAddress);
        return true;
    }

@@ -106,16 +119,55 @@ abstract class HdmiCecLocalDeviceSource extends HdmiCecLocalDevice {
    @ServiceThreadOnly
    protected boolean handleRequestActiveSource(HdmiCecMessage message) {
        assertRunOnServiceThread();
        maySendActiveSource(message.getSource());
        return true;
    }

    @ServiceThreadOnly
    void setIsActiveSource(boolean on) {
        assertRunOnServiceThread();
        mIsActiveSource = on;
    }

    protected void maySendActiveSource(int dest) {
        if (mIsActiveSource) {
            mService.sendCecCommand(HdmiCecMessageBuilder.buildActiveSource(
                    mAddress, mService.getPhysicalAddress()));
        }
        return true;
    }

    @ServiceThreadOnly
    void setIsActiveSource(boolean on) {
    // Check if current device is the Active Source
    boolean isActiveSource() {
        assertRunOnServiceThread();
        mIsActiveSource = on;
        return mIsActiveSource;
    }

    // Method to switch Input with the port id.
    // All the devices with Switch functionality should implement this.
    protected void routeToInputFromPortId(int portId) {
        // do nothing
    }

    // Method to switch Input with the new Active Path.
    // All the devices with Switch functionality should implement this.
    protected void switchInputOnReceivingNewActivePath(int physicalAddress) {
        // do nothing
    }

    @VisibleForTesting
    protected void setLocalActivePort(@LocalActivePort int portId) {
        synchronized (mLock) {
            mLocalActivePort = portId;
        }
    }

    // To get the local active port to switch to
    // when receivng routing change or information.
    @LocalActivePort
    protected int getLocalActivePort() {
        synchronized (mLock) {
            return mLocalActivePort;
        }
    }
}
+14 −0
Original line number Diff line number Diff line
@@ -557,4 +557,18 @@ public class HdmiCecLocalDeviceAudioSystemTest {
        mTestLooper.dispatchAll();
        assertThat(mNativeWrapper.getOnlyResultMessage()).isEqualTo(expectedMessage);
    }

    @Test
    public void handleActiveSource_activeSourceFromTV_swithToArc() {
        mHdmiCecLocalDeviceAudioSystem.setArcStatus(true);
        HdmiCecMessage message =
                HdmiCecMessageBuilder.buildActiveSource(ADDR_TV, 0x0000);

        ActiveSource expectedActiveSource = ActiveSource.of(ADDR_TV, 0x0000);

        assertThat(mHdmiCecLocalDeviceAudioSystem.handleActiveSource(message)).isTrue();
        mTestLooper.dispatchAll();
        assertThat(mHdmiCecLocalDeviceAudioSystem.getActiveSource())
            .isEqualTo(expectedActiveSource);
    }
}