NewDeviceAction.java revision 97affee67b6d88da40af41b36f02ecb2b823daff
1a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich/*
2a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich * Copyright (C) 2014 The Android Open Source Project
3a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich *
4a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich * Licensed under the Apache License, Version 2.0 (the "License");
5a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich * you may not use this file except in compliance with the License.
6a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich * You may obtain a copy of the License at
7a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich *
8a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich *      http://www.apache.org/licenses/LICENSE-2.0
9a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich *
10a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich * Unless required by applicable law or agreed to in writing, software
11a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich * distributed under the License is distributed on an "AS IS" BASIS,
12a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich * See the License for the specific language governing permissions and
14a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich * limitations under the License.
15a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich */
16a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevichpackage com.android.server.hdmi;
17a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich
18a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevichimport android.hardware.hdmi.HdmiCecDeviceInfo;
19a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevichimport android.util.Slog;
20a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich
21a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevichimport java.io.UnsupportedEncodingException;
22a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich
23a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich/**
24a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich * Feature action that discovers the information of a newly found logical device.
25a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich *
26a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich * This action is created when receiving <Report Physical Address>, a CEC command a newly
2716928bfeca8858a0acae6942fc68c14a040b92ffRomain Guy * connected HDMI-CEC device broadcasts to announce its advent. Additional commands are issued in
2816928bfeca8858a0acae6942fc68c14a040b92ffRomain Guy * this action to gather more information on the device such as OSD name and device vendor ID.
2916928bfeca8858a0acae6942fc68c14a040b92ffRomain Guy *
3016928bfeca8858a0acae6942fc68c14a040b92ffRomain Guy * <p>The result is made in the form of {@link HdmiCecDeviceInfo} object, and passed to service
3116928bfeca8858a0acae6942fc68c14a040b92ffRomain Guy * for the management through its life cycle.
321cadb25da1ed875bdd078270e642966724a0c39aMathias Agopian *
33a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich * <p>Package-private, accessed by {@link HdmiControlService} only.
34a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich */
35a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevichfinal class NewDeviceAction extends FeatureAction {
36a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich
37a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich    private static final String TAG = "NewDeviceAction";
38a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich
39a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich    // State in which the action sent <Give OSD Name> and is waiting for <Set OSD Name>
404774338bd0ad1ebe42c311fd0c72f13786b5c800Jesse Hall    // that contains the name of the device for display on screen.
414774338bd0ad1ebe42c311fd0c72f13786b5c800Jesse Hall    static final int STATE_WAITING_FOR_SET_OSD_NAME = 1;
42a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich
43a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich    // State in which the action sent <Give Device Vendor ID> and is waiting for
44a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich    // <Device Vendor ID> that contains the vendor ID of the device.
45a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich    static final int STATE_WAITING_FOR_DEVICE_VENDOR_ID = 2;
46a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich
47a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich    private final int mDeviceLogicalAddress;
48a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich    private final int mDevicePhysicalAddress;
49a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich
50a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich    private int mVendorId;
51a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich    private String mDisplayName;
52a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich
53a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich    /**
54a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich     * Constructor.
55a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich     *
56a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich     * @param source {@link HdmiCecLocalDevice} instance
57a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich     * @param deviceLogicalAddress logical address of the device in interest
58a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich     * @param devicePhysicalAddress physical address of the device in interest
59a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich     */
60a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich    NewDeviceAction(HdmiCecLocalDevice source, int deviceLogicalAddress,
61a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich            int devicePhysicalAddress) {
62a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich        super(source);
63a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich        mDeviceLogicalAddress = deviceLogicalAddress;
64a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich        mDevicePhysicalAddress = devicePhysicalAddress;
65a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich        mVendorId = Constants.UNKNOWN_VENDOR_ID;
66a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich    }
67a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich
68a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich    @Override
696132b3703da76389e81d26b0023846a78b008603Jack Palevich    public boolean start() {
706132b3703da76389e81d26b0023846a78b008603Jack Palevich        mState = STATE_WAITING_FOR_SET_OSD_NAME;
716132b3703da76389e81d26b0023846a78b008603Jack Palevich        if (mayProcessCommandIfCached(mDeviceLogicalAddress, Constants.MESSAGE_SET_OSD_NAME)) {
726132b3703da76389e81d26b0023846a78b008603Jack Palevich            return true;
73a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich        }
74a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich
75a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich        sendCommand(HdmiCecMessageBuilder.buildGiveOsdNameCommand(getSourceAddress(),
76a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich                mDeviceLogicalAddress));
77a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich        addTimer(mState, HdmiConfig.TIMEOUT_MS);
78a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich        return true;
796132b3703da76389e81d26b0023846a78b008603Jack Palevich    }
806132b3703da76389e81d26b0023846a78b008603Jack Palevich
816132b3703da76389e81d26b0023846a78b008603Jack Palevich    @Override
826132b3703da76389e81d26b0023846a78b008603Jack Palevich    public boolean processCommand(HdmiCecMessage cmd) {
836132b3703da76389e81d26b0023846a78b008603Jack Palevich        // For the logical device in interest, we want two more pieces of information -
846132b3703da76389e81d26b0023846a78b008603Jack Palevich        // osd name and vendor id. They are requested in sequence. In case we don't
856132b3703da76389e81d26b0023846a78b008603Jack Palevich        // get the expected responses (either by timeout or by receiving <feature abort> command),
866132b3703da76389e81d26b0023846a78b008603Jack Palevich        // set them to a default osd name and unknown vendor id respectively.
876132b3703da76389e81d26b0023846a78b008603Jack Palevich        int opcode = cmd.getOpcode();
886132b3703da76389e81d26b0023846a78b008603Jack Palevich        int src = cmd.getSource();
896132b3703da76389e81d26b0023846a78b008603Jack Palevich        byte[] params = cmd.getParams();
906132b3703da76389e81d26b0023846a78b008603Jack Palevich
916132b3703da76389e81d26b0023846a78b008603Jack Palevich        if (mDeviceLogicalAddress != src) {
926132b3703da76389e81d26b0023846a78b008603Jack Palevich            return false;
936132b3703da76389e81d26b0023846a78b008603Jack Palevich        }
946132b3703da76389e81d26b0023846a78b008603Jack Palevich
956132b3703da76389e81d26b0023846a78b008603Jack Palevich        if (mState == STATE_WAITING_FOR_SET_OSD_NAME) {
966132b3703da76389e81d26b0023846a78b008603Jack Palevich            if (opcode == Constants.MESSAGE_SET_OSD_NAME) {
976132b3703da76389e81d26b0023846a78b008603Jack Palevich                try {
986132b3703da76389e81d26b0023846a78b008603Jack Palevich                    mDisplayName = new String(params, "US-ASCII");
996132b3703da76389e81d26b0023846a78b008603Jack Palevich                } catch (UnsupportedEncodingException e) {
1006132b3703da76389e81d26b0023846a78b008603Jack Palevich                    Slog.e(TAG, "Failed to get OSD name: " + e.getMessage());
101a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich                }
102a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich                requestVendorId();
103a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich                return true;
1049d4536835248525f32f1504a3d28d5bbfa0a2910Steve Block            } else if (opcode == Constants.MESSAGE_FEATURE_ABORT) {
105a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich                int requestOpcode = params[1] & 0xFF;
106a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich                if (requestOpcode == Constants.MESSAGE_SET_OSD_NAME) {
107a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich                    requestVendorId();
108a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich                    return true;
109a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich                }
1109d4536835248525f32f1504a3d28d5bbfa0a2910Steve Block            }
111a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich        } else if (mState == STATE_WAITING_FOR_DEVICE_VENDOR_ID) {
1129d4536835248525f32f1504a3d28d5bbfa0a2910Steve Block            if (opcode == Constants.MESSAGE_DEVICE_VENDOR_ID) {
113a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich                mVendorId = HdmiUtils.threeBytesToInt(params);
114a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich                addDeviceInfo();
1159d4536835248525f32f1504a3d28d5bbfa0a2910Steve Block                finish();
116a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich                return true;
1179d4536835248525f32f1504a3d28d5bbfa0a2910Steve Block            } else if (opcode == Constants.MESSAGE_FEATURE_ABORT) {
118a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich                int requestOpcode = params[1] & 0xFF;
119a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich                if (requestOpcode == Constants.MESSAGE_DEVICE_VENDOR_ID) {
120a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich                    addDeviceInfo();
1219d4536835248525f32f1504a3d28d5bbfa0a2910Steve Block                    finish();
122a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich                    return true;
1239d4536835248525f32f1504a3d28d5bbfa0a2910Steve Block                }
1249d4536835248525f32f1504a3d28d5bbfa0a2910Steve Block            }
125a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich        }
126a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich        return false;
1279d4536835248525f32f1504a3d28d5bbfa0a2910Steve Block    }
128a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich
129a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich    private boolean mayProcessCommandIfCached(int destAddress, int opcode) {
130a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich        HdmiCecMessage message = getCecMessageCache().getMessage(destAddress, opcode);
131a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich        if (message != null) {
1326132b3703da76389e81d26b0023846a78b008603Jack Palevich            return processCommand(message);
1336132b3703da76389e81d26b0023846a78b008603Jack Palevich        }
1346132b3703da76389e81d26b0023846a78b008603Jack Palevich        return false;
1356132b3703da76389e81d26b0023846a78b008603Jack Palevich    }
1366132b3703da76389e81d26b0023846a78b008603Jack Palevich
1376132b3703da76389e81d26b0023846a78b008603Jack Palevich    private void requestVendorId() {
1389d4536835248525f32f1504a3d28d5bbfa0a2910Steve Block        // At first, transit to waiting status for <Device Vendor Id>.
1396132b3703da76389e81d26b0023846a78b008603Jack Palevich        mState = STATE_WAITING_FOR_DEVICE_VENDOR_ID;
1406132b3703da76389e81d26b0023846a78b008603Jack Palevich        // If the message is already in cache, process it.
1416132b3703da76389e81d26b0023846a78b008603Jack Palevich        if (mayProcessCommandIfCached(mDeviceLogicalAddress,
1426132b3703da76389e81d26b0023846a78b008603Jack Palevich                Constants.MESSAGE_DEVICE_VENDOR_ID)) {
1436132b3703da76389e81d26b0023846a78b008603Jack Palevich            return;
1446132b3703da76389e81d26b0023846a78b008603Jack Palevich        }
1456132b3703da76389e81d26b0023846a78b008603Jack Palevich        sendCommand(HdmiCecMessageBuilder.buildGiveDeviceVendorIdCommand(getSourceAddress(),
1466132b3703da76389e81d26b0023846a78b008603Jack Palevich                mDeviceLogicalAddress));
1476132b3703da76389e81d26b0023846a78b008603Jack Palevich        addTimer(mState, HdmiConfig.TIMEOUT_MS);
1486132b3703da76389e81d26b0023846a78b008603Jack Palevich    }
1496132b3703da76389e81d26b0023846a78b008603Jack Palevich
1506132b3703da76389e81d26b0023846a78b008603Jack Palevich    private void addDeviceInfo() {
1516132b3703da76389e81d26b0023846a78b008603Jack Palevich        if (mDisplayName == null) {
1526132b3703da76389e81d26b0023846a78b008603Jack Palevich            mDisplayName = HdmiUtils.getDefaultDeviceName(mDeviceLogicalAddress);
1536132b3703da76389e81d26b0023846a78b008603Jack Palevich        }
1546132b3703da76389e81d26b0023846a78b008603Jack Palevich        tv().addCecDevice(new HdmiCecDeviceInfo(
1556132b3703da76389e81d26b0023846a78b008603Jack Palevich                mDeviceLogicalAddress, mDevicePhysicalAddress,
1566132b3703da76389e81d26b0023846a78b008603Jack Palevich                HdmiUtils.getTypeFromAddress(mDeviceLogicalAddress),
1576132b3703da76389e81d26b0023846a78b008603Jack Palevich                mVendorId, mDisplayName));
1586132b3703da76389e81d26b0023846a78b008603Jack Palevich
1599d4536835248525f32f1504a3d28d5bbfa0a2910Steve Block        if (HdmiUtils.getTypeFromAddress(mDeviceLogicalAddress)
1606132b3703da76389e81d26b0023846a78b008603Jack Palevich                == HdmiCecDeviceInfo.DEVICE_AUDIO_SYSTEM) {
1616132b3703da76389e81d26b0023846a78b008603Jack Palevich            if (tv().getSystemAudioMode()) {
1629d4536835248525f32f1504a3d28d5bbfa0a2910Steve Block                addAndStartAction(new SystemAudioAutoInitiationAction(localDevice(),
1636132b3703da76389e81d26b0023846a78b008603Jack Palevich                        mDeviceLogicalAddress));
1646132b3703da76389e81d26b0023846a78b008603Jack Palevich            }
1659d4536835248525f32f1504a3d28d5bbfa0a2910Steve Block
1666132b3703da76389e81d26b0023846a78b008603Jack Palevich            if (shouldTryArcInitiation()) {
1676132b3703da76389e81d26b0023846a78b008603Jack Palevich                addAndStartAction(new RequestArcInitiationAction(localDevice(),
1686132b3703da76389e81d26b0023846a78b008603Jack Palevich                        mDeviceLogicalAddress));
1696132b3703da76389e81d26b0023846a78b008603Jack Palevich            }
1706132b3703da76389e81d26b0023846a78b008603Jack Palevich        }
1719d4536835248525f32f1504a3d28d5bbfa0a2910Steve Block    }
1726132b3703da76389e81d26b0023846a78b008603Jack Palevich
1736132b3703da76389e81d26b0023846a78b008603Jack Palevich    private boolean shouldTryArcInitiation() {
1746132b3703da76389e81d26b0023846a78b008603Jack Palevich        return tv().isConnectedToArcPort(mDevicePhysicalAddress) && tv().isArcFeatureEnabled();
1756132b3703da76389e81d26b0023846a78b008603Jack Palevich    }
1766132b3703da76389e81d26b0023846a78b008603Jack Palevich
1779d4536835248525f32f1504a3d28d5bbfa0a2910Steve Block    @Override
1786132b3703da76389e81d26b0023846a78b008603Jack Palevich    public void handleTimerEvent(int state) {
1796132b3703da76389e81d26b0023846a78b008603Jack Palevich        if (mState == STATE_NONE || mState != state) {
1806132b3703da76389e81d26b0023846a78b008603Jack Palevich            return;
181a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich        }
182a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich        if (state == STATE_WAITING_FOR_SET_OSD_NAME) {
183a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich            // Osd name request timed out. Try vendor id
1846132b3703da76389e81d26b0023846a78b008603Jack Palevich            requestVendorId();
1856132b3703da76389e81d26b0023846a78b008603Jack Palevich        } else if (state == STATE_WAITING_FOR_DEVICE_VENDOR_ID) {
1866132b3703da76389e81d26b0023846a78b008603Jack Palevich            // vendor id timed out. Go ahead creating the device info what we've got so far.
1876132b3703da76389e81d26b0023846a78b008603Jack Palevich            addDeviceInfo();
188a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich            finish();
189a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich        }
190a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich    }
191a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich
192a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich    boolean isActionOf(int address, int path) {
193a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich        return (mDeviceLogicalAddress == address) && (mDevicePhysicalAddress == path);
194a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich    }
195a2dd6cf59962e3a21a47df29b2f243e904839ba7Jack Palevich}
1966132b3703da76389e81d26b0023846a78b008603Jack Palevich