HdmiTvClient.java revision 6ffb03816f7410c001072a25c3e4161a2da4f501
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 */
16package android.hardware.hdmi;
17
18import android.annotation.NonNull;
19import android.annotation.SystemApi;
20import android.hardware.hdmi.HdmiRecordSources.RecordSource;
21import android.hardware.hdmi.HdmiTimerRecordSources.TimerRecordSource;
22import android.os.RemoteException;
23import android.util.Log;
24
25import libcore.util.EmptyArray;
26
27/**
28 * HdmiTvClient represents HDMI-CEC logical device of type TV in the Android system
29 * which acts as TV/Display. It provides with methods that manage, interact with other
30 * devices on the CEC bus.
31 *
32 * @hide
33 */
34@SystemApi
35public final class HdmiTvClient extends HdmiClient {
36    private static final String TAG = "HdmiTvClient";
37
38    // Definitions used for setOption(). These should be in sync with the definition
39    // in hardware/libhardware/include/hardware/{hdmi_cec.h,mhl.h}.
40
41    /**
42     * TV gets turned on by incoming <Text/Image View On>. {@code ENABLED} by default.
43     * If set to {@code DISABLED}, TV won't turn on automatically.
44     */
45    public static final int OPTION_CEC_AUTO_WAKEUP = 1;
46
47    /**
48     * If set to {@code DISABLED}, all CEC commands are discarded.
49     *
50     * <p> This option is for internal use only, not supposed to be used by other components.
51     * @hide
52     */
53    public static final int OPTION_CEC_ENABLE = 2;
54
55    /**
56     * If set to {@code DISABLED}, system service yields control of CEC to sub-microcontroller.
57     * If {@code ENABLED}, it take the control back.
58     *
59     * <p> This option is for internal use only, not supposed to be used by other components.
60     * @hide
61     */
62    public static final int OPTION_CEC_SERVICE_CONTROL = 3;
63
64    /**
65     * Put other devices to standby when TV goes to standby. {@code ENABLED} by default.
66     * If set to {@code DISABLED}, TV doesn't send &lt;Standby&gt; to other devices.
67     */
68    public static final int OPTION_CEC_AUTO_DEVICE_OFF = 4;
69
70    /** If set to {@code DISABLED}, TV does not switch ports when mobile device is connected. */
71    public static final int OPTION_MHL_INPUT_SWITCHING = 101;
72
73    /** If set to {@code ENABLED}, TV disables power charging for mobile device. */
74    public static final int OPTION_MHL_POWER_CHARGE = 102;
75
76    /**
77     * If set to {@code DISABLED}, all MHL commands are discarded.
78     *
79     * <p> This option is for internal use only, not supposed to be used by other components.
80     * @hide
81     */
82    public static final int OPTION_MHL_ENABLE = 103;
83
84    public static final int DISABLED = 0;
85    public static final int ENABLED = 1;
86
87    HdmiTvClient(IHdmiControlService service) {
88        super(service);
89    }
90
91    // Factory method for HdmiTvClient.
92    // Declared package-private. Accessed by HdmiControlManager only.
93    static HdmiTvClient create(IHdmiControlService service) {
94        return new HdmiTvClient(service);
95    }
96
97    @Override
98    public int getDeviceType() {
99        return HdmiCecDeviceInfo.DEVICE_TV;
100    }
101
102    /**
103     * Callback interface used to get the result of {@link #deviceSelect}.
104     */
105    public interface SelectCallback {
106        /**
107         * Called when the operation is finished.
108         *
109         * @param result the result value of {@link #deviceSelect}
110         */
111        void onComplete(int result);
112    }
113
114    /**
115     * Select a CEC logical device to be a new active source.
116     *
117     * @param logicalAddress logical address of the device to select
118     * @param callback callback to get the result with
119     * @throws {@link IllegalArgumentException} if the {@code callback} is null
120     */
121    public void deviceSelect(int logicalAddress, @NonNull SelectCallback callback) {
122        if (callback == null) {
123            throw new IllegalArgumentException("callback must not be null.");
124        }
125        try {
126            mService.deviceSelect(logicalAddress, getCallbackWrapper(callback));
127        } catch (RemoteException e) {
128            Log.e(TAG, "failed to select device: ", e);
129        }
130    }
131
132    /**
133     * Select a HDMI port to be a new route path.
134     *
135     * @param portId HDMI port to select
136     * @param callback callback to get the result with
137     * @throws {@link IllegalArgumentException} if the {@code callback} is null
138     */
139    public void portSelect(int portId, @NonNull SelectCallback callback) {
140        if (callback == null) {
141            throw new IllegalArgumentException("Callback must not be null");
142        }
143        try {
144            mService.portSelect(portId, getCallbackWrapper(callback));
145        } catch (RemoteException e) {
146            Log.e(TAG, "failed to select port: ", e);
147        }
148    }
149
150    /**
151     * Set system audio volume
152     *
153     * @param oldIndex current volume index
154     * @param newIndex volume index to be set
155     * @param maxIndex maximum volume index
156     */
157    public void setSystemAudioVolume(int oldIndex, int newIndex, int maxIndex) {
158        try {
159            mService.setSystemAudioVolume(oldIndex, newIndex, maxIndex);
160        } catch (RemoteException e) {
161            Log.e(TAG, "failed to set volume: ", e);
162        }
163    }
164
165    /**
166     * Set system audio mute status
167     *
168     * @param mute {@code true} if muted; otherwise, {@code false}
169     */
170    public void setSystemAudioMute(boolean mute) {
171        try {
172            mService.setSystemAudioMute(mute);
173        } catch (RemoteException e) {
174            Log.e(TAG, "failed to set mute: ", e);
175        }
176    }
177
178    /**
179     * Set record listener
180     *
181     * @param listener
182     */
183    public void setRecordListener(@NonNull HdmiRecordListener listener) {
184        if (listener == null) {
185            throw new IllegalArgumentException("listener must not be null.");
186        }
187        try {
188            mService.setHdmiRecordListener(getListenerWrapper(listener));
189        } catch (RemoteException e) {
190            Log.e(TAG, "failed to set record listener.", e);
191        }
192    }
193
194    /**
195     * Start one touch recording with the given recorder address and recorder source.
196     * <p>
197     * Usage
198     * <pre>
199     * HdmiTvClient tvClient = ....;
200     * // for own source.
201     * OwnSource ownSource = ownHdmiRecordSources.ownSource();
202     * tvClient.startOneTouchRecord(recorderAddress, ownSource);
203     * </pre>
204     */
205    public void startOneTouchRecord(int recorderAddress, @NonNull RecordSource source) {
206        if (source == null) {
207            throw new IllegalArgumentException("source must not be null.");
208        }
209
210        try {
211            byte[] data = new byte[source.getDataSize(true)];
212            source.toByteArray(true, data, 0);
213            mService.startOneTouchRecord(recorderAddress, data);
214        } catch (RemoteException e) {
215            Log.e(TAG, "failed to start record: ", e);
216        }
217    }
218
219    /**
220     * Stop one touch record.
221     *
222     * @param recorderAddress recorder address where recoding will be stopped
223     */
224    public void stopOneTouchRecord(int recorderAddress) {
225        try {
226            mService.stopOneTouchRecord(recorderAddress);
227        } catch (RemoteException e) {
228            Log.e(TAG, "failed to stop record: ", e);
229        }
230    }
231
232    /**
233     * Start timer recording with the given recoder address and recorder source.
234     * <p>
235     * Usage
236     * <pre>
237     * HdmiTvClient tvClient = ....;
238     * // create timer info
239     * TimerInfo timerInfo = HdmiTimerRecourdSources.timerInfoOf(...);
240     * // for digital source.
241     * DigitalServiceSource recordSource = HdmiRecordSources.ofDigitalService(...);
242     * // create timer recording source.
243     * TimerRecordSource source = HdmiTimerRecourdSources.ofDigitalSource(timerInfo, recordSource);
244     * tvClient.startTimerRecording(recorderAddress, source);
245     * </pre>
246     *
247     * @param recorderAddress target recorder address
248     * @param sourceType type of record source. It should be one of
249     *          {@link HdmiControlManager#TIMER_RECORDING_TYPE_DIGITAL},
250     *          {@link HdmiControlManager#TIMER_RECORDING_TYPE_ANALOGUE},
251     *          {@link HdmiControlManager#TIMER_RECORDING_TYPE_EXTERNAL}.
252     * @param source record source to be used
253     */
254    public void startTimerRecording(int recorderAddress, int sourceType, TimerRecordSource source) {
255        if (source == null) {
256            throw new IllegalArgumentException("source must not be null.");
257        }
258
259        checkTimerRecordingSourceType(sourceType);
260
261        try {
262            byte[] data = new byte[source.getDataSize()];
263            source.toByteArray(data, 0);
264            mService.startTimerRecording(recorderAddress, sourceType, data);
265        } catch (RemoteException e) {
266            Log.e(TAG, "failed to start record: ", e);
267        }
268    }
269
270    private void checkTimerRecordingSourceType(int sourceType) {
271        switch (sourceType) {
272            case HdmiControlManager.TIMER_RECORDING_TYPE_DIGITAL:
273            case HdmiControlManager.TIMER_RECORDING_TYPE_ANALOGUE:
274            case HdmiControlManager.TIMER_RECORDING_TYPE_EXTERNAL:
275                break;
276            default:
277                throw new IllegalArgumentException("Invalid source type:" + sourceType);
278        }
279    }
280
281    /**
282     * Clear timer recording with the given recorder address and recording source.
283     * For more details, please refer {@link #startTimerRecording(int, int, TimerRecordSource)}.
284     */
285    public void clearTimerRecording(int recorderAddress, int sourceType, TimerRecordSource source) {
286        if (source == null) {
287            throw new IllegalArgumentException("source must not be null.");
288        }
289
290        checkTimerRecordingSourceType(sourceType);
291        try {
292            byte[] data = new byte[source.getDataSize()];
293            source.toByteArray(data, 0);
294            mService.clearTimerRecording(recorderAddress, sourceType, data);
295        } catch (RemoteException e) {
296            Log.e(TAG, "failed to start record: ", e);
297        }
298    }
299
300    private static IHdmiControlCallback getCallbackWrapper(final SelectCallback callback) {
301        return new IHdmiControlCallback.Stub() {
302            @Override
303            public void onComplete(int result) {
304                callback.onComplete(result);
305            }
306        };
307    }
308
309    private static IHdmiRecordListener getListenerWrapper(final HdmiRecordListener callback) {
310        return new IHdmiRecordListener.Stub() {
311            @Override
312            public byte[] getOneTouchRecordSource(int recorderAddress) {
313                HdmiRecordSources.RecordSource source =
314                        callback.getOneTouchRecordSource(recorderAddress);
315                if (source == null) {
316                    return EmptyArray.BYTE;
317                }
318                byte[] data = new byte[source.getDataSize(true)];
319                source.toByteArray(true, data, 0);
320                return data;
321            }
322
323            @Override
324            public void onOneTouchRecordResult(int result) {
325                callback.onOneTouchRecordResult(result);
326            }
327
328            @Override
329            public void onTimerRecordingResult(int result) {
330                callback.onTimerRecordingResult(
331                        HdmiRecordListener.TimerStatusData.parseFrom(result));
332            }
333
334            @Override
335            public void onClearTimerRecordingResult(int result) {
336                callback.onClearTimerRecordingResult(result);
337            }
338        };
339    }
340}
341