HdmiUtils.java revision 92b77cf9cbf512e7141cad6fef5a38d0682dde43
1/* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.server.hdmi; 18 19import android.hardware.hdmi.HdmiCec; 20import android.hardware.hdmi.HdmiCecMessage; 21import android.util.Slog; 22import android.util.SparseArray; 23 24import java.util.ArrayList; 25import java.util.Collections; 26import java.util.List; 27 28/** 29 * Various utilities to handle HDMI CEC messages. 30 */ 31final class HdmiUtils { 32 33 private HdmiUtils() { /* cannot be instantiated */ } 34 35 /** 36 * Verify if the given address is for the given device type. If not it will throw 37 * {@link IllegalArgumentException}. 38 * 39 * @param logicalAddress the logical address to verify 40 * @param deviceType the device type to check 41 * @throw IllegalArgumentException 42 */ 43 static void verifyAddressType(int logicalAddress, int deviceType) { 44 int actualDeviceType = HdmiCec.getTypeFromAddress(logicalAddress); 45 if (actualDeviceType != deviceType) { 46 throw new IllegalArgumentException("Device type missmatch:[Expected:" + deviceType 47 + ", Actual:" + actualDeviceType); 48 } 49 } 50 51 /** 52 * Check if the given CEC message come from the given address. 53 * 54 * @param cmd the CEC message to check 55 * @param expectedAddress the expected source address of the given message 56 * @param tag the tag of caller module (for log message) 57 * @return true if the CEC message comes from the given address 58 */ 59 static boolean checkCommandSource(HdmiCecMessage cmd, int expectedAddress, String tag) { 60 int src = cmd.getSource(); 61 if (src != expectedAddress) { 62 Slog.w(tag, "Invalid source [Expected:" + expectedAddress + ", Actual:" + src + "]"); 63 return false; 64 } 65 return true; 66 } 67 68 /** 69 * Parse the parameter block of CEC message as [System Audio Status]. 70 * 71 * @param cmd the CEC message to parse 72 * @return true if the given parameter has [ON] value 73 */ 74 static boolean parseCommandParamSystemAudioStatus(HdmiCecMessage cmd) { 75 // TODO: Handle the exception when the length is wrong. 76 return cmd.getParams().length > 0 77 && cmd.getParams()[0] == HdmiConstants.SYSTEM_AUDIO_STATUS_ON; 78 } 79 80 /** 81 * Convert integer array to list of {@link Integer}. 82 * 83 * <p>The result is immutable. 84 * 85 * @param is integer array 86 * @return {@link List} instance containing the elements in the given array 87 */ 88 static List<Integer> asImmutableList(final int[] is) { 89 ArrayList<Integer> list = new ArrayList<>(is.length); 90 for (int type : is) { 91 list.add(type); 92 } 93 return Collections.unmodifiableList(list); 94 } 95 96 /** 97 * Assemble two bytes into single integer value. 98 * 99 * @param data to be assembled 100 * @return assembled value 101 */ 102 static int twoBytesToInt(byte[] data) { 103 return ((data[0] & 0xFF) << 8) | (data[1] & 0xFF); 104 } 105 106 /** 107 * Assemble two bytes into single integer value. 108 * 109 * @param data to be assembled 110 * @param offset offset to the data to convert in the array 111 * @return assembled value 112 */ 113 static int twoBytesToInt(byte[] data, int offset) { 114 return ((data[offset] & 0xFF) << 8) | (data[offset + 1] & 0xFF); 115 } 116 117 /** 118 * Assemble three bytes into single integer value. 119 * 120 * @param data to be assembled 121 * @return assembled value 122 */ 123 static int threeBytesToInt(byte[] data) { 124 return ((data[0] & 0xFF) << 16) | ((data[1] & 0xFF) << 8) | (data[2] & 0xFF); 125 } 126 127 static <T> List<T> sparseArrayToList(SparseArray<T> array) { 128 ArrayList<T> list = new ArrayList<>(); 129 for (int i = 0; i < array.size(); ++i) { 130 list.add(array.valueAt(i)); 131 } 132 return list; 133 } 134 135 /** 136 * See if the new path is affecting the active path. 137 * 138 * @param activePath current active path 139 * @param newPath new path 140 * @return true if the new path changes the current active path 141 */ 142 static boolean isAffectingActiveRoutingPath(int activePath, int newPath) { 143 // The new path affects the current active path if the parent of the new path 144 // is an ancestor of the active path. 145 // (1.1.0.0, 2.0.0.0) -> true, new path alters the parent 146 // (1.1.0.0, 1.2.0.0) -> true, new path is a sibling 147 // (1.1.0.0, 1.2.1.0) -> false, new path is a descendant of a sibling 148 // (1.0.0.0, 3.2.0.0) -> false, in a completely different path 149 150 // Get the parent of the new path by clearing the least significant 151 // non-zero nibble. 152 for (int i = 0; i <= 12; i += 4) { 153 int nibble = (newPath >> i) & 0xF; 154 if (nibble != 0) { 155 int mask = 0xFFF0 << i; 156 newPath &= mask; 157 break; 158 } 159 } 160 if (newPath == 0x0000) { 161 return true; // Top path always affects the active path 162 } 163 return isInActiveRoutingPath(activePath, newPath); 164 } 165 166 /** 167 * See if the new path is in the active path. 168 * 169 * @param activePath current active path 170 * @param newPath new path 171 * @return true if the new path in the active routing path 172 */ 173 static boolean isInActiveRoutingPath(int activePath, int newPath) { 174 // Check each nibble of the currently active path and the new path till the position 175 // where the active nibble is not zero. For (activePath, newPath), 176 // (1.1.0.0, 1.0.0.0) -> true, new path is a parent 177 // (1.2.1.0, 1.2.1.2) -> true, new path is a descendant 178 // (1.1.0.0, 1.2.0.0) -> false, new path is a sibling 179 // (1.0.0.0, 2.0.0.0) -> false, in a completely different path 180 for (int i = 12; i >= 0; i -= 4) { 181 int nibbleActive = (activePath >> i) & 0xF; 182 if (nibbleActive == 0) { 183 break; 184 } 185 int nibbleNew = (newPath >> i) & 0xF; 186 if (nibbleNew == 0) { 187 break; 188 } 189 if (nibbleActive != nibbleNew) { 190 return false; 191 } 192 } 193 return true; 194 } 195 196} 197