191120c541ac0c8c5e256b75759c884b4d6d664fcJinsuk Kim/*
291120c541ac0c8c5e256b75759c884b4d6d664fcJinsuk Kim * Copyright (C) 2014 The Android Open Source Project
391120c541ac0c8c5e256b75759c884b4d6d664fcJinsuk Kim *
491120c541ac0c8c5e256b75759c884b4d6d664fcJinsuk Kim * Licensed under the Apache License, Version 2.0 (the "License");
591120c541ac0c8c5e256b75759c884b4d6d664fcJinsuk Kim * you may not use this file except in compliance with the License.
691120c541ac0c8c5e256b75759c884b4d6d664fcJinsuk Kim * You may obtain a copy of the License at
791120c541ac0c8c5e256b75759c884b4d6d664fcJinsuk Kim *
891120c541ac0c8c5e256b75759c884b4d6d664fcJinsuk Kim *      http://www.apache.org/licenses/LICENSE-2.0
991120c541ac0c8c5e256b75759c884b4d6d664fcJinsuk Kim *
1091120c541ac0c8c5e256b75759c884b4d6d664fcJinsuk Kim * Unless required by applicable law or agreed to in writing, software
1191120c541ac0c8c5e256b75759c884b4d6d664fcJinsuk Kim * distributed under the License is distributed on an "AS IS" BASIS,
1291120c541ac0c8c5e256b75759c884b4d6d664fcJinsuk Kim * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1391120c541ac0c8c5e256b75759c884b4d6d664fcJinsuk Kim * See the License for the specific language governing permissions and
1491120c541ac0c8c5e256b75759c884b4d6d664fcJinsuk Kim * limitations under the License.
1591120c541ac0c8c5e256b75759c884b4d6d664fcJinsuk Kim */
1691120c541ac0c8c5e256b75759c884b4d6d664fcJinsuk Kimpackage android.hardware.hdmi;
1791120c541ac0c8c5e256b75759c884b4d6d664fcJinsuk Kim
18e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jangimport android.annotation.NonNull;
1966d1eb285b129836d1b3c392ed609283c0dbf830Jinsuk Kimimport android.annotation.SystemApi;
2012e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jangimport android.hardware.hdmi.HdmiRecordSources.RecordSource;
2112e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jangimport android.hardware.hdmi.HdmiTimerRecordSources.TimerRecordSource;
22a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kimimport android.os.RemoteException;
23a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kimimport android.util.Log;
2466d1eb285b129836d1b3c392ed609283c0dbf830Jinsuk Kim
252b0da5c4c84305f1d391dc78b85e244c9fd92456Yuncheol Heoimport libcore.util.EmptyArray;
262b0da5c4c84305f1d391dc78b85e244c9fd92456Yuncheol Heo
27bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kimimport java.util.Collections;
28bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kimimport java.util.List;
29bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim
3091120c541ac0c8c5e256b75759c884b4d6d664fcJinsuk Kim/**
3191120c541ac0c8c5e256b75759c884b4d6d664fcJinsuk Kim * HdmiTvClient represents HDMI-CEC logical device of type TV in the Android system
3291120c541ac0c8c5e256b75759c884b4d6d664fcJinsuk Kim * which acts as TV/Display. It provides with methods that manage, interact with other
3391120c541ac0c8c5e256b75759c884b4d6d664fcJinsuk Kim * devices on the CEC bus.
3466d1eb285b129836d1b3c392ed609283c0dbf830Jinsuk Kim *
3566d1eb285b129836d1b3c392ed609283c0dbf830Jinsuk Kim * @hide
3691120c541ac0c8c5e256b75759c884b4d6d664fcJinsuk Kim */
3766d1eb285b129836d1b3c392ed609283c0dbf830Jinsuk Kim@SystemApi
38119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kimpublic final class HdmiTvClient extends HdmiClient {
3991120c541ac0c8c5e256b75759c884b4d6d664fcJinsuk Kim    private static final String TAG = "HdmiTvClient";
4091120c541ac0c8c5e256b75759c884b4d6d664fcJinsuk Kim
41f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang    /**
42b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim     * Size of MHL register for vendor command
43f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang     */
44b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim    public static final int VENDOR_DATA_SIZE = 16;
45f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang
462b0da5c4c84305f1d391dc78b85e244c9fd92456Yuncheol Heo    /* package */ HdmiTvClient(IHdmiControlService service) {
47119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim        super(service);
4891120c541ac0c8c5e256b75759c884b4d6d664fcJinsuk Kim    }
49a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim
50a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim    // Factory method for HdmiTvClient.
51a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim    // Declared package-private. Accessed by HdmiControlManager only.
522b0da5c4c84305f1d391dc78b85e244c9fd92456Yuncheol Heo    /* package */ static HdmiTvClient create(IHdmiControlService service) {
53a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim        return new HdmiTvClient(service);
54a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim    }
55a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim
56a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang    @Override
57119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim    public int getDeviceType() {
5861f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang        return HdmiDeviceInfo.DEVICE_TV;
59119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim    }
60119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim
61a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim    /**
62a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim     * Callback interface used to get the result of {@link #deviceSelect}.
63a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim     */
64a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim    public interface SelectCallback {
65a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim        /**
66a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim         * Called when the operation is finished.
67a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim         *
68a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim         * @param result the result value of {@link #deviceSelect}
69a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim         */
70a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim        void onComplete(int result);
71a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim    }
72a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim
73a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim    /**
742b0da5c4c84305f1d391dc78b85e244c9fd92456Yuncheol Heo     * Selects a CEC logical device to be a new active source.
75a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim     *
766ffb03816f7410c001072a25c3e4161a2da4f501Jinsuk Kim     * @param logicalAddress logical address of the device to select
776ffb03816f7410c001072a25c3e4161a2da4f501Jinsuk Kim     * @param callback callback to get the result with
786ffb03816f7410c001072a25c3e4161a2da4f501Jinsuk Kim     * @throws {@link IllegalArgumentException} if the {@code callback} is null
79a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim     */
80e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang    public void deviceSelect(int logicalAddress, @NonNull SelectCallback callback) {
81e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang        if (callback == null) {
82e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang            throw new IllegalArgumentException("callback must not be null.");
83e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang        }
84a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim        try {
85a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim            mService.deviceSelect(logicalAddress, getCallbackWrapper(callback));
86a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim        } catch (RemoteException e) {
87a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim            Log.e(TAG, "failed to select device: ", e);
88a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim        }
89a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim    }
90a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim
91f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang    private static IHdmiControlCallback getCallbackWrapper(final SelectCallback callback) {
92f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang        return new IHdmiControlCallback.Stub() {
93f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang            @Override
94f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang            public void onComplete(int result) {
95f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang                callback.onComplete(result);
96f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang            }
97f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang        };
98f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang    }
99f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang
10041d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang    /**
1012b0da5c4c84305f1d391dc78b85e244c9fd92456Yuncheol Heo     * Selects a HDMI port to be a new route path.
1026ffb03816f7410c001072a25c3e4161a2da4f501Jinsuk Kim     *
1036ffb03816f7410c001072a25c3e4161a2da4f501Jinsuk Kim     * @param portId HDMI port to select
1046ffb03816f7410c001072a25c3e4161a2da4f501Jinsuk Kim     * @param callback callback to get the result with
1056ffb03816f7410c001072a25c3e4161a2da4f501Jinsuk Kim     * @throws {@link IllegalArgumentException} if the {@code callback} is null
1066ffb03816f7410c001072a25c3e4161a2da4f501Jinsuk Kim     */
1076ffb03816f7410c001072a25c3e4161a2da4f501Jinsuk Kim    public void portSelect(int portId, @NonNull SelectCallback callback) {
1086ffb03816f7410c001072a25c3e4161a2da4f501Jinsuk Kim        if (callback == null) {
1096ffb03816f7410c001072a25c3e4161a2da4f501Jinsuk Kim            throw new IllegalArgumentException("Callback must not be null");
1106ffb03816f7410c001072a25c3e4161a2da4f501Jinsuk Kim        }
1116ffb03816f7410c001072a25c3e4161a2da4f501Jinsuk Kim        try {
1126ffb03816f7410c001072a25c3e4161a2da4f501Jinsuk Kim            mService.portSelect(portId, getCallbackWrapper(callback));
1136ffb03816f7410c001072a25c3e4161a2da4f501Jinsuk Kim        } catch (RemoteException e) {
1146ffb03816f7410c001072a25c3e4161a2da4f501Jinsuk Kim            Log.e(TAG, "failed to select port: ", e);
1156ffb03816f7410c001072a25c3e4161a2da4f501Jinsuk Kim        }
1166ffb03816f7410c001072a25c3e4161a2da4f501Jinsuk Kim    }
1176ffb03816f7410c001072a25c3e4161a2da4f501Jinsuk Kim
1186ffb03816f7410c001072a25c3e4161a2da4f501Jinsuk Kim    /**
119d38bf476f6a31602e92a3207a4ceb29bf965f9aaJinsuk Kim     * Callback interface used to get the input change event.
120d38bf476f6a31602e92a3207a4ceb29bf965f9aaJinsuk Kim     */
121d38bf476f6a31602e92a3207a4ceb29bf965f9aaJinsuk Kim    public interface InputChangeListener {
122d38bf476f6a31602e92a3207a4ceb29bf965f9aaJinsuk Kim        /**
123d38bf476f6a31602e92a3207a4ceb29bf965f9aaJinsuk Kim         * Called when the input was changed.
124d38bf476f6a31602e92a3207a4ceb29bf965f9aaJinsuk Kim         *
125d38bf476f6a31602e92a3207a4ceb29bf965f9aaJinsuk Kim         * @param info newly selected HDMI input
126d38bf476f6a31602e92a3207a4ceb29bf965f9aaJinsuk Kim         */
127d38bf476f6a31602e92a3207a4ceb29bf965f9aaJinsuk Kim        void onChanged(HdmiDeviceInfo info);
128d38bf476f6a31602e92a3207a4ceb29bf965f9aaJinsuk Kim    }
129d38bf476f6a31602e92a3207a4ceb29bf965f9aaJinsuk Kim
130d38bf476f6a31602e92a3207a4ceb29bf965f9aaJinsuk Kim    /**
1312b0da5c4c84305f1d391dc78b85e244c9fd92456Yuncheol Heo     * Sets the listener used to get informed of the input change event.
132d38bf476f6a31602e92a3207a4ceb29bf965f9aaJinsuk Kim     *
133d38bf476f6a31602e92a3207a4ceb29bf965f9aaJinsuk Kim     * @param listener listener object
134d38bf476f6a31602e92a3207a4ceb29bf965f9aaJinsuk Kim     */
135d38bf476f6a31602e92a3207a4ceb29bf965f9aaJinsuk Kim    public void setInputChangeListener(InputChangeListener listener) {
136d38bf476f6a31602e92a3207a4ceb29bf965f9aaJinsuk Kim        if (listener == null) {
137d38bf476f6a31602e92a3207a4ceb29bf965f9aaJinsuk Kim            throw new IllegalArgumentException("listener must not be null.");
138d38bf476f6a31602e92a3207a4ceb29bf965f9aaJinsuk Kim        }
139d38bf476f6a31602e92a3207a4ceb29bf965f9aaJinsuk Kim        try {
140d38bf476f6a31602e92a3207a4ceb29bf965f9aaJinsuk Kim            mService.setInputChangeListener(getListenerWrapper(listener));
141d38bf476f6a31602e92a3207a4ceb29bf965f9aaJinsuk Kim        } catch (RemoteException e) {
142d38bf476f6a31602e92a3207a4ceb29bf965f9aaJinsuk Kim            Log.e("TAG", "Failed to set InputChangeListener:", e);
143d38bf476f6a31602e92a3207a4ceb29bf965f9aaJinsuk Kim        }
144d38bf476f6a31602e92a3207a4ceb29bf965f9aaJinsuk Kim    }
145d38bf476f6a31602e92a3207a4ceb29bf965f9aaJinsuk Kim
146f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang    private static IHdmiInputChangeListener getListenerWrapper(final InputChangeListener listener) {
147f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang        return new IHdmiInputChangeListener.Stub() {
148f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang            @Override
149f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang            public void onChanged(HdmiDeviceInfo info) {
150f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang                listener.onChanged(info);
151f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang            }
152f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang        };
153f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang    }
154f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang
155d38bf476f6a31602e92a3207a4ceb29bf965f9aaJinsuk Kim    /**
156bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim     * Returns all the CEC devices connected to TV.
157bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim     *
158bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim     * @return list of {@link HdmiDeviceInfo} for connected CEC devices.
159bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim     *         Empty list is returned if there is none.
160bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim     */
161bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim    public List<HdmiDeviceInfo> getDeviceList() {
162bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim        try {
163bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim            return mService.getDeviceList();
164bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim        } catch (RemoteException e) {
165bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim            Log.e("TAG", "Failed to call getDeviceList():", e);
166bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim            return Collections.<HdmiDeviceInfo>emptyList();
167bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim        }
168bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim    }
169bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim
170bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim    /**
171c6563961e5cce5cfa781c5a956b4e51e3b440883Jinsuk Kim     * Sets system audio mode.
172c6563961e5cce5cfa781c5a956b4e51e3b440883Jinsuk Kim     *
173c6563961e5cce5cfa781c5a956b4e51e3b440883Jinsuk Kim     * @param enabled set to {@code true} to enable the mode; otherwise {@code false}
174c6563961e5cce5cfa781c5a956b4e51e3b440883Jinsuk Kim     * @param callback callback to get the result with
175c6563961e5cce5cfa781c5a956b4e51e3b440883Jinsuk Kim     * @throws {@link IllegalArgumentException} if the {@code callback} is null
176c6563961e5cce5cfa781c5a956b4e51e3b440883Jinsuk Kim     */
177c6563961e5cce5cfa781c5a956b4e51e3b440883Jinsuk Kim    public void setSystemAudioMode(boolean enabled, SelectCallback callback) {
178c6563961e5cce5cfa781c5a956b4e51e3b440883Jinsuk Kim        try {
179c6563961e5cce5cfa781c5a956b4e51e3b440883Jinsuk Kim            mService.setSystemAudioMode(enabled, getCallbackWrapper(callback));
180c6563961e5cce5cfa781c5a956b4e51e3b440883Jinsuk Kim        } catch (RemoteException e) {
181c6563961e5cce5cfa781c5a956b4e51e3b440883Jinsuk Kim            Log.e(TAG, "failed to set system audio mode:", e);
182c6563961e5cce5cfa781c5a956b4e51e3b440883Jinsuk Kim        }
183c6563961e5cce5cfa781c5a956b4e51e3b440883Jinsuk Kim    }
184c6563961e5cce5cfa781c5a956b4e51e3b440883Jinsuk Kim
185c6563961e5cce5cfa781c5a956b4e51e3b440883Jinsuk Kim    /**
186c6563961e5cce5cfa781c5a956b4e51e3b440883Jinsuk Kim     * Sets system audio volume.
18741d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang     *
18841d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang     * @param oldIndex current volume index
18941d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang     * @param newIndex volume index to be set
19041d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang     * @param maxIndex maximum volume index
19141d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang     */
19241d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang    public void setSystemAudioVolume(int oldIndex, int newIndex, int maxIndex) {
19341d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang        try {
19441d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang            mService.setSystemAudioVolume(oldIndex, newIndex, maxIndex);
19541d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang        } catch (RemoteException e) {
19641d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang            Log.e(TAG, "failed to set volume: ", e);
19741d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang        }
19841d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang    }
19941d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang
20041d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang    /**
201c6563961e5cce5cfa781c5a956b4e51e3b440883Jinsuk Kim     * Sets system audio mute status.
20241d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang     *
20341d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang     * @param mute {@code true} if muted; otherwise, {@code false}
20441d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang     */
20541d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang    public void setSystemAudioMute(boolean mute) {
20641d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang        try {
20741d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang            mService.setSystemAudioMute(mute);
20841d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang        } catch (RemoteException e) {
20941d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang            Log.e(TAG, "failed to set mute: ", e);
21041d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang        }
21141d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang    }
21241d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang
213a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang    /**
214c6563961e5cce5cfa781c5a956b4e51e3b440883Jinsuk Kim     * Sets record listener.
21512e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang     *
21612e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang     * @param listener
217a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang     */
218e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang    public void setRecordListener(@NonNull HdmiRecordListener listener) {
219e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang        if (listener == null) {
220e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang            throw new IllegalArgumentException("listener must not be null.");
221e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang        }
222a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang        try {
22312e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang            mService.setHdmiRecordListener(getListenerWrapper(listener));
224a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang        } catch (RemoteException e) {
22512e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang            Log.e(TAG, "failed to set record listener.", e);
226a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang        }
227a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang    }
228a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang
2298d115eb18fce5b85538239e2373c3efd28e46986Jinsuk Kim    /**
2308d115eb18fce5b85538239e2373c3efd28e46986Jinsuk Kim     * Sends a &lt;Standby&gt; command to other device.
2318d115eb18fce5b85538239e2373c3efd28e46986Jinsuk Kim     *
2328d115eb18fce5b85538239e2373c3efd28e46986Jinsuk Kim     * @param deviceId device id to send the command to
2338d115eb18fce5b85538239e2373c3efd28e46986Jinsuk Kim     */
2348d115eb18fce5b85538239e2373c3efd28e46986Jinsuk Kim    public void sendStandby(int deviceId) {
2358d115eb18fce5b85538239e2373c3efd28e46986Jinsuk Kim        try {
2368d115eb18fce5b85538239e2373c3efd28e46986Jinsuk Kim            mService.sendStandby(getDeviceType(), deviceId);
2378d115eb18fce5b85538239e2373c3efd28e46986Jinsuk Kim        } catch (RemoteException e) {
2388d115eb18fce5b85538239e2373c3efd28e46986Jinsuk Kim            Log.e(TAG, "sendStandby threw exception ", e);
2398d115eb18fce5b85538239e2373c3efd28e46986Jinsuk Kim        }
2408d115eb18fce5b85538239e2373c3efd28e46986Jinsuk Kim    }
2418d115eb18fce5b85538239e2373c3efd28e46986Jinsuk Kim
242f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang    private static IHdmiRecordListener getListenerWrapper(final HdmiRecordListener callback) {
243f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang        return new IHdmiRecordListener.Stub() {
244f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang            @Override
245f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang            public byte[] getOneTouchRecordSource(int recorderAddress) {
246f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang                HdmiRecordSources.RecordSource source =
2472b0da5c4c84305f1d391dc78b85e244c9fd92456Yuncheol Heo                        callback.onOneTouchRecordSourceRequested(recorderAddress);
248f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang                if (source == null) {
249f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang                    return EmptyArray.BYTE;
250f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang                }
251f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang                byte[] data = new byte[source.getDataSize(true)];
252f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang                source.toByteArray(true, data, 0);
253f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang                return data;
254f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang            }
255f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang
256f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang            @Override
257326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang            public void onOneTouchRecordResult(int recorderAddress, int result) {
258326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang                callback.onOneTouchRecordResult(recorderAddress, result);
259f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang            }
260f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang
261f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang            @Override
262326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang            public void onTimerRecordingResult(int recorderAddress, int result) {
263326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang                callback.onTimerRecordingResult(recorderAddress,
264f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang                        HdmiRecordListener.TimerStatusData.parseFrom(result));
265f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang            }
266f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang
267f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang            @Override
268326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang            public void onClearTimerRecordingResult(int recorderAddress, int result) {
269326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang                callback.onClearTimerRecordingResult(recorderAddress, result);
270f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang            }
271f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang        };
272f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang    }
273f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang
274a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang    /**
2752b0da5c4c84305f1d391dc78b85e244c9fd92456Yuncheol Heo     * Starts one touch recording with the given recorder address and recorder source.
276bffb0635aaaaf9140d9120e3f3d95a4f7391a0acJungshik Jang     * <p>
277bffb0635aaaaf9140d9120e3f3d95a4f7391a0acJungshik Jang     * Usage
278a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang     * <pre>
279a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang     * HdmiTvClient tvClient = ....;
280a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang     * // for own source.
2812b0da5c4c84305f1d391dc78b85e244c9fd92456Yuncheol Heo     * OwnSource ownSource = HdmiRecordSources.ofOwnSource();
282bffb0635aaaaf9140d9120e3f3d95a4f7391a0acJungshik Jang     * tvClient.startOneTouchRecord(recorderAddress, ownSource);
283a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang     * </pre>
284a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang     */
285e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang    public void startOneTouchRecord(int recorderAddress, @NonNull RecordSource source) {
286e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang        if (source == null) {
287e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang            throw new IllegalArgumentException("source must not be null.");
288e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang        }
289e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang
290a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang        try {
291a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang            byte[] data = new byte[source.getDataSize(true)];
292a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang            source.toByteArray(true, data, 0);
293bffb0635aaaaf9140d9120e3f3d95a4f7391a0acJungshik Jang            mService.startOneTouchRecord(recorderAddress, data);
294bffb0635aaaaf9140d9120e3f3d95a4f7391a0acJungshik Jang        } catch (RemoteException e) {
295bffb0635aaaaf9140d9120e3f3d95a4f7391a0acJungshik Jang            Log.e(TAG, "failed to start record: ", e);
296bffb0635aaaaf9140d9120e3f3d95a4f7391a0acJungshik Jang        }
297bffb0635aaaaf9140d9120e3f3d95a4f7391a0acJungshik Jang    }
298bffb0635aaaaf9140d9120e3f3d95a4f7391a0acJungshik Jang
299bffb0635aaaaf9140d9120e3f3d95a4f7391a0acJungshik Jang    /**
3002b0da5c4c84305f1d391dc78b85e244c9fd92456Yuncheol Heo     * Stops one touch record.
301b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang     *
302b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang     * @param recorderAddress recorder address where recoding will be stopped
303b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang     */
304b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang    public void stopOneTouchRecord(int recorderAddress) {
305b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang        try {
306b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang            mService.stopOneTouchRecord(recorderAddress);
307b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang        } catch (RemoteException e) {
308b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang            Log.e(TAG, "failed to stop record: ", e);
309b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang        }
310b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang    }
311b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang
312b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang    /**
3132b0da5c4c84305f1d391dc78b85e244c9fd92456Yuncheol Heo     * Starts timer recording with the given recoder address and recorder source.
314bffb0635aaaaf9140d9120e3f3d95a4f7391a0acJungshik Jang     * <p>
315bffb0635aaaaf9140d9120e3f3d95a4f7391a0acJungshik Jang     * Usage
316bffb0635aaaaf9140d9120e3f3d95a4f7391a0acJungshik Jang     * <pre>
317bffb0635aaaaf9140d9120e3f3d95a4f7391a0acJungshik Jang     * HdmiTvClient tvClient = ....;
318bffb0635aaaaf9140d9120e3f3d95a4f7391a0acJungshik Jang     * // create timer info
319bffb0635aaaaf9140d9120e3f3d95a4f7391a0acJungshik Jang     * TimerInfo timerInfo = HdmiTimerRecourdSources.timerInfoOf(...);
320bffb0635aaaaf9140d9120e3f3d95a4f7391a0acJungshik Jang     * // for digital source.
321bffb0635aaaaf9140d9120e3f3d95a4f7391a0acJungshik Jang     * DigitalServiceSource recordSource = HdmiRecordSources.ofDigitalService(...);
322bffb0635aaaaf9140d9120e3f3d95a4f7391a0acJungshik Jang     * // create timer recording source.
323bffb0635aaaaf9140d9120e3f3d95a4f7391a0acJungshik Jang     * TimerRecordSource source = HdmiTimerRecourdSources.ofDigitalSource(timerInfo, recordSource);
324bffb0635aaaaf9140d9120e3f3d95a4f7391a0acJungshik Jang     * tvClient.startTimerRecording(recorderAddress, source);
325bffb0635aaaaf9140d9120e3f3d95a4f7391a0acJungshik Jang     * </pre>
326b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang     *
327b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang     * @param recorderAddress target recorder address
328b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang     * @param sourceType type of record source. It should be one of
329b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang     *          {@link HdmiControlManager#TIMER_RECORDING_TYPE_DIGITAL},
330b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang     *          {@link HdmiControlManager#TIMER_RECORDING_TYPE_ANALOGUE},
331b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang     *          {@link HdmiControlManager#TIMER_RECORDING_TYPE_EXTERNAL}.
332b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang     * @param source record source to be used
333b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang     */
334b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang    public void startTimerRecording(int recorderAddress, int sourceType, TimerRecordSource source) {
335e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang        if (source == null) {
336e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang            throw new IllegalArgumentException("source must not be null.");
337e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang        }
338e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang
339b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang        checkTimerRecordingSourceType(sourceType);
340b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang
341b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang        try {
342b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang            byte[] data = new byte[source.getDataSize()];
343b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang            source.toByteArray(data, 0);
344b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang            mService.startTimerRecording(recorderAddress, sourceType, data);
345b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang        } catch (RemoteException e) {
346b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang            Log.e(TAG, "failed to start record: ", e);
347b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang        }
348b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang    }
349b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang
350b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang    private void checkTimerRecordingSourceType(int sourceType) {
351b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang        switch (sourceType) {
352b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang            case HdmiControlManager.TIMER_RECORDING_TYPE_DIGITAL:
353b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang            case HdmiControlManager.TIMER_RECORDING_TYPE_ANALOGUE:
354b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang            case HdmiControlManager.TIMER_RECORDING_TYPE_EXTERNAL:
355b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang                break;
356b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang            default:
357b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang                throw new IllegalArgumentException("Invalid source type:" + sourceType);
358b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang        }
359b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang    }
360b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang
361b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang    /**
3622b0da5c4c84305f1d391dc78b85e244c9fd92456Yuncheol Heo     * Clears timer recording with the given recorder address and recording source.
363b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang     * For more details, please refer {@link #startTimerRecording(int, int, TimerRecordSource)}.
364bffb0635aaaaf9140d9120e3f3d95a4f7391a0acJungshik Jang     */
365b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang    public void clearTimerRecording(int recorderAddress, int sourceType, TimerRecordSource source) {
366e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang        if (source == null) {
367e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang            throw new IllegalArgumentException("source must not be null.");
368e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang        }
369e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang
370b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang        checkTimerRecordingSourceType(sourceType);
371bffb0635aaaaf9140d9120e3f3d95a4f7391a0acJungshik Jang        try {
372bffb0635aaaaf9140d9120e3f3d95a4f7391a0acJungshik Jang            byte[] data = new byte[source.getDataSize()];
373bffb0635aaaaf9140d9120e3f3d95a4f7391a0acJungshik Jang            source.toByteArray(data, 0);
374b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang            mService.clearTimerRecording(recorderAddress, sourceType, data);
375a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang        } catch (RemoteException e) {
376a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang            Log.e(TAG, "failed to start record: ", e);
377a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang        }
378a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang    }
379a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang
380f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang    /**
381b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim     * Interface used to get incoming MHL vendor command.
382f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang     */
383b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim    public interface HdmiMhlVendorCommandListener {
384f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang        void onReceived(int portId, int offset, int length, byte[] data);
385a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim    }
386a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang
387f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang    /**
3882b0da5c4c84305f1d391dc78b85e244c9fd92456Yuncheol Heo     * Sets {@link HdmiMhlVendorCommandListener} to get incoming MHL vendor command.
389f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang     *
390b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim     * @param listener to receive incoming MHL vendor command
391f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang     */
392b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim    public void setHdmiMhlVendorCommandListener(HdmiMhlVendorCommandListener listener) {
393f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang        if (listener == null) {
394f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang            throw new IllegalArgumentException("listener must not be null.");
395f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang        }
396f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang        try {
397b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim            mService.addHdmiMhlVendorCommandListener(getListenerWrapper(listener));
398f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang        } catch (RemoteException e) {
399b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim            Log.e(TAG, "failed to set hdmi mhl vendor command listener: ", e);
400f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang        }
401d38bf476f6a31602e92a3207a4ceb29bf965f9aaJinsuk Kim    }
402d38bf476f6a31602e92a3207a4ceb29bf965f9aaJinsuk Kim
403b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim    private IHdmiMhlVendorCommandListener getListenerWrapper(
404b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim            final HdmiMhlVendorCommandListener listener) {
405b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim        return new IHdmiMhlVendorCommandListener.Stub() {
406a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang            @Override
407f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang            public void onReceived(int portId, int offset, int length, byte[] data) {
408f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang                listener.onReceived(portId, offset, length, data);
40912e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang            }
410f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang        };
411f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang    }
41212e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang
413f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang    /**
4142b0da5c4c84305f1d391dc78b85e244c9fd92456Yuncheol Heo     * Sends MHL vendor command to the device connected to a port of the given portId.
415f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang     *
416b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim     * @param portId id of port to send MHL vendor command
417f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang     * @param offset offset in the in given data
418f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang     * @param length length of data. offset + length should be bound to length of data.
419b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim     * @param data container for vendor command data. It should be 16 bytes.
420f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang     * @throws IllegalArgumentException if the given parameters are invalid
421f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang     */
422b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim    public void sendMhlVendorCommand(int portId, int offset, int length, byte[] data) {
423b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim        if (data == null || data.length != VENDOR_DATA_SIZE) {
424b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim            throw new IllegalArgumentException("Invalid vendor command data.");
425f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang        }
426b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim        if (offset < 0 || offset >= VENDOR_DATA_SIZE) {
427f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang            throw new IllegalArgumentException("Invalid offset:" + offset);
428f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang        }
429b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim        if (length < 0 || offset + length > VENDOR_DATA_SIZE) {
430f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang            throw new IllegalArgumentException("Invalid length:" + length);
431f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang        }
432e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang
433f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang        try {
434b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim            mService.sendMhlVendorCommand(portId, offset, length, data);
435f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang        } catch (RemoteException e) {
436b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim            Log.e(TAG, "failed to send vendor command: ", e);
437f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang        }
438a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang    }
43991120c541ac0c8c5e256b75759c884b4d6d664fcJinsuk Kim}
440