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

Commit 0c891e8f authored by Shubang Lu's avatar Shubang Lu Committed by Android (Google) Code Review
Browse files

Merge changes Ie889f696,Ie3d7189b,Ibeceb4c4,I08055c7e,I7b01513b, ...

* changes:
  playback device should handle the active source claiming when it exists.
  Set local active port to HOME when oneTouchPlay is triggered. Update local active source at the same time.
  Add ro.hdmi.property_hdmi_cec_never_assign_logical_addresses to skip the logical addresses that will not be assigned.
  Fix routing logic on handling routing change/info.
  Add routingChange and routingInformation handlers.
  Add setStreamPath handlers and do input switching according to the new active path.
  Add ActiveSouce handling logic to switch to ARC input when the new Active is not under the current device.
parents 0b22084b 8b4a4a90
Loading
Loading
Loading
Loading
+60 −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.
     *
@@ -291,6 +333,24 @@ final class Constants {
    static final String PROPERTY_HDMI_CEC_NEVER_CLAIM_PLAYBACK_LOGICAL_ADDRESS =
            "ro.hdmi.property_hdmi_cec_never_claim_playback_logical_address";

    /**
     * A comma separated list of logical addresses that HdmiControlService
     * will never assign local CEC devices to.
     *
     * <p> This is useful when HDMI CEC hardware module can't assign multiple logical addresses
     * in the range same range of 0-7 or 8-15.
     */
    static final String PROPERTY_HDMI_CEC_NEVER_ASSIGN_LOGICAL_ADDRESSES =
            "ro.hdmi.property_hdmi_cec_never_assign_logical_addresses";

    /**
     * Property to indicate if the current device is a cec switch device.
     *
     * <p> Default is false.
     */
    static final String PROPERTY_HDMI_IS_DEVICE_HDMI_CEC_SWITCH =
            "ro.hdmi.property_is_device_hdmi_cec_switch";

    // Set to false to allow playback device to go to suspend mode even
    // when it's an active source. True by default.
    static final String PROPERTY_KEEP_AWAKE = "persist.sys.hdmi.keep_awake";
@@ -330,13 +390,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.
+17 −3
Original line number Diff line number Diff line
@@ -22,20 +22,25 @@ import android.hardware.tv.cec.V1_0.SendMessageResult;
import android.os.Handler;
import android.os.Looper;
import android.os.MessageQueue;
import android.os.SystemProperties;
import android.util.Slog;
import android.util.SparseArray;

import com.android.internal.util.IndentingPrintWriter;
import com.android.server.hdmi.HdmiAnnotations.IoThreadOnly;
import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly;
import com.android.server.hdmi.HdmiControlService.DevicePollingCallback;

import libcore.util.EmptyArray;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.function.Predicate;
import java.util.concurrent.ArrayBlockingQueue;
import libcore.util.EmptyArray;
import java.util.function.Predicate;

import sun.util.locale.LanguageTag;

/**
@@ -112,10 +117,18 @@ final class HdmiCecController {

    private final NativeWrapper mNativeWrapperImpl;

    /** List of logical addresses that should not be assigned to the current device.
     *
     * <p>Parsed from {@link Constants#PROPERTY_HDMI_CEC_NEVER_ASSIGN_LOGICAL_ADDRESSES}
     */
    private final List<Integer> mNeverAssignLogicalAddresses;

    // Private constructor.  Use HdmiCecController.create().
    private HdmiCecController(HdmiControlService service, NativeWrapper nativeWrapper) {
        mService = service;
        mNativeWrapperImpl = nativeWrapper;
        mNeverAssignLogicalAddresses = mService.getIntList(SystemProperties.get(
            Constants.PROPERTY_HDMI_CEC_NEVER_ASSIGN_LOGICAL_ADDRESSES));
    }

    /**
@@ -208,7 +221,8 @@ final class HdmiCecController {
        for (int i = 0; i < NUM_LOGICAL_ADDRESS; ++i) {
            int curAddress = (startAddress + i) % NUM_LOGICAL_ADDRESS;
            if (curAddress != Constants.ADDR_UNREGISTERED
                    && deviceType == HdmiUtils.getTypeFromAddress(curAddress)) {
                    && deviceType == HdmiUtils.getTypeFromAddress(curAddress)
                    && !mNeverAssignLogicalAddresses.contains(curAddress)) {
                boolean acked = false;
                for (int j = 0; j < HdmiConfig.ADDRESS_ALLOCATION_RETRY; ++j) {
                    if (sendPollMessage(curAddress, curAddress, 1)) {
+25 −1
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ import android.view.KeyEvent;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.hdmi.Constants.LocalActivePort;
import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly;
import com.android.server.hdmi.HdmiControlService.SendMessageCallback;

@@ -1051,7 +1052,7 @@ abstract class HdmiCecLocalDevice {
     * <p>This check assumes target address is valid.
     * @param targetPhysicalAddress is the physical address of the target device
     * @return
     * <p>If the target device is under the current device, return the port number of current device
     * If the target device is under the current device, return the port number of current device
     * that the target device is connected to.
     *
     * <p>If the target device has the same physical address as the current device, return
@@ -1085,4 +1086,27 @@ abstract class HdmiCecLocalDevice {
        }
        return TARGET_NOT_UNDER_LOCAL_DEVICE;
    }

    /** Calculates the physical address for {@code activePortId}.
     *
     * <p>This method assumes current device physical address is valid.
     * <p>If the current device is already the leaf of the whole CEC system
     * and can't have devices under it, will return its own physical address.
     *
     * @param activePortId is the local active port Id
     * @return the calculated physical address of the port
     */
    protected int getActivePathOnSwitchFromActivePortId(@LocalActivePort int activePortId) {
        int myPhysicalAddress = mService.getPhysicalAddress();
        int finalMask = activePortId << 8;
        int mask;
        for (mask = 0x0F00; mask > 0x000F;  mask >>= 4) {
            if ((myPhysicalAddress & mask) == 0)  {
                break;
            } else {
                finalMask >>= 4;
            }
        }
        return finalMask | myPhysicalAddress;
    }
}
+151 −9
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;

@@ -32,6 +34,8 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.server.hdmi.Constants.AudioCodec;
import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly;

import java.util.HashMap;

/**
 * Represent a logical device of type {@link HdmiDeviceInfo#DEVICE_AUDIO_SYSTEM} residing in Android
 * system.
@@ -60,16 +64,16 @@ 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;
    // If the current device uses TvInput for ARC. We assume all other inputs also use TvInput
    // when ARC is using TvInput.
    private boolean mArcIntentUsed = SystemProperties
            .get(Constants.PROPERTY_SYSTEM_AUDIO_DEVICE_ARC_PORT, "0").contains("tvinput");

    // 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;
    // Keeps the mapping (HDMI port ID to TV input URI) to keep track of the TV inputs ready to
    // accept input switching request from HDMI devices. Requests for which the corresponding
    // input ID is not yet registered by TV input framework need to be buffered for delayed
    // processing.
    private final HashMap<Integer, String> mTvInputs = new HashMap<>();

    protected HdmiCecLocalDeviceAudioSystem(HdmiControlService service) {
        super(service, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
@@ -81,6 +85,13 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource {
                Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED, true);
        mAutoTvOff = mService.readBooleanSetting(
                Global.HDMI_CONTROL_AUTO_TV_OFF_ENABLED, true);
        // TODO(amyjojo): make the map ro property.
        mTvInputs.put(Constants.CEC_SWITCH_HDMI1,
                "com.droidlogic.tvinput/.services.Hdmi1InputService/HW5");
        mTvInputs.put(Constants.CEC_SWITCH_HDMI2,
                "com.droidlogic.tvinput/.services.Hdmi2InputService/HW6");
        mTvInputs.put(Constants.CEC_SWITCH_HDMI3,
                "com.droidlogic.tvinput/.services.Hdmi3InputService/HW7");
    }

    @Override
@@ -595,4 +606,135 @@ 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 System Audio Control is enabled.
        if ((isSystemAudioActivated() || port >= 0) && mService.isPowerStandbyOrTransient()) {
            mService.wakeUp();
        }

        if (isSystemAudioActivated() && port < 0) {
            // If system audio mode is on and the new active source is not under the current device,
            // Will switch to ARC input.
            // TODO(b/115637145): handle system aduio without ARC
            routeToInputFromPortId(Constants.CEC_SWITCH_ARC);
        } else if (mIsSwitchDevice && port >= 0) {
            // If current device is a switch and the new active source is under it,
            // will switch to the corresponding active path.
            routeToInputFromPortId(port);
        }
    }

    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 && mService.isPlaybackDevice()) {
            switchToHomeTvInput();
        } else if (portId == Constants.CEC_SWITCH_ARC) {
            switchToTvInput(SystemProperties.get(Constants.PROPERTY_SYSTEM_AUDIO_DEVICE_ARC_PORT));
            return;
        } else {
            String uri = mTvInputs.get(portId);
            if (uri != null) {
                switchToTvInput(mTvInputs.get(portId));
            } else {
                HdmiLogger.debug("Port number does not match any Tv Input.");
                return;
            }
        }

        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);
    }

    @Override
    protected void handleRoutingChangeAndInformation(int physicalAddress, HdmiCecMessage message) {
        int port = getLocalPortFromPhysicalAddress(physicalAddress);
        // Routing change or information sent from switches under the current device can be ignored.
        if (port > 0) {
            return;
        }
        // When other switches route to some other devices not under the current device,
        // check system audio mode status and do ARC switch if needed.
        if (port < 0 && isSystemAudioActivated()) {
            handleRoutingChangeAndInformationForSystemAudio();
            return;
        }
        // When other switches route to the current device
        // and the current device is also a switch.
        if (port == 0) {
            handleRoutingChangeAndInformationForSwitch(message);
        }
    }

    // Handle the system audio(ARC) part of the logic on receiving routing change or information.
    private void handleRoutingChangeAndInformationForSystemAudio() {
        if (mService.isPowerStandbyOrTransient()) {
            mService.wakeUp();
        }
        // TODO(b/115637145): handle system aduio without ARC
        routeToInputFromPortId(Constants.CEC_SWITCH_ARC);
    }

    // Handle the routing control part of the logic on receiving routing change or information.
    private void handleRoutingChangeAndInformationForSwitch(HdmiCecMessage message) {
        if (mService.isPowerStandbyOrTransient()) {
            mService.wakeUp();
        }
        if (getLocalActivePort() == Constants.CEC_SWITCH_HOME && mService.isPlaybackDevice()) {
            routeToInputFromPortId(Constants.CEC_SWITCH_HOME);
            if (mService.playback() != null) {
                mService.playback().setAndBroadcastActiveSource(
                        message, mService.getPhysicalAddress());
            } else {
                setAndBroadcastActiveSource(message, mService.getPhysicalAddress());
            }
            return;
        }

        int routingInformationPath =
                getActivePathOnSwitchFromActivePortId(getLocalActivePort());
        // If current device is already the leaf of the whole HDMI system, will do nothing.
        if (routingInformationPath == mService.getPhysicalAddress()) {
            HdmiLogger.debug("Current device can't assign valid physical address"
                    + "to devices under it any more. "
                    + "It's physical address is " + routingInformationPath);
            return;
        }
        // Otherwise will switch to the current active port and broadcast routing information.
        mService.sendCecCommand(HdmiCecMessageBuilder.buildRoutingInformation(
                mAddress, routingInformationPath));
        routeToInputFromPortId(getLocalActivePort());
    }
}
+4 −2
Original line number Diff line number Diff line
@@ -266,7 +266,8 @@ final class HdmiCecLocalDevicePlayback extends HdmiCecLocalDeviceSource {
        setIsActiveSource(physicalAddress == mService.getPhysicalAddress());
    }

    private void wakeUpIfActiveSource() {
    @Override
    protected void wakeUpIfActiveSource() {
        if (!mIsActiveSource) {
            return;
        }
@@ -277,7 +278,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()));
Loading