blob: 0ba7773d4b720fc2b4858b7a09d4581eb878101c [file] [log] [blame]
Jinsuk Kimc70d2292014-04-30 15:43:16 +09001/*
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 */
16package com.android.server.hdmi;
17
Jinsuk Kimc70d2292014-04-30 15:43:16 +090018import android.hardware.hdmi.HdmiCecMessage;
19import android.os.Handler;
20import android.os.Looper;
21import android.os.Message;
22import android.util.Slog;
23
24import com.android.internal.annotations.VisibleForTesting;
25
26/**
27 * Encapsulates a sequence of CEC/MHL command exchange for a certain feature.
28 *
29 * <p>Many CEC/MHL features are accomplished by CEC devices on the bus exchanging
30 * more than one command. {@link FeatureAction} represents the life cycle of the communication,
31 * manages the state as the process progresses, and if necessary, returns the result
32 * to the caller which initiates the action, through the callback given at the creation
33 * of the object. All the actual action classes inherit FeatureAction.
34 *
35 * <p>More than one FeatureAction objects can be up and running simultaneously,
36 * maintained by {@link HdmiControlService}. Each action is passed a new command
37 * arriving from the bus, and either consumes it if the command is what the action expects,
38 * or yields it to other action.
39 *
40 * Declared as package private, accessed by {@link HdmiControlService} only.
41 */
42abstract class FeatureAction {
43
44 private static final String TAG = "FeatureAction";
45
46 // Timer handler message used for timeout event
47 protected static final int MSG_TIMEOUT = 100;
48
49 // Default timeout for the incoming command to arrive in response to a request
50 protected static final int TIMEOUT_MS = 1000;
51
52 // Default state used in common by all the feature actions.
53 protected static final int STATE_NONE = 0;
54
55 // Internal state indicating the progress of action.
56 protected int mState = STATE_NONE;
57
58 protected final HdmiControlService mService;
59
60 // Logical address of the device for which the feature action is taken. The commands
61 // generated in an action all use this field as source address.
62 protected final int mSourceAddress;
63
64 // Timer that manages timeout events.
65 protected ActionTimer mActionTimer;
66
67 FeatureAction(HdmiControlService service, int sourceAddress) {
68 mService = service;
69 mSourceAddress = sourceAddress;
70 mActionTimer = createActionTimer(service.getServiceLooper());
71 }
72
73 @VisibleForTesting
74 void setActionTimer(ActionTimer actionTimer) {
75 mActionTimer = actionTimer;
76 }
77
78 /**
79 * Called right after the action is created. Initialization or first step to take
80 * for the action can be done in this method.
81 *
82 * @return true if the operation is successful; otherwise false.
83 */
84 abstract boolean start();
85
86 /**
87 * Process the command. Called whenever a new command arrives.
88 *
89 * @param cmd command to process
90 * @return true if the command was consumed in the process; Otherwise false, which
91 * indicates that the command shall be handled by other actions.
92 */
93 abstract boolean processCommand(HdmiCecMessage cmd);
94
95 /**
96 * Called when the action should handle the timer event it created before.
97 *
98 * <p>CEC standard mandates each command transmission should be responded within
99 * certain period of time. The method is called when the timer it created as it transmitted
100 * a command gets expired. Inner logic should take an appropriate action.
101 *
102 * @param state the state associated with the time when the timer was created
103 */
104 abstract void handleTimerEvent(int state);
105
106 /**
107 * Timer handler interface used for FeatureAction classes.
108 */
109 interface ActionTimer {
110 /**
111 * Send a timer message.
112 *
113 * Also carries the state of the action when the timer is created. Later this state is
114 * compared to the one the action is in when it receives the timer to let the action tell
115 * the right timer to handle.
116 *
117 * @param state state of the action is in
118 * @param delayMillis amount of delay for the timer
119 */
120 void sendTimerMessage(int state, long delayMillis);
Jungshik Jang67ea5212014-05-15 14:05:24 +0900121
122 /**
123 * Removes any pending timer message.
124 */
125 void clearTimerMessage();
Jinsuk Kimc70d2292014-04-30 15:43:16 +0900126 }
127
128 private class ActionTimerHandler extends Handler implements ActionTimer {
129
130 public ActionTimerHandler(Looper looper) {
131 super(looper);
132 }
133
134 @Override
135 public void sendTimerMessage(int state, long delayMillis) {
Jinsuk Kimb0674f02014-05-28 17:42:56 +0900136 // The third argument(0) is not used.
137 sendMessageDelayed(obtainMessage(MSG_TIMEOUT, state, 0), delayMillis);
Jinsuk Kimc70d2292014-04-30 15:43:16 +0900138 }
139
140 @Override
Jungshik Jang67ea5212014-05-15 14:05:24 +0900141 public void clearTimerMessage() {
142 removeMessages(MSG_TIMEOUT);
143 }
144
145 @Override
Jinsuk Kimc70d2292014-04-30 15:43:16 +0900146 public void handleMessage(Message msg) {
147 switch (msg.what) {
148 case MSG_TIMEOUT:
149 handleTimerEvent(msg.arg1);
150 break;
151 default:
152 Slog.w(TAG, "Unsupported message:" + msg.what);
153 break;
154 }
155 }
156 }
157
158 private ActionTimer createActionTimer(Looper looper) {
159 return new ActionTimerHandler(looper);
160 }
161
162 // Add a new timer. The timer event will come to mActionTimer.handleMessage() in
163 // delayMillis.
164 protected void addTimer(int state, int delayMillis) {
165 mActionTimer.sendTimerMessage(state, delayMillis);
166 }
167
Jungshik Jangd643f762014-05-22 19:28:09 +0900168 protected final void sendCommand(HdmiCecMessage cmd) {
169 mService.sendCecCommand(cmd);
170 }
171
172 protected final void sendCommand(HdmiCecMessage cmd,
173 HdmiControlService.SendMessageCallback callback) {
174 mService.sendCecCommand(cmd, callback);
Jungshik Jang67ea5212014-05-15 14:05:24 +0900175 }
176
177 /**
178 * Clean up action's state.
179 *
180 * <p>Declared as package-private. Only {@link HdmiControlService} can access it.
181 */
182 void clear() {
183 mState = STATE_NONE;
184 // Clear all timers.
185 mActionTimer.clearTimerMessage();
Jinsuk Kimc70d2292014-04-30 15:43:16 +0900186 }
187
Jinsuk Kimc70d2292014-04-30 15:43:16 +0900188 /**
189 * Finish up the action. Reset the state, and remove itself from the action queue.
190 */
191 protected void finish() {
Jungshik Jang67ea5212014-05-15 14:05:24 +0900192 clear();
Jinsuk Kimc70d2292014-04-30 15:43:16 +0900193 removeAction(this);
194 }
195
196 /**
197 * Remove the action from the action queue. This is called after the action finishes
198 * its role.
199 *
200 * @param action
201 */
202 private void removeAction(FeatureAction action) {
203 mService.removeAction(action);
204 }
Jinsuk Kimc70d2292014-04-30 15:43:16 +0900205}