NewDeviceAction.java revision c70d2295dd3fb87ce8c81c704688d1ad05043b4d
194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood/*
294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood * Copyright (C) 2014 The Android Open Source Project
394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood *
494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood * Licensed under the Apache License, Version 2.0 (the "License");
594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood * you may not use this file except in compliance with the License.
694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood * You may obtain a copy of the License at
794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood *
894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood *      http://www.apache.org/licenses/LICENSE-2.0
994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood *
1094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood * Unless required by applicable law or agreed to in writing, software
1194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood * distributed under the License is distributed on an "AS IS" BASIS,
1294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood * See the License for the specific language governing permissions and
1494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood * limitations under the License.
15399b6c3bbc0d887ab016a8bb686ff16d36edc6c8Arve Hjønnevåg */
169b738bb4110926b85da65d36b2e6f1a50199ec4cSerban Constantinescupackage com.android.server.hdmi;
179b738bb4110926b85da65d36b2e6f1a50199ec4cSerban Constantinescu
1894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwoodimport android.hardware.hdmi.HdmiCec;
1994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwoodimport android.hardware.hdmi.HdmiCecDeviceInfo;
20399b6c3bbc0d887ab016a8bb686ff16d36edc6c8Arve Hjønnevågimport android.hardware.hdmi.HdmiCecMessage;
2194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwoodimport android.util.Slog;
2294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
2394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwoodimport java.io.UnsupportedEncodingException;
2494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
2594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood/**
2694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood * Feature action that discovers the information of a newly found logical device.
2794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood *
289b738bb4110926b85da65d36b2e6f1a50199ec4cSerban Constantinescu * This action is created when receiving <Report Physical Address>, a CEC command a newly
2994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood * connected HDMI-CEC device broadcasts to announce its advent. Additional commands are issued in
305fb1b8836aa5cf0f38b49bc7bfb8343b84fdf9bfSerban Constantinescu * this action to gather more information on the device such as OSD name and device vendor ID.
315fb1b8836aa5cf0f38b49bc7bfb8343b84fdf9bfSerban Constantinescu *
3294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood * <p>The result is made in the form of {@link HdmiCecDeviceInfo} object, and passed to service
3394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood * for the management through its life cycle.
3494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood *
3594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood * <p>Package-private, accessed by {@link HdmiControlService} only.
36e5245cbf5d4e830cf605ef07f5d284d7c5d2867eArve Hjønnevåg */
37e5245cbf5d4e830cf605ef07f5d284d7c5d2867eArve Hjønnevågfinal class NewDeviceAction extends FeatureAction {
3894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
3994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    private static final String TAG = "NewDeviceAction";
4094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
4194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    // State in which the action sent <Give OSD Name> and is waiting for <Set OSD Name>
4294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    // that contains the name of the device for display on screen.
4394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    static final int STATE_WAITING_FOR_SET_OSD_NAME = 1;
4494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
45bcf38880c65297da58194eb0c0ce8d6e2bab7d94Serban Constantinescu    // State in which the action sent <Give Device Vendor ID> and is waiting for
4694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    // <Device Vendor ID> that contains the vendor ID of the device.
4794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    static final int STATE_WAITING_FOR_DEVICE_VENDOR_ID = 2;
4894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
499b738bb4110926b85da65d36b2e6f1a50199ec4cSerban Constantinescu    private final int mDeviceLogicalAddress;
5094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    private final int mDevicePhysicalAddress;
5194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
5294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    private int mVendorId;
5394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    private String mDisplayName;
5494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
5594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    /**
5694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood     * Constructor.
575fb1b8836aa5cf0f38b49bc7bfb8343b84fdf9bfSerban Constantinescu     *
5894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood     * @param service {@link HdmiControlService} instance
5994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood     * @param sourceAddress logical address to be used as source address
6094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood     * @param deviceLogicalAddress logical address of the device in interest
6194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood     * @param devicePhysicalAddress physical address of the device in interest
6294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood     */
6394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    NewDeviceAction(HdmiControlService service, int sourceAddress, int deviceLogicalAddress,
6494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            int devicePhysicalAddress) {
6594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        super(service, sourceAddress);
6694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        mDeviceLogicalAddress = deviceLogicalAddress;
6794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        mDevicePhysicalAddress = devicePhysicalAddress;
685fb1b8836aa5cf0f38b49bc7bfb8343b84fdf9bfSerban Constantinescu        mVendorId = HdmiCec.UNKNOWN_VENDOR_ID;
695fb1b8836aa5cf0f38b49bc7bfb8343b84fdf9bfSerban Constantinescu    }
7094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
715fb1b8836aa5cf0f38b49bc7bfb8343b84fdf9bfSerban Constantinescu    @Override
7294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    public boolean start() {
7394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        sendCommand(
7494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                buildCommand(mSourceAddress, mDeviceLogicalAddress, HdmiCec.MESSAGE_GET_OSD_NAME));
7594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        mState = STATE_WAITING_FOR_SET_OSD_NAME;
7694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        addTimer(mState, TIMEOUT_MS);
7794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        return true;
7894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    }
7994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
8094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    @Override
8194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    public boolean processCommand(HdmiCecMessage cmd) {
829b738bb4110926b85da65d36b2e6f1a50199ec4cSerban Constantinescu        // For the logical device in interest, we want two more pieces of information -
8394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        // osd name and vendor id. They are requested in sequence. In case we don't
8494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        // get the expected responses (either by timeout or by receiving <feature abort> command),
855fb1b8836aa5cf0f38b49bc7bfb8343b84fdf9bfSerban Constantinescu        // set them to a default osd name and unknown vendor id respectively.
8694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        int opcode = cmd.getOpcode();
8794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        int src = cmd.getSource();
8894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        byte[] params = cmd.getParams();
8994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
9094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        if (mDeviceLogicalAddress != src) {
919b738bb4110926b85da65d36b2e6f1a50199ec4cSerban Constantinescu            return false;
925fb1b8836aa5cf0f38b49bc7bfb8343b84fdf9bfSerban Constantinescu        }
9394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
9494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        if (mState == STATE_WAITING_FOR_SET_OSD_NAME) {
95            if (opcode == HdmiCec.MESSAGE_SET_OSD_NAME) {
96                try {
97                    mDisplayName = new String(params, "US-ASCII");
98                } catch (UnsupportedEncodingException e) {
99                    Slog.e(TAG, "Failed to get OSD name: " + e.getMessage());
100                }
101                mState = STATE_WAITING_FOR_DEVICE_VENDOR_ID;
102                requestVendorId();
103                return true;
104            } else if (opcode == HdmiCec.MESSAGE_FEATURE_ABORT) {
105                int requestOpcode = params[1];
106                if (requestOpcode == HdmiCec.MESSAGE_SET_OSD_NAME) {
107                    mState = STATE_WAITING_FOR_DEVICE_VENDOR_ID;
108                    requestVendorId();
109                    return true;
110                }
111            }
112        } else if (mState == STATE_WAITING_FOR_DEVICE_VENDOR_ID) {
113            if (opcode == HdmiCec.MESSAGE_DEVICE_VENDOR_ID) {
114                if (params.length == 3) {
115                    mVendorId = (params[0] << 16) + (params[1] << 8) + params[2];
116                } else {
117                    Slog.e(TAG, "Failed to get device vendor ID: ");
118                }
119                addDeviceInfo();
120                finish();
121                return true;
122            } else if (opcode == HdmiCec.MESSAGE_FEATURE_ABORT) {
123                int requestOpcode = params[1];
124                if (requestOpcode == HdmiCec.MESSAGE_DEVICE_VENDOR_ID) {
125                    addDeviceInfo();
126                    finish();
127                    return true;
128                }
129            }
130        }
131        return false;
132    }
133
134    private void requestVendorId() {
135        sendCommand(buildCommand(mSourceAddress, mDeviceLogicalAddress,
136                HdmiCec.MESSAGE_GIVE_DEVICE_VENDOR_ID));
137        addTimer(mState, TIMEOUT_MS);
138    }
139
140    private void addDeviceInfo() {
141        if (mDisplayName == null) {
142            mDisplayName = HdmiCec.getDefaultDeviceName(mDeviceLogicalAddress);
143        }
144        mService.addDeviceInfo(new HdmiCecDeviceInfo(
145                mDeviceLogicalAddress, mDevicePhysicalAddress,
146                HdmiCec.getTypeFromAddress(mDeviceLogicalAddress),
147                mVendorId, mDisplayName));
148    }
149
150    @Override
151    public void handleTimerEvent(int state) {
152        if (mState == STATE_NONE || mState != state) {
153            return;
154        }
155        if (state == STATE_WAITING_FOR_SET_OSD_NAME) {
156            // Osd name request timed out. Try vendor id
157            mState = STATE_WAITING_FOR_DEVICE_VENDOR_ID;
158            requestVendorId();
159        } else if (state == STATE_WAITING_FOR_DEVICE_VENDOR_ID) {
160            // vendor id timed out. Go ahead creating the device info what we've got so far.
161            addDeviceInfo();
162            finish();
163        }
164    }
165}
166