HdmiControlService.java revision 092b445ef898e3c1e5b2918b554480940f0f5a28
10792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang/* 20792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * Copyright (C) 2014 The Android Open Source Project 30792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * 40792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * Licensed under the Apache License, Version 2.0 (the "License"); 50792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * you may not use this file except in compliance with the License. 60792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * You may obtain a copy of the License at 70792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * 80792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * http://www.apache.org/licenses/LICENSE-2.0 90792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * 100792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * Unless required by applicable law or agreed to in writing, software 110792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * distributed under the License is distributed on an "AS IS" BASIS, 120792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 130792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * See the License for the specific language governing permissions and 140792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * limitations under the License. 150792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang */ 160792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 170792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangpackage com.android.server.hdmi; 180792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 190792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangimport android.annotation.Nullable; 200792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangimport android.content.Context; 21a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jangimport android.hardware.hdmi.HdmiCec; 22c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kimimport android.hardware.hdmi.HdmiCecDeviceInfo; 23c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kimimport android.hardware.hdmi.HdmiCecMessage; 24d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jangimport android.hardware.hdmi.IHdmiControlCallback; 25d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jangimport android.hardware.hdmi.IHdmiControlService; 26d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jangimport android.hardware.hdmi.IHdmiHotplugEventListener; 2767ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jangimport android.os.Handler; 280792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangimport android.os.HandlerThread; 2978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kimimport android.os.IBinder; 30e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jangimport android.os.Looper; 3178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kimimport android.os.RemoteException; 320792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangimport android.util.Slog; 333ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jangimport android.util.SparseArray; 348b308d93c8fdcc7304b33d9b445ae3807eae97c8Jungshik Jangimport android.util.SparseIntArray; 3578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 3678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kimimport com.android.internal.annotations.GuardedBy; 370792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangimport com.android.server.SystemService; 38cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jangimport com.android.server.hdmi.DeviceDiscoveryAction.DeviceDiscoveryCallback; 393ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jangimport com.android.server.hdmi.HdmiCecController.AllocateAddressCallback; 400792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 4178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kimimport java.util.ArrayList; 4267ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jangimport java.util.Iterator; 4367ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jangimport java.util.LinkedList; 4402bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jangimport java.util.List; 45a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jangimport java.util.Locale; 46a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang 470792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang/** 480792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * Provides a service for sending and processing HDMI control messages, 490792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * HDMI-CEC and MHL control command, and providing the information on both standard. 500792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang */ 510792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangpublic final class HdmiControlService extends SystemService { 520792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang private static final String TAG = "HdmiControlService"; 530792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 5478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // TODO: Rename the permission to HDMI_CONTROL. 5578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private static final String PERMISSION = "android.permission.HDMI_CEC"; 5678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 57ece603b7955938d6001c376f351ca0a2219330acYuncheol Heo static final int SEND_RESULT_SUCCESS = 0; 58ece603b7955938d6001c376f351ca0a2219330acYuncheol Heo static final int SEND_RESULT_NAK = -1; 59ece603b7955938d6001c376f351ca0a2219330acYuncheol Heo static final int SEND_RESULT_FAILURE = -2; 60ece603b7955938d6001c376f351ca0a2219330acYuncheol Heo 610f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang static final int POLL_STRATEGY_MASK = 0x3; // first and second bit. 620f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang static final int POLL_STRATEGY_REMOTES_DEVICES = 0x1; 630f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang static final int POLL_STRATEGY_SYSTEM_AUDIO = 0x2; 640f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang 650f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang static final int POLL_ITERATION_STRATEGY_MASK = 0x30000; // first and second bit. 660f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang static final int POLL_ITERATION_IN_ORDER = 0x10000; 670f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang static final int POLL_ITERATION_REVERSE_ORDER = 0x20000; 680f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang 69d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang /** 70d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang * Interface to report send result. 71d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang */ 72d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang interface SendMessageCallback { 73d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang /** 74d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang * Called when {@link HdmiControlService#sendCecCommand} is completed. 75d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang * 76ece603b7955938d6001c376f351ca0a2219330acYuncheol Heo * @param error result of send request. 77ece603b7955938d6001c376f351ca0a2219330acYuncheol Heo * @see {@link #SEND_RESULT_SUCCESS} 78ece603b7955938d6001c376f351ca0a2219330acYuncheol Heo * @see {@link #SEND_RESULT_NAK} 79ece603b7955938d6001c376f351ca0a2219330acYuncheol Heo * @see {@link #SEND_RESULT_FAILURE} 80d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang */ 81d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang void onSendCompleted(int error); 82d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang } 83d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang 8402bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang /** 8502bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * Interface to get a list of available logical devices. 8602bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang */ 8702bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang interface DevicePollingCallback { 8802bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang /** 8902bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * Called when device polling is finished. 9002bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * 9102bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * @param ackedAddress a list of logical addresses of available devices 9202bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang */ 9302bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang void onPollingFinished(List<Integer> ackedAddress); 9402bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang } 9502bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang 960792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang // A thread to handle synchronous IO of CEC and MHL control service. 970792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang // Since all of CEC and MHL HAL interfaces processed in short time (< 200ms) 980792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang // and sparse call it shares a thread to handle IO operations. 990792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang private final HandlerThread mIoThread = new HandlerThread("Hdmi Control Io Thread"); 1000792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 10167ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang // A collection of FeatureAction. 10267ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang // Note that access to this collection should happen in service thread. 10367ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang private final LinkedList<FeatureAction> mActions = new LinkedList<>(); 10467ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang 10578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // Used to synchronize the access to the service. 10678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final Object mLock = new Object(); 10778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 10878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // Type of logical devices hosted in the system. 10978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @GuardedBy("mLock") 11078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final int[] mLocalDevices; 11178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 11278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // List of listeners registered by callers that want to get notified of 11378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // hotplug events. 11478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final ArrayList<IHdmiHotplugEventListener> mHotplugEventListeners = new ArrayList<>(); 11578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 11678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // List of records for hotplug event listener to handle the the caller killed in action. 11778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final ArrayList<HotplugEventListenerRecord> mHotplugEventListenerRecords = 11878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim new ArrayList<>(); 11978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 120e81e108c4035ea8933525baa8108cb392f8abf5dJungshik Jang private final HdmiCecMessageCache mCecMessageCache = new HdmiCecMessageCache(); 121e81e108c4035ea8933525baa8108cb392f8abf5dJungshik Jang 1220792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang @Nullable 1230792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang private HdmiCecController mCecController; 1240792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 1250792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang @Nullable 1260792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang private HdmiMhlController mMhlController; 1270792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 1280f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang @GuardedBy("mLock") 12967ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang // Whether ARC is "enabled" or not. 13067ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang // TODO: it may need to hold lock if it's accessed from others. 13167ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang private boolean mArcStatusEnabled = false; 13267ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang 1330f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang @GuardedBy("mLock") 13463a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo // Whether SystemAudioMode is "On" or not. 13563a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo private boolean mSystemAudioMode; 13663a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 13767ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang // Handler running on service thread. It's used to run a task in service thread. 13863a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo private final Handler mHandler = new Handler(); 13967ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang 1400792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang public HdmiControlService(Context context) { 1410792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang super(context); 14278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mLocalDevices = getContext().getResources().getIntArray( 14378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim com.android.internal.R.array.config_hdmiCecLogicalDeviceType); 1440792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang } 1450792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 1460792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang @Override 1470792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang public void onStart() { 1482f51aec689226e259d08bf04d838251f249572e3Jungshik Jang mIoThread.start(); 149e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang mCecController = HdmiCecController.create(this); 1508b308d93c8fdcc7304b33d9b445ae3807eae97c8Jungshik Jang 1513ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang if (mCecController != null) { 1523ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang initializeLocalDevices(mLocalDevices); 153a8a5e50c6f9ba3ae0ff59eda76354e93515d6f8fJinsuk Kim } else { 1540792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang Slog.i(TAG, "Device does not support HDMI-CEC."); 1550792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang } 1560792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 157e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang mMhlController = HdmiMhlController.create(this); 1580792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang if (mMhlController == null) { 1590792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang Slog.i(TAG, "Device does not support MHL-control."); 1600792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang } 16178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 1628692fc68a413c7aca75f094bb02bcbabcc277c73Jinsuk Kim publishBinderService(Context.HDMI_CONTROL_SERVICE, new BinderService()); 16363a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 16463a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo // TODO: Read the preference for SystemAudioMode and initialize mSystemAudioMode and 16563a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo // start to monitor the preference value and invoke SystemAudioActionFromTv if needed. 1660792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang } 167e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang 1683ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang private void initializeLocalDevices(final int[] deviceTypes) { 1693ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang // A container for [Logical Address, Local device info]. 1703ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang final SparseArray<HdmiCecLocalDevice> devices = new SparseArray<>(); 1713ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang final SparseIntArray finished = new SparseIntArray(); 1723ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang for (int type : deviceTypes) { 1733ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang final HdmiCecLocalDevice localDevice = HdmiCecLocalDevice.create(this, type); 1743ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang localDevice.init(); 1753ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang mCecController.allocateLogicalAddress(type, 1763ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang localDevice.getPreferredAddress(), new AllocateAddressCallback() { 1773ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang @Override 1783ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang public void onAllocated(int deviceType, int logicalAddress) { 1793ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang if (logicalAddress == HdmiCec.ADDR_UNREGISTERED) { 1803ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang Slog.e(TAG, "Failed to allocate address:[device_type:" + deviceType + "]"); 1813ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } else { 1823ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang HdmiCecDeviceInfo deviceInfo = createDeviceInfo(logicalAddress, deviceType); 1833ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang localDevice.setDeviceInfo(deviceInfo); 1843ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang mCecController.addLocalDevice(deviceType, localDevice); 1853ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang mCecController.addLogicalAddress(logicalAddress); 1863ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang devices.append(logicalAddress, localDevice); 1873ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 1883ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang finished.append(deviceType, logicalAddress); 1893ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 1903ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang // Once finish address allocation for all devices, notify 1913ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang // it to each device. 1923ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang if (deviceTypes.length == finished.size()) { 1933ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang notifyAddressAllocated(devices); 1943ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 1953ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 1963ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang }); 1973ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 1983ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 1993ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 2003ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang private void notifyAddressAllocated(SparseArray<HdmiCecLocalDevice> devices) { 2013ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang for (int i = 0; i < devices.size(); ++i) { 2023ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang int address = devices.keyAt(i); 2033ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang HdmiCecLocalDevice device = devices.valueAt(i); 2043ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang device.onAddressAllocated(address); 2053ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 2063ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 2073ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 208e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang /** 209e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * Returns {@link Looper} for IO operation. 210e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * 211e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * <p>Declared as package-private. 212e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang */ 213e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang Looper getIoLooper() { 214e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang return mIoThread.getLooper(); 215e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang } 216e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang 217e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang /** 218e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * Returns {@link Looper} of main thread. Use this {@link Looper} instance 219e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * for tasks that are running on main service thread. 220e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * 221e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * <p>Declared as package-private. 222e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang */ 223e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang Looper getServiceLooper() { 22467ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang return mHandler.getLooper(); 225e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang } 226c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim 227c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim /** 2283ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang * Returns physical address of the device. 2293ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang */ 2303ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang int getPhysicalAddress() { 2313ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang return mCecController.getPhysicalAddress(); 2323ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 2333ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 2343ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang /** 2353ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang * Returns vendor id of CEC service. 2363ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang */ 2373ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang int getVendorId() { 2383ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang return mCecController.getVendorId(); 2393ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 2403ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 2413ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang /** 242092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang * Returns version of CEC. 243092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang */ 244092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang int getCecVersion() { 245092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return mCecController.getVersion(); 246092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 247092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang 248092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang /** 2490f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang * Returns a list of {@link HdmiCecDeviceInfo}. 2500f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang * 2510f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang * @param includeLocalDevice whether to include local devices 2520f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang */ 2530f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang List<HdmiCecDeviceInfo> getDeviceInfoList(boolean includeLocalDevice) { 2540f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang assertRunOnServiceThread(); 2550f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang return mCecController.getDeviceInfoList(includeLocalDevice); 2560f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 2570f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang 2580f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang /** 25967ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang * Add and start a new {@link FeatureAction} to the action queue. 260c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * 26167ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang * @param action {@link FeatureAction} to add and start 262c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim */ 26367ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang void addAndStartAction(final FeatureAction action) { 26467ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang // TODO: may need to check the number of stale actions. 26567ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang runOnServiceThread(new Runnable() { 26667ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang @Override 26767ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang public void run() { 26867ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang mActions.add(action); 26967ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang action.start(); 27067ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang } 27167ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang }); 272c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim } 273c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim 2740f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang void setSystemAudioMode(boolean on) { 2750f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang synchronized (mLock) { 2760f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang mSystemAudioMode = on; 2770f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 2780f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 2790f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang 2800f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang boolean getSystemAudioMode() { 2810f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang synchronized (mLock) { 2820f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang return mSystemAudioMode; 2830f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 2840f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 2850f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang 2867fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim // See if we have an action of a given type in progress. 287092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang <T extends FeatureAction> boolean hasAction(final Class<T> clazz) { 2887fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim for (FeatureAction action : mActions) { 2897fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim if (action.getClass().equals(clazz)) { 2907fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim return true; 2917fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 2927fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 2937fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim return false; 2947fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 2957fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim 296c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim /** 297c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * Remove the given {@link FeatureAction} object from the action queue. 298c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * 29967ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang * @param action {@link FeatureAction} to remove 300c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim */ 30167ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang void removeAction(final FeatureAction action) { 30263a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo assertRunOnServiceThread(); 30363a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo mActions.remove(action); 30467ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang } 30567ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang 30667ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang // Remove all actions matched with the given Class type. 30767ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang private <T extends FeatureAction> void removeAction(final Class<T> clazz) { 30863a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo removeActionExcept(clazz, null); 30963a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo } 31063a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 31163a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo // Remove all actions matched with the given Class type besides |exception|. 31263a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo <T extends FeatureAction> void removeActionExcept(final Class<T> clazz, 31363a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo final FeatureAction exception) { 31463a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo assertRunOnServiceThread(); 31563a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo Iterator<FeatureAction> iter = mActions.iterator(); 31663a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo while (iter.hasNext()) { 31763a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo FeatureAction action = iter.next(); 31863a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo if (action != exception && action.getClass().equals(clazz)) { 31963a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo action.clear(); 32063a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo mActions.remove(action); 32167ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang } 32263a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo } 32367ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang } 32467ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang 32567ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang private void runOnServiceThread(Runnable runnable) { 32667ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang mHandler.post(runnable); 32767ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang } 32867ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang 32963a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo void runOnServiceThreadAtFrontOfQueue(Runnable runnable) { 33063a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo mHandler.postAtFrontOfQueue(runnable); 33163a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo } 33263a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 33363a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo private void assertRunOnServiceThread() { 33463a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo if (Looper.myLooper() != mHandler.getLooper()) { 33563a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo throw new IllegalStateException("Should run on service thread."); 33663a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo } 33763a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo } 33863a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 33967ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang /** 34067ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang * Change ARC status into the given {@code enabled} status. 34167ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang * 34267ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang * @return {@code true} if ARC was in "Enabled" status 34367ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang */ 34467ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang boolean setArcStatus(boolean enabled) { 345092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang assertRunOnServiceThread(); 3460f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang synchronized (mLock) { 3470f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang boolean oldStatus = mArcStatusEnabled; 3480f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang // 1. Enable/disable ARC circuit. 349092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang mCecController.setAudioReturnChannel(enabled); 350092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang 351092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang // TODO: notify arc mode change to AudioManager. 35267ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang 3530f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang // 2. Update arc status; 3540f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang mArcStatusEnabled = enabled; 3550f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang return oldStatus; 3560f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 357c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim } 358c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim 359c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim /** 360c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * Transmit a CEC command to CEC bus. 361c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * 362c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * @param command CEC command to send out 363d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang * @param callback interface used to the result of send command 364c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim */ 365d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang void sendCecCommand(HdmiCecMessage command, @Nullable SendMessageCallback callback) { 366d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang mCecController.sendCommand(command, callback); 367d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang } 368d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang 369d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang void sendCecCommand(HdmiCecMessage command) { 370d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang mCecController.sendCommand(command, null); 371c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim } 372c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim 373a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang boolean handleCecCommand(HdmiCecMessage message) { 374e81e108c4035ea8933525baa8108cb392f8abf5dJungshik Jang // Cache incoming message. Note that it caches only white-listed one. 375e81e108c4035ea8933525baa8108cb392f8abf5dJungshik Jang mCecMessageCache.cacheMessage(message); 376e81e108c4035ea8933525baa8108cb392f8abf5dJungshik Jang 377a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang // Commands that queries system information replies directly instead 378a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang // of creating FeatureAction because they are state-less. 379092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang // TODO: move the leftover message to local device. 380a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang switch (message.getOpcode()) { 38167ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang case HdmiCec.MESSAGE_INITIATE_ARC: 38267ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang handleInitiateArc(message); 38367ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang return true; 38467ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang case HdmiCec.MESSAGE_TERMINATE_ARC: 38567ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang handleTerminateArc(message); 38667ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang return true; 38763a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo case HdmiCec.MESSAGE_SET_SYSTEM_AUDIO_MODE: 38863a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo handleSetSystemAudioMode(message); 38963a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo return true; 39063a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo case HdmiCec.MESSAGE_SYSTEM_AUDIO_MODE_STATUS: 39163a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo handleSystemAudioModeStatus(message); 39263a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo return true; 393a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang default: 394092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang if (dispatchMessageToAction(message)) { 395092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return true; 396092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 397092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang break; 398a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang } 399092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang 400092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return dispatchMessageToLocalDevice(message); 401092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 402092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang 403092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang private boolean dispatchMessageToLocalDevice(HdmiCecMessage message) { 404092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) { 405092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang if (device.dispatchMessage(message)) { 406092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return true; 407092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 408092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 409092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return false; 410a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang } 411a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang 41267ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang /** 41367ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang * Called when a new hotplug event is issued. 41467ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang * 4158b308d93c8fdcc7304b33d9b445ae3807eae97c8Jungshik Jang * @param portNo hdmi port number where hot plug event issued. 41667ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang * @param connected whether to be plugged in or not 41767ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang */ 41867ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang void onHotplug(int portNo, boolean connected) { 41967ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang // TODO: Start "RequestArcInitiationAction" if ARC port. 42067ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang } 42167ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang 42202bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang /** 42302bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * Poll all remote devices. It sends <Polling Message> to all remote 42402bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * devices. 42502bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * 42602bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * @param callback an interface used to get a list of all remote devices' address 4270f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang * @param pickStrategy strategy how to pick polling candidates 42802bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * @param retryCount the number of retry used to send polling message to remote devices 4290f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang * @throw IllegalArgumentException if {@code pickStrategy} is invalid value 43002bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang */ 4310f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang void pollDevices(DevicePollingCallback callback, int pickStrategy, int retryCount) { 4320f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang mCecController.pollDevices(callback, checkPollStrategy(pickStrategy), retryCount); 4330f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 4340f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang 4350f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang private int checkPollStrategy(int pickStrategy) { 4360f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang int strategy = pickStrategy & POLL_STRATEGY_MASK; 4370f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang if (strategy == 0) { 4380f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang throw new IllegalArgumentException("Invalid poll strategy:" + pickStrategy); 4390f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 4400f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang int iterationStrategy = pickStrategy & POLL_ITERATION_STRATEGY_MASK; 4410f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang if (iterationStrategy == 0) { 4420f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang throw new IllegalArgumentException("Invalid iteration strategy:" + pickStrategy); 4430f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 4440f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang return strategy | iterationStrategy; 44502bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang } 44602bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang 4473ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang /** 4483ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang * Launch device discovery sequence. It starts with clearing the existing device info list. 4493ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang * Note that it assumes that logical address of all local devices is already allocated. 4503ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang * 4513ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang * @param sourceAddress a logical address of tv 4523ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang */ 4530f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang void launchDeviceDiscovery(final int sourceAddress) { 4543ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang // At first, clear all existing device infos. 4553ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang mCecController.clearDeviceInfoList(); 456092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang // TODO: flush cec message cache when CEC is turned off. 4573ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 4583ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang DeviceDiscoveryAction action = new DeviceDiscoveryAction(this, sourceAddress, 4593ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang new DeviceDiscoveryCallback() { 4603ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang @Override 4613ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang public void onDeviceDiscoveryDone(List<HdmiCecDeviceInfo> deviceInfos) { 4623ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang for (HdmiCecDeviceInfo info : deviceInfos) { 463a466929979a92a578d4ba00093fefa57cfb982b4Jungshik Jang addCecDevice(info); 4643ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 4653ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 4663ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang // Add device info of all local devices. 4673ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) { 468a466929979a92a578d4ba00093fefa57cfb982b4Jungshik Jang addCecDevice(device.getDeviceInfo()); 4693ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 4703ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 4710f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang addAndStartAction(new HotplugDetectionAction(HdmiControlService.this, 4720f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang sourceAddress)); 4733ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 4743ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang }); 4753ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang addAndStartAction(action); 4763ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 4773ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 4783ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang private HdmiCecDeviceInfo createDeviceInfo(int logicalAddress, int deviceType) { 4793ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang // TODO: get device name read from system configuration. 4803ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang String displayName = HdmiCec.getDefaultDeviceName(logicalAddress); 4813ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang return new HdmiCecDeviceInfo(logicalAddress, 4823ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang getPhysicalAddress(), deviceType, getVendorId(), displayName); 4833ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 4843ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 48567ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang private void handleInitiateArc(HdmiCecMessage message){ 48667ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang // In case where <Initiate Arc> is started by <Request ARC Initiation> 48767ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang // need to clean up RequestArcInitiationAction. 48867ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang removeAction(RequestArcInitiationAction.class); 48967ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang SetArcTransmissionStateAction action = new SetArcTransmissionStateAction(this, 49067ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang message.getDestination(), message.getSource(), true); 49167ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang addAndStartAction(action); 49267ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang } 49367ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang 49467ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang private void handleTerminateArc(HdmiCecMessage message) { 49567ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang // In case where <Terminate Arc> is started by <Request ARC Termination> 49667ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang // need to clean up RequestArcInitiationAction. 49767ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang // TODO: check conditions of power status by calling is_connected api 49867ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang // to be added soon. 49967ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang removeAction(RequestArcTerminationAction.class); 50067ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang SetArcTransmissionStateAction action = new SetArcTransmissionStateAction(this, 50167ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang message.getDestination(), message.getSource(), false); 50267ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang addAndStartAction(action); 50367ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang } 50467ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang 505c3923ea50dd0b161ba84941c071d34bb98c0700aJinsuk Kim private boolean dispatchMessageToAction(HdmiCecMessage message) { 506c3923ea50dd0b161ba84941c071d34bb98c0700aJinsuk Kim for (FeatureAction action : mActions) { 507c3923ea50dd0b161ba84941c071d34bb98c0700aJinsuk Kim if (action.processCommand(message)) { 508c3923ea50dd0b161ba84941c071d34bb98c0700aJinsuk Kim return true; 509c3923ea50dd0b161ba84941c071d34bb98c0700aJinsuk Kim } 510c3923ea50dd0b161ba84941c071d34bb98c0700aJinsuk Kim } 511c3923ea50dd0b161ba84941c071d34bb98c0700aJinsuk Kim Slog.w(TAG, "Unsupported cec command:" + message); 512c3923ea50dd0b161ba84941c071d34bb98c0700aJinsuk Kim return false; 513c3923ea50dd0b161ba84941c071d34bb98c0700aJinsuk Kim } 514c3923ea50dd0b161ba84941c071d34bb98c0700aJinsuk Kim 51563a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo private void handleSetSystemAudioMode(HdmiCecMessage message) { 51663a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo if (dispatchMessageToAction(message) || !isMessageForSystemAudio(message)) { 51763a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo return; 51863a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo } 51963a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo SystemAudioActionFromAvr action = new SystemAudioActionFromAvr(this, 52063a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo message.getDestination(), message.getSource(), 52163a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo HdmiUtils.parseCommandParamSystemAudioStatus(message)); 52263a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo addAndStartAction(action); 52363a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo } 52463a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 52563a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo private void handleSystemAudioModeStatus(HdmiCecMessage message) { 52663a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo if (!isMessageForSystemAudio(message)) { 52763a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo return; 52863a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo } 52963a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo setSystemAudioMode(HdmiUtils.parseCommandParamSystemAudioStatus(message)); 53063a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo } 53163a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 53263a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo private boolean isMessageForSystemAudio(HdmiCecMessage message) { 53363a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo if (message.getSource() != HdmiCec.ADDR_AUDIO_SYSTEM 53463a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo || message.getDestination() != HdmiCec.ADDR_TV 53563a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo || getAvrDeviceInfo() == null) { 53663a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo Slog.w(TAG, "Skip abnormal CecMessage: " + message); 53763a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo return false; 53863a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo } 53963a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo return true; 54063a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo } 54163a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 54278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // Record class that monitors the event of the caller of being killed. Used to clean up 54378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // the listener list and record list accordingly. 54478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final class HotplugEventListenerRecord implements IBinder.DeathRecipient { 54578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final IHdmiHotplugEventListener mListener; 54678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 54778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim public HotplugEventListenerRecord(IHdmiHotplugEventListener listener) { 54878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mListener = listener; 54978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 55078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 55178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 55278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim public void binderDied() { 55378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim synchronized (mLock) { 55478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListenerRecords.remove(this); 55578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListeners.remove(mListener); 55678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 55778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 55878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 55978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 560cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang void addCecDevice(HdmiCecDeviceInfo info) { 561cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang mCecController.addDeviceInfo(info); 562cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang } 563cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang 56478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private void enforceAccessPermission() { 56578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim getContext().enforceCallingOrSelfPermission(PERMISSION, TAG); 56678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 56778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 56878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final class BinderService extends IHdmiControlService.Stub { 56978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 57078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim public int[] getSupportedTypes() { 57178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 57278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim synchronized (mLock) { 57378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim return mLocalDevices; 57478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 57578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 57678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 57778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 5787fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void oneTouchPlay(final IHdmiControlCallback callback) { 57978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 5807fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim runOnServiceThread(new Runnable() { 5817fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim @Override 5827fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void run() { 5837fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim HdmiControlService.this.oneTouchPlay(callback); 5847fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 5857fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim }); 58678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 58778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 58878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 5897fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void queryDisplayStatus(final IHdmiControlCallback callback) { 59078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 5917fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim runOnServiceThread(new Runnable() { 5927fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim @Override 5937fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void run() { 5947fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim HdmiControlService.this.queryDisplayStatus(callback); 5957fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 5967fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim }); 59778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 59878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 59978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 6007fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void addHotplugEventListener(final IHdmiHotplugEventListener listener) { 60178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 6027fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim runOnServiceThread(new Runnable() { 6037fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim @Override 6047fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void run() { 6057fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim HdmiControlService.this.addHotplugEventListener(listener); 6067fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 6077fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim }); 60878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 60978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 61078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 6117fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void removeHotplugEventListener(final IHdmiHotplugEventListener listener) { 61278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 6137fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim runOnServiceThread(new Runnable() { 6147fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim @Override 6157fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void run() { 6167fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim HdmiControlService.this.removeHotplugEventListener(listener); 6177fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 6187fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim }); 61978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 62078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 62178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 62278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private void oneTouchPlay(IHdmiControlCallback callback) { 6237fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim if (hasAction(OneTouchPlayAction.class)) { 6247fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim Slog.w(TAG, "oneTouchPlay already in progress"); 6257fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim invokeCallback(callback, HdmiCec.RESULT_ALREADY_IN_PROGRESS); 6267fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim return; 6277fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 6287fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim HdmiCecLocalDevice source = mCecController.getLocalDevice(HdmiCec.DEVICE_PLAYBACK); 6297fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim if (source == null) { 6307fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim Slog.w(TAG, "Local playback device not available"); 6317fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim invokeCallback(callback, HdmiCec.RESULT_SOURCE_NOT_AVAILABLE); 6327fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim return; 6337fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 6347fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim // TODO: Consider the case of multiple TV sets. For now we always direct the command 6357fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim // to the primary one. 6367fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim OneTouchPlayAction action = OneTouchPlayAction.create(this, 6377fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim source.getDeviceInfo().getLogicalAddress(), 6387fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim source.getDeviceInfo().getPhysicalAddress(), HdmiCec.ADDR_TV, callback); 6397fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim if (action == null) { 6407fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim Slog.w(TAG, "Cannot initiate oneTouchPlay"); 6417fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim invokeCallback(callback, HdmiCec.RESULT_EXCEPTION); 6427fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim return; 6437fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 6447fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim addAndStartAction(action); 64578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 64678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 64778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private void queryDisplayStatus(IHdmiControlCallback callback) { 6487fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim if (hasAction(DevicePowerStatusAction.class)) { 6497fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim Slog.w(TAG, "queryDisplayStatus already in progress"); 6507fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim invokeCallback(callback, HdmiCec.RESULT_ALREADY_IN_PROGRESS); 6517fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim return; 6527fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 6537fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim HdmiCecLocalDevice source = mCecController.getLocalDevice(HdmiCec.DEVICE_PLAYBACK); 6547fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim if (source == null) { 6557fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim Slog.w(TAG, "Local playback device not available"); 6567fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim invokeCallback(callback, HdmiCec.RESULT_SOURCE_NOT_AVAILABLE); 6577fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim return; 6587fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 6597fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim DevicePowerStatusAction action = DevicePowerStatusAction.create(this, 6607fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim source.getDeviceInfo().getLogicalAddress(), HdmiCec.ADDR_TV, callback); 6617fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim if (action == null) { 6627fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim Slog.w(TAG, "Cannot initiate queryDisplayStatus"); 6637fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim invokeCallback(callback, HdmiCec.RESULT_EXCEPTION); 6647fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim return; 6657fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 6667fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim addAndStartAction(action); 66778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 66878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 66978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private void addHotplugEventListener(IHdmiHotplugEventListener listener) { 67078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim HotplugEventListenerRecord record = new HotplugEventListenerRecord(listener); 67178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim try { 67278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim listener.asBinder().linkToDeath(record, 0); 67378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } catch (RemoteException e) { 67478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim Slog.w(TAG, "Listener already died"); 67578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim return; 67678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 67778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim synchronized (mLock) { 67878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListenerRecords.add(record); 67978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListeners.add(listener); 68078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 68178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 68278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 68378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private void removeHotplugEventListener(IHdmiHotplugEventListener listener) { 68478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim synchronized (mLock) { 68578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim for (HotplugEventListenerRecord record : mHotplugEventListenerRecords) { 68678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim if (record.mListener.asBinder() == listener.asBinder()) { 68778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim listener.asBinder().unlinkToDeath(record, 0); 68878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListenerRecords.remove(record); 68978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim break; 69078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 69178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 69278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListeners.remove(listener); 69378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 69478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 6957fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim 6967fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim private void invokeCallback(IHdmiControlCallback callback, int result) { 6977fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim try { 6987fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim callback.onComplete(result); 6997fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } catch (RemoteException e) { 7007fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim Slog.e(TAG, "Invoking callback failed:" + e); 7017fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 7027fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 70363a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 70463a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo HdmiCecDeviceInfo getAvrDeviceInfo() { 70563a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo return mCecController.getDeviceInfo(HdmiCec.ADDR_AUDIO_SYSTEM); 70663a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo } 70763a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 70863a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo void setAudioStatus(boolean mute, int volume) { 70963a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo // TODO: Hook up with AudioManager. 71063a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo } 71163a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 71263a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo boolean isInPresetInstallationMode() { 71363a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo // TODO: Implement this. 71463a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo return false; 71563a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo } 716e81e108c4035ea8933525baa8108cb392f8abf5dJungshik Jang 717e81e108c4035ea8933525baa8108cb392f8abf5dJungshik Jang /** 718e81e108c4035ea8933525baa8108cb392f8abf5dJungshik Jang * Called when a device is removed or removal of device is detected. 719e81e108c4035ea8933525baa8108cb392f8abf5dJungshik Jang * 720e81e108c4035ea8933525baa8108cb392f8abf5dJungshik Jang * @param address a logical address of a device to be removed 721e81e108c4035ea8933525baa8108cb392f8abf5dJungshik Jang */ 722e81e108c4035ea8933525baa8108cb392f8abf5dJungshik Jang void removeCecDevice(int address) { 723e81e108c4035ea8933525baa8108cb392f8abf5dJungshik Jang mCecController.removeDeviceInfo(address); 724e81e108c4035ea8933525baa8108cb392f8abf5dJungshik Jang mCecMessageCache.flushMessagesFrom(address); 725e81e108c4035ea8933525baa8108cb392f8abf5dJungshik Jang } 726e81e108c4035ea8933525baa8108cb392f8abf5dJungshik Jang 727e81e108c4035ea8933525baa8108cb392f8abf5dJungshik Jang HdmiCecMessageCache getCecMessageCache() { 728e81e108c4035ea8933525baa8108cb392f8abf5dJungshik Jang return mCecMessageCache; 729e81e108c4035ea8933525baa8108cb392f8abf5dJungshik Jang } 7300792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang} 731