blob: baae1d99f9fc35c7654ac8ebb7098252a2314ccf [file] [log] [blame]
Jinsuk Kim4f512fb2014-02-28 17:41:17 +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 */
16
17package com.android.server.hdmi;
18
19import android.hardware.hdmi.HdmiCec;
20import android.hardware.hdmi.HdmiCecMessage;
Jinsuk Kim4f512fb2014-02-28 17:41:17 +090021import android.hardware.hdmi.IHdmiCecListener;
22import android.os.Binder;
23import android.os.RemoteException;
24import android.util.Log;
25
26import java.util.ArrayList;
27import java.util.List;
28
29/**
Jinsuk Kim4e90fcd2014-03-24 18:02:29 +090030 * HdmiCecDevice class represents a CEC logical device characterized
31 * by its device type. It is a superclass of those serving concrete device type.
32 * Currently we're interested in playback(one of sources), display(sink) device type
33 * only. The support for the other types like recorder, audio system will come later.
34 *
35 * <p>A physical device can contain the functions of
Jinsuk Kim4f512fb2014-02-28 17:41:17 +090036 * more than one logical device, in which case it should create
37 * as many logical devices as necessary.
38 *
39 * <p>Note that if a physical device has multiple instances of a particular
40 * functionality, it should advertize only one instance. For instance, if
41 * a device has multiple tuners, it should only expose one for control
42 * via CEC. In this case, it is up to the device itself to manage multiple tuners.
43 *
44 * <p>The version of HDMI-CEC protocol supported in this class is 1.3a.
45 *
46 * <p>Declared as package-private, accessed by HdmiCecService only.
47 */
Jinsuk Kim4e90fcd2014-03-24 18:02:29 +090048abstract class HdmiCecDevice {
Jinsuk Kim4f512fb2014-02-28 17:41:17 +090049 private static final String TAG = "HdmiCecDevice";
50
51 private final int mType;
52
53 // List of listeners to the message/event coming to the device.
54 private final List<IHdmiCecListener> mListeners = new ArrayList<IHdmiCecListener>();
55 private final Binder mBinder = new Binder();
Jinsuk Kim4e90fcd2014-03-24 18:02:29 +090056 private final HdmiCecService mService;
Jinsuk Kim4f512fb2014-02-28 17:41:17 +090057
Jinsuk Kim4f512fb2014-02-28 17:41:17 +090058 private boolean mIsActiveSource;
59
60 /**
Jinsuk Kim4e90fcd2014-03-24 18:02:29 +090061 * Factory method that creates HdmiCecDevice instance to the device type.
62 */
63 public static HdmiCecDevice create(HdmiCecService service, int type) {
64 if (type == HdmiCec.DEVICE_PLAYBACK) {
65 return new HdmiCecDevicePlayback(service, type);
66 } else if (type == HdmiCec.DEVICE_TV) {
67 return new HdmiCecDeviceTv(service, type);
68 }
69 return null;
70 }
71
72 /**
Jinsuk Kim4f512fb2014-02-28 17:41:17 +090073 * Constructor.
74 */
Jinsuk Kim4e90fcd2014-03-24 18:02:29 +090075 public HdmiCecDevice(HdmiCecService service, int type) {
76 mService = service;
Jinsuk Kim4f512fb2014-02-28 17:41:17 +090077 mType = type;
78 mIsActiveSource = false;
79 }
80
81 /**
Jinsuk Kim4e90fcd2014-03-24 18:02:29 +090082 * Called right after the class is instantiated. This method can be used to
83 * implement any initialization tasks for the instance.
84 */
85 abstract public void initialize();
86
87 /**
Jinsuk Kim4f512fb2014-02-28 17:41:17 +090088 * Return the binder token that identifies this instance.
89 */
90 public Binder getToken() {
91 return mBinder;
92 }
93
94 /**
Jinsuk Kim4e90fcd2014-03-24 18:02:29 +090095 * Return the service instance.
96 */
97 public HdmiCecService getService() {
98 return mService;
99 }
100
101 /**
Jinsuk Kim4f512fb2014-02-28 17:41:17 +0900102 * Return the type of this device.
103 */
104 public int getType() {
105 return mType;
106 }
107
108 /**
Jinsuk Kim4f512fb2014-02-28 17:41:17 +0900109 * Register a listener to be invoked when events occur.
110 *
111 * @param listener the listern that will run
112 */
113 public void addListener(IHdmiCecListener listener) {
114 mListeners.add(listener);
115 }
116
117 /**
118 * Remove the listener that was previously registered.
119 *
120 * @param listener IHdmiCecListener instance to be removed
121 */
122 public void removeListener(IHdmiCecListener listener) {
123 mListeners.remove(listener);
124 }
125
126 /**
127 * Indicate if the device has listeners.
128 *
129 * @return true if there are listener instances for this device
130 */
131 public boolean hasListener() {
132 return !mListeners.isEmpty();
133 }
134
135 /**
136 * Handle HDMI-CEC message coming to the device by invoking the registered
137 * listeners.
138 */
139 public void handleMessage(int srcAddress, int dstAddress, int opcode, byte[] params) {
140 if (opcode == HdmiCec.MESSAGE_ACTIVE_SOURCE) {
141 mIsActiveSource = false;
142 }
Jinsuk Kim4e90fcd2014-03-24 18:02:29 +0900143
Jinsuk Kim4f512fb2014-02-28 17:41:17 +0900144 if (mListeners.size() == 0) {
145 return;
146 }
147 HdmiCecMessage message = new HdmiCecMessage(srcAddress, dstAddress, opcode, params);
148 for (IHdmiCecListener listener : mListeners) {
149 try {
150 listener.onMessageReceived(message);
151 } catch (RemoteException e) {
152 Log.e(TAG, "listener.onMessageReceived failed.");
153 }
154 }
155 }
156
157 public void handleHotplug(boolean connected) {
158 for (IHdmiCecListener listener : mListeners) {
159 try {
160 listener.onCableStatusChanged(connected);
161 } catch (RemoteException e) {
162 Log.e(TAG, "listener.onCableStatusChanged failed.");
163 }
164 }
165 }
166
167 /**
168 * Return the active status of the device.
169 *
170 * @return true if the device is the active source among the connected
171 * HDMI-CEC-enabled devices; otherwise false.
172 */
173 public boolean isActiveSource() {
174 return mIsActiveSource;
175 }
176
177 /**
178 * Update the active source state of the device.
179 */
180 public void setIsActiveSource(boolean state) {
181 mIsActiveSource = state;
182 }
Jinsuk Kim4e90fcd2014-03-24 18:02:29 +0900183
184 /**
Jinsuk Kim61791072014-04-07 13:39:17 +0900185 * Send &lt;Active Source&gt; command. The default implementation does nothing. Should be
186 * overriden by subclass.
187 */
188 public void sendActiveSource(int physicalAddress) {
189 logWarning("<Active Source> not valid for the device type: " + mType
190 + " address:" + physicalAddress);
191 }
192
193 /**
194 * Send &lt;Inactive Source&gt; command. The default implementation does nothing. Should be
195 * overriden by subclass.
196 */
197 public void sendInactiveSource(int physicalAddress) {
198 logWarning("<Inactive Source> not valid for the device type: " + mType
199 + " address:" + physicalAddress);
200 }
201
202 /**
203 * Send &lt;Image View On&gt; command. The default implementation does nothing. Should be
204 * overriden by subclass.
205 */
206 public void sendImageViewOn() {
207 logWarning("<Image View On> not valid for the device type: " + mType);
208 }
209
210 /**
211 * Send &lt;Text View On&gt; command. The default implementation does nothing. Should be
212 * overriden by subclass.
213 */
214 public void sendTextViewOn() {
215 logWarning("<Text View On> not valid for the device type: " + mType);
216 }
217
218 /**
Jinsuk Kim4e90fcd2014-03-24 18:02:29 +0900219 * Check if the connected sink device is in powered-on state. The default implementation
220 * simply returns false. Should be overriden by subclass to report the correct state.
221 */
222 public boolean isSinkDeviceOn() {
Jinsuk Kim61791072014-04-07 13:39:17 +0900223 logWarning("isSinkDeviceOn() not valid for the device type: " + mType);
Jinsuk Kim4e90fcd2014-03-24 18:02:29 +0900224 return false;
225 }
Jinsuk Kim61791072014-04-07 13:39:17 +0900226
227 private void logWarning(String msg) {
228 Log.w(TAG, msg);
229 }
Jinsuk Kim4f512fb2014-02-28 17:41:17 +0900230}