163a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo/* 263a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo * Copyright (C) 2014 The Android Open Source Project 363a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo * 463a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo * Licensed under the Apache License, Version 2.0 (the "License"); 563a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo * you may not use this file except in compliance with the License. 663a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo * You may obtain a copy of the License at 763a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo * 863a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo * http://www.apache.org/licenses/LICENSE-2.0 963a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo * 1063a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo * Unless required by applicable law or agreed to in writing, software 1163a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo * distributed under the License is distributed on an "AS IS" BASIS, 1263a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1363a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo * See the License for the specific language governing permissions and 1463a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo * limitations under the License. 1563a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo */ 1663a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 1763a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heopackage com.android.server.hdmi; 1863a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 1961f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jangimport android.hardware.hdmi.HdmiDeviceInfo; 2063a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heoimport android.util.Slog; 2179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jangimport android.util.SparseArray; 2263a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 230340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kimimport java.util.ArrayList; 240340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kimimport java.util.Collections; 250340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kimimport java.util.List; 260340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 2763a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo/** 2863a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo * Various utilities to handle HDMI CEC messages. 2963a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo */ 3063a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heofinal class HdmiUtils { 3163a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 32c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim private static final int[] ADDRESS_TO_TYPE = { 3361f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang HdmiDeviceInfo.DEVICE_TV, // ADDR_TV 3461f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang HdmiDeviceInfo.DEVICE_RECORDER, // ADDR_RECORDER_1 3561f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang HdmiDeviceInfo.DEVICE_RECORDER, // ADDR_RECORDER_2 3661f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang HdmiDeviceInfo.DEVICE_TUNER, // ADDR_TUNER_1 3761f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang HdmiDeviceInfo.DEVICE_PLAYBACK, // ADDR_PLAYBACK_1 3861f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM, // ADDR_AUDIO_SYSTEM 3961f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang HdmiDeviceInfo.DEVICE_TUNER, // ADDR_TUNER_2 4061f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang HdmiDeviceInfo.DEVICE_TUNER, // ADDR_TUNER_3 4161f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang HdmiDeviceInfo.DEVICE_PLAYBACK, // ADDR_PLAYBACK_2 4261f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang HdmiDeviceInfo.DEVICE_RECORDER, // ADDR_RECORDER_3 4361f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang HdmiDeviceInfo.DEVICE_TUNER, // ADDR_TUNER_4 4461f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang HdmiDeviceInfo.DEVICE_PLAYBACK, // ADDR_PLAYBACK_3 4561f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang HdmiDeviceInfo.DEVICE_RESERVED, 4661f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang HdmiDeviceInfo.DEVICE_RESERVED, 4761f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang HdmiDeviceInfo.DEVICE_TV, // ADDR_SPECIFIC_USE 48c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim }; 49c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim 50c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim private static final String[] DEFAULT_NAMES = { 51c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim "TV", 52c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim "Recorder_1", 53c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim "Recorder_2", 54c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim "Tuner_1", 55c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim "Playback_1", 56c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim "AudioSystem", 57c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim "Tuner_2", 58c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim "Tuner_3", 59c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim "Playback_2", 60c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim "Recorder_3", 61c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim "Tuner_4", 62c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim "Playback_3", 63c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim "Reserved_1", 64c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim "Reserved_2", 65c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim "Secondary_TV", 66c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim }; 67c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim 6863a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo private HdmiUtils() { /* cannot be instantiated */ } 6963a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 7063a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo /** 71c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim * Check if the given logical address is valid. A logical address is valid 72c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim * if it is one allocated for an actual device which allows communication 73c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim * with other logical devices. 74c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim * 75c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim * @param address logical address 76c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim * @return true if the given address is valid 77c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim */ 78c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim static boolean isValidAddress(int address) { 79c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim return (Constants.ADDR_TV <= address && address <= Constants.ADDR_SPECIFIC_USE); 80c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim } 81c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim 82c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim /** 83c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim * Return the device type for the given logical address. 84c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim * 85c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim * @param address logical address 86c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim * @return device type for the given logical address; DEVICE_INACTIVE 87c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim * if the address is not valid. 88c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim */ 89c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim static int getTypeFromAddress(int address) { 90c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim if (isValidAddress(address)) { 91c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim return ADDRESS_TO_TYPE[address]; 92c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim } 9361f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang return HdmiDeviceInfo.DEVICE_INACTIVE; 94c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim } 95c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim 96c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim /** 97c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim * Return the default device name for a logical address. This is the name 98c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim * by which the logical device is known to others until a name is 99c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim * set explicitly using HdmiCecService.setOsdName. 100c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim * 101c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim * @param address logical address 102c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim * @return default device name; empty string if the address is not valid 103c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim */ 104c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim static String getDefaultDeviceName(int address) { 105c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim if (isValidAddress(address)) { 106c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim return DEFAULT_NAMES[address]; 107c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim } 108c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim return ""; 109c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim } 110c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim 111c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim /** 11263a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo * Verify if the given address is for the given device type. If not it will throw 11363a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo * {@link IllegalArgumentException}. 11463a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo * 11563a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo * @param logicalAddress the logical address to verify 11663a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo * @param deviceType the device type to check 11763a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo * @throw IllegalArgumentException 11863a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo */ 11963a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo static void verifyAddressType(int logicalAddress, int deviceType) { 120c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim int actualDeviceType = getTypeFromAddress(logicalAddress); 12163a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo if (actualDeviceType != deviceType) { 12263a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo throw new IllegalArgumentException("Device type missmatch:[Expected:" + deviceType 12363a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo + ", Actual:" + actualDeviceType); 12463a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo } 12563a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo } 12663a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 12763a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo /** 12863a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo * Check if the given CEC message come from the given address. 12963a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo * 13063a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo * @param cmd the CEC message to check 13163a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo * @param expectedAddress the expected source address of the given message 13263a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo * @param tag the tag of caller module (for log message) 13363a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo * @return true if the CEC message comes from the given address 13463a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo */ 13563a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo static boolean checkCommandSource(HdmiCecMessage cmd, int expectedAddress, String tag) { 13663a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo int src = cmd.getSource(); 13763a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo if (src != expectedAddress) { 13863a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo Slog.w(tag, "Invalid source [Expected:" + expectedAddress + ", Actual:" + src + "]"); 13963a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo return false; 14063a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo } 14163a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo return true; 14263a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo } 14363a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 14463a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo /** 14563a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo * Parse the parameter block of CEC message as [System Audio Status]. 14663a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo * 14763a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo * @param cmd the CEC message to parse 14863a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo * @return true if the given parameter has [ON] value 14963a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo */ 15063a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo static boolean parseCommandParamSystemAudioStatus(HdmiCecMessage cmd) { 15175a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo return cmd.getParams()[0] == Constants.SYSTEM_AUDIO_STATUS_ON; 15263a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo } 153092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang 154092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang /** 1550340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim * Convert integer array to list of {@link Integer}. 1560340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim * 1570340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim * <p>The result is immutable. 1580340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim * 1590340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim * @param is integer array 1600340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim * @return {@link List} instance containing the elements in the given array 1610340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim */ 1620340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim static List<Integer> asImmutableList(final int[] is) { 1630340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim ArrayList<Integer> list = new ArrayList<>(is.length); 1640340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim for (int type : is) { 1650340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim list.add(type); 1660340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 1670340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim return Collections.unmodifiableList(list); 1680340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 1690340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 1700340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim /** 171092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang * Assemble two bytes into single integer value. 172092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang * 173092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang * @param data to be assembled 174092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang * @return assembled value 175092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang */ 176092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang static int twoBytesToInt(byte[] data) { 177092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return ((data[0] & 0xFF) << 8) | (data[1] & 0xFF); 178092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 179092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang 180092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang /** 18192b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim * Assemble two bytes into single integer value. 18292b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim * 18392b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim * @param data to be assembled 18492b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim * @param offset offset to the data to convert in the array 18592b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim * @return assembled value 18692b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim */ 18792b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim static int twoBytesToInt(byte[] data, int offset) { 18892b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim return ((data[offset] & 0xFF) << 8) | (data[offset + 1] & 0xFF); 18992b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 19092b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim 19192b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim /** 192092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang * Assemble three bytes into single integer value. 193092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang * 194092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang * @param data to be assembled 195092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang * @return assembled value 196092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang */ 197092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang static int threeBytesToInt(byte[] data) { 198092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return ((data[0] & 0xFF) << 16) | ((data[1] & 0xFF) << 8) | (data[2] & 0xFF); 199092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 20079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 20179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang static <T> List<T> sparseArrayToList(SparseArray<T> array) { 20279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang ArrayList<T> list = new ArrayList<>(); 20379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang for (int i = 0; i < array.size(); ++i) { 20479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang list.add(array.valueAt(i)); 20579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 20679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return list; 20779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 20879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 209ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim static <T> List<T> mergeToUnmodifiableList(List<T> a, List<T> b) { 210ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim if (a.isEmpty() && b.isEmpty()) { 211ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim return Collections.emptyList(); 212ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim } 213ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim if (a.isEmpty()) { 214ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim return Collections.unmodifiableList(b); 215ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim } 216ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim if (b.isEmpty()) { 217ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim return Collections.unmodifiableList(a); 218ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim } 219ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim List<T> newList = new ArrayList<>(); 220ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim newList.addAll(a); 221ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim newList.addAll(b); 222ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim return Collections.unmodifiableList(newList); 223ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim } 224ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim 22592b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim /** 22692b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim * See if the new path is affecting the active path. 22792b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim * 22892b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim * @param activePath current active path 22992b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim * @param newPath new path 23092b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim * @return true if the new path changes the current active path 23192b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim */ 23292b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim static boolean isAffectingActiveRoutingPath(int activePath, int newPath) { 23392b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim // The new path affects the current active path if the parent of the new path 23492b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim // is an ancestor of the active path. 23592b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim // (1.1.0.0, 2.0.0.0) -> true, new path alters the parent 23692b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim // (1.1.0.0, 1.2.0.0) -> true, new path is a sibling 23792b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim // (1.1.0.0, 1.2.1.0) -> false, new path is a descendant of a sibling 23892b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim // (1.0.0.0, 3.2.0.0) -> false, in a completely different path 23992b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim 24092b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim // Get the parent of the new path by clearing the least significant 24192b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim // non-zero nibble. 24292b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim for (int i = 0; i <= 12; i += 4) { 24392b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim int nibble = (newPath >> i) & 0xF; 24492b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim if (nibble != 0) { 24592b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim int mask = 0xFFF0 << i; 24692b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim newPath &= mask; 24792b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim break; 24892b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 24992b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 25092b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim if (newPath == 0x0000) { 25192b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim return true; // Top path always affects the active path 25292b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 25392b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim return isInActiveRoutingPath(activePath, newPath); 25492b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 25592b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim 25692b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim /** 25792b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim * See if the new path is in the active path. 25892b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim * 25992b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim * @param activePath current active path 26092b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim * @param newPath new path 26192b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim * @return true if the new path in the active routing path 26292b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim */ 26392b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim static boolean isInActiveRoutingPath(int activePath, int newPath) { 26492b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim // Check each nibble of the currently active path and the new path till the position 26592b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim // where the active nibble is not zero. For (activePath, newPath), 26692b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim // (1.1.0.0, 1.0.0.0) -> true, new path is a parent 26792b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim // (1.2.1.0, 1.2.1.2) -> true, new path is a descendant 26892b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim // (1.1.0.0, 1.2.0.0) -> false, new path is a sibling 26992b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim // (1.0.0.0, 2.0.0.0) -> false, in a completely different path 27092b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim for (int i = 12; i >= 0; i -= 4) { 27192b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim int nibbleActive = (activePath >> i) & 0xF; 27292b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim if (nibbleActive == 0) { 27392b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim break; 27492b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 27592b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim int nibbleNew = (newPath >> i) & 0xF; 27692b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim if (nibbleNew == 0) { 27792b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim break; 27892b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 27992b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim if (nibbleActive != nibbleNew) { 28092b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim return false; 28192b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 28292b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 28392b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim return true; 28492b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 285410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang 286410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang /** 287410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang * Clone {@link HdmiDeviceInfo} with new power status. 288410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang */ 289410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang static HdmiDeviceInfo cloneHdmiDeviceInfo(HdmiDeviceInfo info, int newPowerStatus) { 290410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang return new HdmiDeviceInfo(info.getLogicalAddress(), 291410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang info.getPhysicalAddress(), info.getPortId(), info.getDeviceType(), 292410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang info.getVendorId(), info.getDisplayName(), newPowerStatus); 293410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang } 294410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang 2955b8cb00b8a302329b98a5528eaa7934d0f5c3e65Jinsuk Kim /** 2965b8cb00b8a302329b98a5528eaa7934d0f5c3e65Jinsuk Kim * Convert 3 byte-long language code in string to integer representation. 2975b8cb00b8a302329b98a5528eaa7934d0f5c3e65Jinsuk Kim * English(eng), for example, is converted to 0x656e67. 2985b8cb00b8a302329b98a5528eaa7934d0f5c3e65Jinsuk Kim * 2995b8cb00b8a302329b98a5528eaa7934d0f5c3e65Jinsuk Kim * @param language language code in string 3005b8cb00b8a302329b98a5528eaa7934d0f5c3e65Jinsuk Kim * @return language code in integer representation 3015b8cb00b8a302329b98a5528eaa7934d0f5c3e65Jinsuk Kim */ 3025b8cb00b8a302329b98a5528eaa7934d0f5c3e65Jinsuk Kim static int languageToInt(String language) { 3035b8cb00b8a302329b98a5528eaa7934d0f5c3e65Jinsuk Kim String normalized = language.toLowerCase(); 3045b8cb00b8a302329b98a5528eaa7934d0f5c3e65Jinsuk Kim return ((normalized.charAt(0) & 0xFF) << 16) 3055b8cb00b8a302329b98a5528eaa7934d0f5c3e65Jinsuk Kim | ((normalized.charAt(1) & 0xFF) << 8) 3065b8cb00b8a302329b98a5528eaa7934d0f5c3e65Jinsuk Kim | (normalized.charAt(2) & 0xFF); 3075b8cb00b8a302329b98a5528eaa7934d0f5c3e65Jinsuk Kim } 30863a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo} 309