HdmiCecStandbyModeHandler.java revision 25c20298ad04e0e591e0cfdc0bb9d01a985433ab
1/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.hdmi;
18
19import android.util.SparseArray;
20
21/**
22 * This class handles the incoming messages when HdmiCecService is in the standby mode.
23 */
24public final class HdmiCecStandbyModeHandler {
25
26    private interface CecMessageHandler {
27        boolean handle(HdmiCecMessage message);
28    }
29
30    private static final class Bystander implements CecMessageHandler {
31        @Override
32        public boolean handle(HdmiCecMessage message) {
33            return true;
34        }
35    }
36
37    private static final class Bypasser implements CecMessageHandler {
38        @Override
39        public boolean handle(HdmiCecMessage message) {
40            return false;
41        }
42    }
43
44    private final class Aborter implements CecMessageHandler {
45        private final int mReason;
46        public Aborter(int reason) {
47            mReason = reason;
48        }
49        @Override
50        public boolean handle(HdmiCecMessage message) {
51            int src = message.getSource();
52            int dest = message.getDestination();
53            if (src == Constants.ADDR_BROADCAST || dest == Constants.ADDR_BROADCAST) {
54                // Do not send <Feature Abort> on the message from the unassigned device
55                // or the broadcasted message.
56                return true;
57            }
58            HdmiCecMessage cecMessage = HdmiCecMessageBuilder.buildFeatureAbortCommand(
59                    dest, src, message.getOpcode(), mReason);
60            mService.sendCecCommand(cecMessage);
61            return true;
62        }
63    }
64
65    private final class AutoOnHandler implements CecMessageHandler {
66        @Override
67        public boolean handle(HdmiCecMessage message) {
68            if (!mTv.getAutoWakeup()) {
69                mAborterRefused.handle(message);
70                return true;
71            }
72            return false;
73        }
74    }
75
76    private final class UserControlProcessedHandler implements CecMessageHandler {
77        @Override
78        public boolean handle(HdmiCecMessage message) {
79            // The power status here is always standby.
80            if (HdmiCecLocalDevice.isPowerOnOrToggleCommand(message)) {
81                return false;
82            } else if (HdmiCecLocalDevice.isPowerOffOrToggleCommand(message)) {
83                return true;
84            }
85            return mAborterIncorrectMode.handle(message);
86        }
87    }
88
89    private final HdmiControlService mService;
90    private final HdmiCecLocalDeviceTv mTv;
91
92    private final SparseArray<CecMessageHandler> mCecMessageHandlers = new SparseArray<>();
93    private final CecMessageHandler mDefaultHandler = new Aborter(
94            Constants.ABORT_UNRECOGNIZED_OPCODE);
95    private final CecMessageHandler mAborterIncorrectMode = new Aborter(
96            Constants.ABORT_NOT_IN_CORRECT_MODE);
97    private final CecMessageHandler mAborterRefused = new Aborter(Constants.ABORT_REFUSED);
98    private final CecMessageHandler mAutoOnHandler = new AutoOnHandler();
99    private final CecMessageHandler mBypasser = new Bypasser();
100    private final CecMessageHandler mBystander = new Bystander();
101    private final UserControlProcessedHandler
102            mUserControlProcessedHandler = new UserControlProcessedHandler();
103
104    public HdmiCecStandbyModeHandler(HdmiControlService service, HdmiCecLocalDeviceTv tv) {
105        mService = service;
106        mTv = tv;
107
108        addHandler(Constants.MESSAGE_IMAGE_VIEW_ON, mAutoOnHandler);
109        addHandler(Constants.MESSAGE_TEXT_VIEW_ON, mAutoOnHandler);
110
111        addHandler(Constants.MESSAGE_ACTIVE_SOURCE, mBystander);
112        addHandler(Constants.MESSAGE_REQUEST_ACTIVE_SOURCE, mBystander);
113        addHandler(Constants.MESSAGE_ROUTING_CHANGE, mBystander);
114        addHandler(Constants.MESSAGE_ROUTING_INFORMATION, mBystander);
115        addHandler(Constants.MESSAGE_SET_STREAM_PATH, mBystander);
116        addHandler(Constants.MESSAGE_STANDBY, mBystander);
117        addHandler(Constants.MESSAGE_SET_MENU_LANGUAGE, mBystander);
118        addHandler(Constants.MESSAGE_DEVICE_VENDOR_ID, mBystander);
119        addHandler(Constants.MESSAGE_USER_CONTROL_RELEASED, mBystander);
120        addHandler(Constants.MESSAGE_REPORT_POWER_STATUS, mBystander);
121        addHandler(Constants.MESSAGE_FEATURE_ABORT, mBystander);
122        addHandler(Constants.MESSAGE_INACTIVE_SOURCE, mBystander);
123        addHandler(Constants.MESSAGE_SYSTEM_AUDIO_MODE_STATUS, mBystander);
124        addHandler(Constants.MESSAGE_REPORT_AUDIO_STATUS, mBystander);
125
126        // If TV supports the following messages during power-on, ignore them and do nothing,
127        // else reply with <Feature Abort>["Unrecognized Opcode"]
128        // <Deck Status>, <Tuner Device Status>, <Tuner Cleared Status>, <Timer Status>
129        addHandler(Constants.MESSAGE_RECORD_STATUS, mBystander);
130
131        // If TV supports the following messages during power-on, reply with <Feature Abort>["Not
132        // in correct mode to respond"], else reply with <Feature Abort>["Unrecognized Opcode"]
133        // <Give Tuner Device Status>, <Select Digital Service>, <Tuner Step Decrement>,
134        // <Tuner Stem Increment>, <Menu Status>.
135        addHandler(Constants.MESSAGE_RECORD_TV_SCREEN, mAborterIncorrectMode);
136        addHandler(Constants.MESSAGE_INITIATE_ARC, mAborterIncorrectMode);
137        addHandler(Constants.MESSAGE_TERMINATE_ARC, mAborterIncorrectMode);
138
139        addHandler(Constants.MESSAGE_GIVE_PHYSICAL_ADDRESS, mBypasser);
140        addHandler(Constants.MESSAGE_GET_MENU_LANGUAGE, mBypasser);
141        addHandler(Constants.MESSAGE_REPORT_PHYSICAL_ADDRESS, mBypasser);
142        addHandler(Constants.MESSAGE_GIVE_DEVICE_VENDOR_ID, mBypasser);
143        addHandler(Constants.MESSAGE_GIVE_OSD_NAME, mBypasser);
144        addHandler(Constants.MESSAGE_SET_OSD_NAME, mBypasser);
145
146        addHandler(Constants.MESSAGE_USER_CONTROL_PRESSED, mUserControlProcessedHandler);
147
148        addHandler(Constants.MESSAGE_GIVE_DEVICE_POWER_STATUS, mBypasser);
149        addHandler(Constants.MESSAGE_ABORT, mBypasser);
150        addHandler(Constants.MESSAGE_GET_CEC_VERSION, mBypasser);
151
152        addHandler(Constants.MESSAGE_VENDOR_COMMAND_WITH_ID, mAborterIncorrectMode);
153        addHandler(Constants.MESSAGE_SET_SYSTEM_AUDIO_MODE, mAborterIncorrectMode);
154    }
155
156    private void addHandler(int opcode, CecMessageHandler handler) {
157        mCecMessageHandlers.put(opcode, handler);
158    }
159
160    /**
161     * Handles the CEC message in the standby mode.
162     *
163     * @param message {@link HdmiCecMessage} to be processed
164     * @return true if the message is handled in the handler, false means that the message is need
165     *         to be dispatched to the local device.
166     */
167    boolean handleCommand(HdmiCecMessage message) {
168        CecMessageHandler handler = mCecMessageHandlers.get(message.getOpcode());
169        if (handler != null) {
170            return handler.handle(message);
171        }
172        return mDefaultHandler.handle(message);
173    }
174}
175