HdmiUtils.java revision 92b77cf9cbf512e7141cad6fef5a38d0682dde43
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
1963a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heoimport android.hardware.hdmi.HdmiCec;
2063a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heoimport android.hardware.hdmi.HdmiCecMessage;
2163a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heoimport android.util.Slog;
2279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jangimport android.util.SparseArray;
2363a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo
240340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kimimport java.util.ArrayList;
250340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kimimport java.util.Collections;
260340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kimimport java.util.List;
270340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim
2863a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo/**
2963a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo * Various utilities to handle HDMI CEC messages.
3063a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo */
3163a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heofinal class HdmiUtils {
3263a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo
3363a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo    private HdmiUtils() { /* cannot be instantiated */ }
3463a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo
3563a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo    /**
3663a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo     * Verify if the given address is for the given device type.  If not it will throw
3763a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo     * {@link IllegalArgumentException}.
3863a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo     *
3963a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo     * @param logicalAddress the logical address to verify
4063a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo     * @param deviceType the device type to check
4163a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo     * @throw IllegalArgumentException
4263a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo     */
4363a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo    static void verifyAddressType(int logicalAddress, int deviceType) {
4463a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo        int actualDeviceType = HdmiCec.getTypeFromAddress(logicalAddress);
4563a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo        if (actualDeviceType != deviceType) {
4663a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo            throw new IllegalArgumentException("Device type missmatch:[Expected:" + deviceType
4763a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo                    + ", Actual:" + actualDeviceType);
4863a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo        }
4963a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo    }
5063a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo
5163a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo    /**
5263a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo     * Check if the given CEC message come from the given address.
5363a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo     *
5463a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo     * @param cmd the CEC message to check
5563a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo     * @param expectedAddress the expected source address of the given message
5663a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo     * @param tag the tag of caller module (for log message)
5763a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo     * @return true if the CEC message comes from the given address
5863a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo     */
5963a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo    static boolean checkCommandSource(HdmiCecMessage cmd, int expectedAddress, String tag) {
6063a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo        int src = cmd.getSource();
6163a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo        if (src != expectedAddress) {
6263a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo            Slog.w(tag, "Invalid source [Expected:" + expectedAddress + ", Actual:" + src + "]");
6363a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo            return false;
6463a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo        }
6563a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo        return true;
6663a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo    }
6763a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo
6863a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo    /**
6963a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo     * Parse the parameter block of CEC message as [System Audio Status].
7063a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo     *
7163a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo     * @param cmd the CEC message to parse
7263a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo     * @return true if the given parameter has [ON] value
7363a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo     */
7463a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo    static boolean parseCommandParamSystemAudioStatus(HdmiCecMessage cmd) {
7563a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo        // TODO: Handle the exception when the length is wrong.
7663a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo        return cmd.getParams().length > 0
7763a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo                && cmd.getParams()[0] == HdmiConstants.SYSTEM_AUDIO_STATUS_ON;
7863a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo    }
79092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang
80092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang    /**
810340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim     * Convert integer array to list of {@link Integer}.
820340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim     *
830340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim     * <p>The result is immutable.
840340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim     *
850340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim     * @param is integer array
860340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim     * @return {@link List} instance containing the elements in the given array
870340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim     */
880340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim    static List<Integer> asImmutableList(final int[] is) {
890340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim        ArrayList<Integer> list = new ArrayList<>(is.length);
900340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim        for (int type : is) {
910340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim            list.add(type);
920340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim        }
930340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim        return Collections.unmodifiableList(list);
940340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim    }
950340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim
960340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim    /**
97092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang     * Assemble two bytes into single integer value.
98092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang     *
99092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang     * @param data to be assembled
100092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang     * @return assembled value
101092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang     */
102092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang    static int twoBytesToInt(byte[] data) {
103092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang        return ((data[0] & 0xFF) << 8) | (data[1] & 0xFF);
104092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang    }
105092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang
106092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang    /**
10792b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim     * Assemble two bytes into single integer value.
10892b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim     *
10992b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim     * @param data to be assembled
11092b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim     * @param offset offset to the data to convert in the array
11192b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim     * @return assembled value
11292b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim     */
11392b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim    static int twoBytesToInt(byte[] data, int offset) {
11492b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim        return ((data[offset] & 0xFF) << 8) | (data[offset + 1] & 0xFF);
11592b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim    }
11692b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim
11792b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim    /**
118092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang     * Assemble three bytes into single integer value.
119092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang     *
120092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang     * @param data to be assembled
121092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang     * @return assembled value
122092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang     */
123092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang    static int threeBytesToInt(byte[] data) {
124092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang        return ((data[0] & 0xFF) << 16) | ((data[1] & 0xFF) << 8) | (data[2] & 0xFF);
125092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang    }
12679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
12779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    static <T> List<T> sparseArrayToList(SparseArray<T> array) {
12879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        ArrayList<T> list = new ArrayList<>();
12979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        for (int i = 0; i < array.size(); ++i) {
13079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang            list.add(array.valueAt(i));
13179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        }
13279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        return list;
13379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    }
13479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
13592b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim    /**
13692b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim     * See if the new path is affecting the active path.
13792b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim     *
13892b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim     * @param activePath current active path
13992b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim     * @param newPath new path
14092b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim     * @return true if the new path changes the current active path
14192b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim     */
14292b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim    static boolean isAffectingActiveRoutingPath(int activePath, int newPath) {
14392b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim        // The new path affects the current active path if the parent of the new path
14492b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim        // is an ancestor of the active path.
14592b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim        // (1.1.0.0, 2.0.0.0) -> true, new path alters the parent
14692b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim        // (1.1.0.0, 1.2.0.0) -> true, new path is a sibling
14792b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim        // (1.1.0.0, 1.2.1.0) -> false, new path is a descendant of a sibling
14892b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim        // (1.0.0.0, 3.2.0.0) -> false, in a completely different path
14992b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim
15092b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim        // Get the parent of the new path by clearing the least significant
15192b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim        // non-zero nibble.
15292b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim        for (int i = 0; i <= 12; i += 4) {
15392b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim            int nibble = (newPath >> i) & 0xF;
15492b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim            if (nibble != 0) {
15592b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim                int mask = 0xFFF0 << i;
15692b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim                newPath &= mask;
15792b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim                break;
15892b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim            }
15992b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim        }
16092b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim        if (newPath == 0x0000) {
16192b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim            return true;  // Top path always affects the active path
16292b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim        }
16392b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim        return isInActiveRoutingPath(activePath, newPath);
16492b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim    }
16592b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim
16692b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim    /**
16792b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim     * See if the new path is in the active path.
16892b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim     *
16992b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim     * @param activePath current active path
17092b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim     * @param newPath new path
17192b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim     * @return true if the new path in the active routing path
17292b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim     */
17392b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim    static boolean isInActiveRoutingPath(int activePath, int newPath) {
17492b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim        // Check each nibble of the currently active path and the new path till the position
17592b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim        // where the active nibble is not zero. For (activePath, newPath),
17692b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim        // (1.1.0.0, 1.0.0.0) -> true, new path is a parent
17792b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim        // (1.2.1.0, 1.2.1.2) -> true, new path is a descendant
17892b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim        // (1.1.0.0, 1.2.0.0) -> false, new path is a sibling
17992b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim        // (1.0.0.0, 2.0.0.0) -> false, in a completely different path
18092b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim        for (int i = 12; i >= 0; i -= 4) {
18192b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim            int nibbleActive = (activePath >> i) & 0xF;
18292b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim            if (nibbleActive == 0) {
18392b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim                break;
18492b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim            }
18592b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim            int nibbleNew = (newPath >> i) & 0xF;
18692b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim            if (nibbleNew == 0) {
18792b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim                break;
18892b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim            }
18992b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim            if (nibbleActive != nibbleNew) {
19092b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim                return false;
19192b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim            }
19292b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim        }
19392b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim        return true;
19492b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim    }
19592b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim
19663a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo}
197