10f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang/* 20f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang * Copyright (C) 2014 The Android Open Source Project 30f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang * 40f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang * Licensed under the Apache License, Version 2.0 (the "License"); 50f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang * you may not use this file except in compliance with the License. 60f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang * You may obtain a copy of the License at 70f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang * 80f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang * http://www.apache.org/licenses/LICENSE-2.0 90f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang * 100f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang * Unless required by applicable law or agreed to in writing, software 110f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang * distributed under the License is distributed on an "AS IS" BASIS, 120f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 130f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang * See the License for the specific language governing permissions and 140f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang * limitations under the License. 150f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang */ 160f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang 170f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jangpackage com.android.server.hdmi; 180f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang 1961f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jangimport android.hardware.hdmi.HdmiDeviceInfo; 200f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jangimport android.util.Slog; 210f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang 220f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jangimport com.android.server.hdmi.HdmiControlService.DevicePollingCallback; 230f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang 240f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jangimport java.util.BitSet; 250f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jangimport java.util.List; 260f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang 270f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang/** 280f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang * Feature action that handles hot-plug detection mechanism. 290f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang * Hot-plug event is initiated by timer after device discovery action. 300f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang * 310f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang * <p>Check all devices every 15 secs except for system audio. 320f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang * If system audio is on, check hot-plug for audio system every 5 secs. 330f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang * For other devices, keep 15 secs period. 340f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang */ 35210d73df0b77b4c8be67ecc92afb238dc8c7ccfaJungshik Jang// Seq #3 36b509c2ecd99619248b7a07fb0fa978bb27f25cc3Jungshik Jangfinal class HotplugDetectionAction extends HdmiCecFeatureAction { 370f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang private static final String TAG = "HotPlugDetectionAction"; 380f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang 390f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang private static final int POLLING_INTERVAL_MS = 5000; 400f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang private static final int TIMEOUT_COUNT = 3; 4107600116b59e2accd1e95b9029c2c9819cd76c5aJinsuk Kim private static final int AVR_COUNT_MAX = 3; 420f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang 430f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang // State in which waits for next polling 440f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang private static final int STATE_WAIT_FOR_NEXT_POLLING = 1; 450f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang 460f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang // All addresses except for broadcast (unregistered address). 47c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim private static final int NUM_OF_ADDRESS = Constants.ADDR_SPECIFIC_USE 48c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim - Constants.ADDR_TV + 1; 490f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang 500f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang private int mTimeoutCount = 0; 510f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang 5207600116b59e2accd1e95b9029c2c9819cd76c5aJinsuk Kim // Counter used to ensure the connection to AVR is stable. Occasional failure to get 5307600116b59e2accd1e95b9029c2c9819cd76c5aJinsuk Kim // polling response from AVR despite its presence leads to unstable status flipping. 5407600116b59e2accd1e95b9029c2c9819cd76c5aJinsuk Kim // This is a workaround to deal with it, by removing the device only if the removal 5507600116b59e2accd1e95b9029c2c9819cd76c5aJinsuk Kim // is detected {@code AVR_COUNT_MAX} times in a row. 5607600116b59e2accd1e95b9029c2c9819cd76c5aJinsuk Kim private int mAvrStatusCount = 0; 5707600116b59e2accd1e95b9029c2c9819cd76c5aJinsuk Kim 580f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang /** 590f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang * Constructor 600f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang * 6179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang * @param source {@link HdmiCecLocalDevice} instance 620f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang */ 6379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang HotplugDetectionAction(HdmiCecLocalDevice source) { 6479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang super(source); 650f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 660f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang 670f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang @Override 680f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang boolean start() { 690f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang Slog.v(TAG, "Hot-plug dection started."); 700f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang 710f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang mState = STATE_WAIT_FOR_NEXT_POLLING; 720f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang mTimeoutCount = 0; 730f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang 740f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang // Start timer without polling. 750f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang // The first check for all devices will be initiated 15 seconds later. 760f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang addTimer(mState, POLLING_INTERVAL_MS); 770f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang return true; 780f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 790f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang 800f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang @Override 810f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang boolean processCommand(HdmiCecMessage cmd) { 820f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang // No-op 830f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang return false; 840f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 850f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang 860f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang @Override 870f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang void handleTimerEvent(int state) { 880f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang if (mState != state) { 890f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang return; 900f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 910f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang 920f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang if (mState == STATE_WAIT_FOR_NEXT_POLLING) { 930f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang mTimeoutCount = (mTimeoutCount + 1) % TIMEOUT_COUNT; 940f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang pollDevices(); 950f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 960f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 970f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang 9860cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang /** 9960cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang * Start device polling immediately. 10060cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang */ 10160cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang void pollAllDevicesNow() { 10260cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang // Clear existing timer to avoid overlapped execution 10360cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang mActionTimer.clearTimerMessage(); 10460cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 10560cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang mTimeoutCount = 0; 10660cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang mState = STATE_WAIT_FOR_NEXT_POLLING; 10760cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang pollAllDevices(); 10860cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 10960cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang addTimer(mState, POLLING_INTERVAL_MS); 11060cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 11160cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 1120f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang // This method is called every 5 seconds. 1130f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang private void pollDevices() { 1140f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang // All device check called every 15 seconds. 1150f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang if (mTimeoutCount == 0) { 1160f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang pollAllDevices(); 1170f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } else { 118377dcbd53af4529c352d453424539b069909fce4Jungshik Jang if (tv().isSystemAudioActivated()) { 1190f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang pollAudioSystem(); 1200f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 1210f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 1220f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang 1230f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang addTimer(mState, POLLING_INTERVAL_MS); 1240f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 1250f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang 1260f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang private void pollAllDevices() { 1270f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang Slog.v(TAG, "Poll all devices."); 1280f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang 12979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang pollDevices(new DevicePollingCallback() { 1300f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang @Override 1310f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang public void onPollingFinished(List<Integer> ackedAddress) { 1320f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang checkHotplug(ackedAddress, false); 1330f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 134c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim }, Constants.POLL_ITERATION_IN_ORDER 1355fba96df30b6b50b3cb9fe1d783320b1cc3bd6eaJinsuk Kim | Constants.POLL_STRATEGY_REMOTES_DEVICES, HdmiConfig.HOTPLUG_DETECTION_RETRY); 1360f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 1370f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang 1380f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang private void pollAudioSystem() { 1390f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang Slog.v(TAG, "Poll audio system."); 1400f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang 14179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang pollDevices(new DevicePollingCallback() { 1420f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang @Override 1430f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang public void onPollingFinished(List<Integer> ackedAddress) { 144a466929979a92a578d4ba00093fefa57cfb982b4Jungshik Jang checkHotplug(ackedAddress, true); 1450f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 146c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim }, Constants.POLL_ITERATION_IN_ORDER 1475fba96df30b6b50b3cb9fe1d783320b1cc3bd6eaJinsuk Kim | Constants.POLL_STRATEGY_SYSTEM_AUDIO, HdmiConfig.HOTPLUG_DETECTION_RETRY); 1480f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 1490f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang 1500f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang private void checkHotplug(List<Integer> ackedAddress, boolean audioOnly) { 15179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang BitSet currentInfos = infoListToBitSet(tv().getDeviceInfoList(false), audioOnly); 1520f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang BitSet polledResult = addressListToBitSet(ackedAddress); 1530f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang 1540f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang // At first, check removed devices. 1550f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang BitSet removed = complement(currentInfos, polledResult); 1560f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang int index = -1; 1570f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang while ((index = removed.nextSetBit(index + 1)) != -1) { 15807600116b59e2accd1e95b9029c2c9819cd76c5aJinsuk Kim if (index == Constants.ADDR_AUDIO_SYSTEM) { 1597b0cf6413218e5b5c549eea31733222fcffafabcJinsuk Kim HdmiDeviceInfo avr = tv().getAvrDeviceInfo(); 1607b0cf6413218e5b5c549eea31733222fcffafabcJinsuk Kim if (avr != null && tv().isConnected(avr.getPortId())) { 1617b0cf6413218e5b5c549eea31733222fcffafabcJinsuk Kim ++mAvrStatusCount; 1627b0cf6413218e5b5c549eea31733222fcffafabcJinsuk Kim Slog.w(TAG, "Ack not returned from AVR. count: " + mAvrStatusCount); 1637b0cf6413218e5b5c549eea31733222fcffafabcJinsuk Kim if (mAvrStatusCount < AVR_COUNT_MAX) { 1647b0cf6413218e5b5c549eea31733222fcffafabcJinsuk Kim continue; 1657b0cf6413218e5b5c549eea31733222fcffafabcJinsuk Kim } 16607600116b59e2accd1e95b9029c2c9819cd76c5aJinsuk Kim } 16707600116b59e2accd1e95b9029c2c9819cd76c5aJinsuk Kim } 1680f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang Slog.v(TAG, "Remove device by hot-plug detection:" + index); 1690f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang removeDevice(index); 1700f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 1710f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang 17207600116b59e2accd1e95b9029c2c9819cd76c5aJinsuk Kim // Reset the counter if the ack is returned from AVR. 17307600116b59e2accd1e95b9029c2c9819cd76c5aJinsuk Kim if (!removed.get(Constants.ADDR_AUDIO_SYSTEM)) { 17407600116b59e2accd1e95b9029c2c9819cd76c5aJinsuk Kim mAvrStatusCount = 0; 17507600116b59e2accd1e95b9029c2c9819cd76c5aJinsuk Kim } 17607600116b59e2accd1e95b9029c2c9819cd76c5aJinsuk Kim 1770f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang // Next, check added devices. 1780f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang BitSet added = complement(polledResult, currentInfos); 1790f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang index = -1; 1800f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang while ((index = added.nextSetBit(index + 1)) != -1) { 1810f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang Slog.v(TAG, "Add device by hot-plug detection:" + index); 1820f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang addDevice(index); 1830f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 1840f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 1850f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang 18661f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang private static BitSet infoListToBitSet(List<HdmiDeviceInfo> infoList, boolean audioOnly) { 1870f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang BitSet set = new BitSet(NUM_OF_ADDRESS); 18861f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang for (HdmiDeviceInfo info : infoList) { 1890f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang if (audioOnly) { 19061f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang if (info.getDeviceType() == HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM) { 1910f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang set.set(info.getLogicalAddress()); 1920f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 1930f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } else { 1940f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang set.set(info.getLogicalAddress()); 1950f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 1960f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 1970f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang return set; 1980f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 1990f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang 2000f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang private static BitSet addressListToBitSet(List<Integer> list) { 2010f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang BitSet set = new BitSet(NUM_OF_ADDRESS); 2020f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang for (Integer value : list) { 2030f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang set.set(value); 2040f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 2050f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang return set; 2060f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 2070f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang 2080f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang // A - B = A & ~B 2090f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang private static BitSet complement(BitSet first, BitSet second) { 2100f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang // Need to clone it so that it doesn't touch original set. 2110f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang BitSet clone = (BitSet) first.clone(); 2120f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang clone.andNot(second); 2130f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang return clone; 2140f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 2150f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang 2160f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang private void addDevice(int addedAddress) { 21726dc71e7feefb2417fd5f007af68614c1c197cf8Jungshik Jang // Sending <Give Physical Address> will initiate new device action. 21879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang sendCommand(HdmiCecMessageBuilder.buildGivePhysicalAddress(getSourceAddress(), 21979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang addedAddress)); 2200f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 2210f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang 2220f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang private void removeDevice(int removedAddress) { 22360cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang mayChangeRoutingPath(removedAddress); 22460cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang mayCancelDeviceSelect(removedAddress); 22560cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang mayCancelOneTouchRecord(removedAddress); 22660cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang mayDisableSystemAudioAndARC(removedAddress); 22760cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 22879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang tv().removeCecDevice(removedAddress); 22960cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 23060cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 23160cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang private void mayChangeRoutingPath(int address) { 2328960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim HdmiDeviceInfo info = tv().getCecDeviceInfo(address); 23326dc71e7feefb2417fd5f007af68614c1c197cf8Jungshik Jang if (info != null) { 23426dc71e7feefb2417fd5f007af68614c1c197cf8Jungshik Jang tv().handleRemoveActiveRoutingPath(info.getPhysicalAddress()); 23526dc71e7feefb2417fd5f007af68614c1c197cf8Jungshik Jang } 23660cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 23760cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 23860cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang private void mayCancelDeviceSelect(int address) { 23979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang List<DeviceSelectAction> actions = getActions(DeviceSelectAction.class); 24060cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang if (actions.isEmpty()) { 24160cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang return; 24260cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 24360cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 244c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo // Should have only one Device Select Action 24560cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang DeviceSelectAction action = actions.get(0); 24660cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang if (action.getTargetAddress() == address) { 24779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang removeAction(DeviceSelectAction.class); 24860cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 24960cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 25060cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 25160cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang private void mayCancelOneTouchRecord(int address) { 2523dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang List<OneTouchRecordAction> actions = getActions(OneTouchRecordAction.class); 2533dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang for (OneTouchRecordAction action : actions) { 2543dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang if (action.getRecorderAddress() == address) { 2553dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang removeAction(action); 2563dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang } 2573dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang } 25860cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 25960cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 26060cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang private void mayDisableSystemAudioAndARC(int address) { 26161f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang if (HdmiUtils.getTypeFromAddress(address) != HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM) { 26260cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang return; 26360cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 26460cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 265c1fa9afbcd1cafd205d46b2fd0bdaadccb7d29eaDonghyun Cho tv().setSystemAudioMode(false); 2665bcf5bf6b4203629e153dcb0646596e9b3f7c7c2Jinsuk Kim if (tv().isArcEstablished()) { 267bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho tv().enableAudioReturnChannel(false); 26879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang addAndStartAction(new RequestArcTerminationAction(localDevice(), address)); 26960cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 2700f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 2710f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang} 272