diff options
| author | 2018-11-29 16:36:52 -0800 | |
|---|---|---|
| committer | 2019-01-16 15:24:40 -0800 | |
| commit | 19ccf61302b31fe61a500a9f7636a855fcc7e8c9 (patch) | |
| tree | 221568ffdcc116461575855e347ac03bd4013bf3 | |
| parent | aa8ae68c65092754f2b352b8b57281343790135a (diff) | |
Deprecate isConnectedToHdmiSwitch
ag/5655140
Bug: 120108729
Test: make; local tests
Change-Id: I889e267ec120f8e6fedc8cd8ab80b68b3a6fb6f5
| -rw-r--r-- | core/java/android/hardware/hdmi/HdmiUtils.java | 172 | ||||
| -rw-r--r-- | core/tests/hdmitests/Android.mk | 2 | ||||
| -rw-r--r-- | core/tests/hdmitests/src/android/hardware/hdmi/HdmiUtilsTest.java | 145 | ||||
| -rw-r--r-- | media/java/android/media/tv/TvInputInfo.java | 45 |
4 files changed, 355 insertions, 9 deletions
diff --git a/core/java/android/hardware/hdmi/HdmiUtils.java b/core/java/android/hardware/hdmi/HdmiUtils.java index 308173816f13..8c94b7841a80 100644 --- a/core/java/android/hardware/hdmi/HdmiUtils.java +++ b/core/java/android/hardware/hdmi/HdmiUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014 The Android Open Source Project + * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,14 +16,18 @@ package android.hardware.hdmi; +import android.annotation.IntDef; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + /** - * Various utilities to handle HDMI CEC messages. + * Various utilities related to HDMI CEC. * * TODO(b/110094868): unhide for Q * @hide */ -public class HdmiUtils { - +public final class HdmiUtils { /** * Return value of {@link #getLocalPortFromPhysicalAddress(int, int)} */ @@ -78,4 +82,164 @@ public class HdmiUtils { } return port; } + + /** + * TODO(b/110094868): unhide for Q + * @hide + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef({HDMI_RELATIVE_POSITION_UNKNOWN, HDMI_RELATIVE_POSITION_DIRECTLY_BELOW, + HDMI_RELATIVE_POSITION_BELOW, HDMI_RELATIVE_POSITION_SAME, + HDMI_RELATIVE_POSITION_DIRECTLY_ABOVE, HDMI_RELATIVE_POSITION_ABOVE, + HDMI_RELATIVE_POSITION_SIBLING, HDMI_RELATIVE_POSITION_DIFFERENT_BRANCH}) + public @interface HdmiAddressRelativePosition {} + /** + * HDMI relative position is not determined. + * TODO(b/110094868): unhide for Q + * @hide + */ + public static final int HDMI_RELATIVE_POSITION_UNKNOWN = 0; + /** + * HDMI relative position: directly blow the device. + * TODO(b/110094868): unhide for Q + * @hide + */ + public static final int HDMI_RELATIVE_POSITION_DIRECTLY_BELOW = 1; + /** + * HDMI relative position: indirectly below the device. + * TODO(b/110094868): unhide for Q + * @hide + */ + public static final int HDMI_RELATIVE_POSITION_BELOW = 2; + /** + * HDMI relative position: the same device. + * TODO(b/110094868): unhide for Q + * @hide + */ + public static final int HDMI_RELATIVE_POSITION_SAME = 3; + /** + * HDMI relative position: directly above the device. + * TODO(b/110094868): unhide for Q + * @hide + */ + public static final int HDMI_RELATIVE_POSITION_DIRECTLY_ABOVE = 4; + /** + * HDMI relative position: indirectly above the device. + * TODO(b/110094868): unhide for Q + * @hide + */ + public static final int HDMI_RELATIVE_POSITION_ABOVE = 5; + /** + * HDMI relative position: directly below a same device. + * TODO(b/110094868): unhide for Q + * @hide + */ + public static final int HDMI_RELATIVE_POSITION_SIBLING = 6; + /** + * HDMI relative position: different branch. + * TODO(b/110094868): unhide for Q + * @hide + */ + public static final int HDMI_RELATIVE_POSITION_DIFFERENT_BRANCH = 7; + + private static final int NPOS = -1; + + /** + * Check if the given physical address is valid. + * + * @param address physical address + * @return {@code true} if the given address is valid + */ + public static boolean isValidPhysicalAddress(int address) { + if (address < 0 || address >= 0xFFFF) { + return false; + } + int mask = 0xF000; + boolean hasZero = false; + for (int i = 0; i < 4; i++) { + if ((address & mask) == 0) { + hasZero = true; + } else if (hasZero) { + // only 0s are valid after a 0. + // e.g. 0x1012 is not valid. + return false; + } + mask >>= 4; + } + return true; + } + + + /** + * Returns the relative position of two physical addresses. + */ + @HdmiAddressRelativePosition + public static int getHdmiAddressRelativePosition(int src, int dest) { + if (src == 0xFFFF || dest == 0xFFFF) { + // address not assigned + return HDMI_RELATIVE_POSITION_UNKNOWN; + } + try { + int firstDiffPos = physicalAddressFirstDifferentDigitPos(src, dest); + if (firstDiffPos == NPOS) { + return HDMI_RELATIVE_POSITION_SAME; + } + int mask = (0xF000 >> (firstDiffPos * 4)); + int nextPos = firstDiffPos + 1; + if ((src & mask) == 0) { + // src is above dest + if (nextPos == 4) { + // last digits are different + return HDMI_RELATIVE_POSITION_DIRECTLY_ABOVE; + } + if (((0xF000 >> (nextPos * 4)) & dest) == 0) { + // next digit is 0 + return HDMI_RELATIVE_POSITION_DIRECTLY_ABOVE; + } + return HDMI_RELATIVE_POSITION_ABOVE; + } + + if ((dest & mask) == 0) { + // src is below dest + if (nextPos == 4) { + // last digits are different + return HDMI_RELATIVE_POSITION_DIRECTLY_BELOW; + } + if (((0xF000 >> (nextPos * 4)) & src) == 0) { + // next digit is 0 + return HDMI_RELATIVE_POSITION_DIRECTLY_BELOW; + } + return HDMI_RELATIVE_POSITION_BELOW; + } + if (nextPos == 4) { + // last digits are different + return HDMI_RELATIVE_POSITION_SIBLING; + } + if (((0xF000 >> (nextPos * 4)) & src) == 0 && ((0xF000 >> (nextPos * 4)) & dest) == 0) { + return HDMI_RELATIVE_POSITION_SIBLING; + } + return HDMI_RELATIVE_POSITION_DIFFERENT_BRANCH; + } catch (IllegalArgumentException e) { + // invalid address + return HDMI_RELATIVE_POSITION_UNKNOWN; + } + } + + private static int physicalAddressFirstDifferentDigitPos(int address1, int address2) + throws IllegalArgumentException { + if (!isValidPhysicalAddress(address1)) { + throw new IllegalArgumentException(address1 + " is not a valid address."); + } + if (!isValidPhysicalAddress(address2)) { + throw new IllegalArgumentException(address2 + " is not a valid address."); + } + int mask = 0xF000; + for (int i = 0; i < 4; i++) { + if ((address1 & mask) != (address2 & mask)) { + return i; + } + mask = mask >> 4; + } + return NPOS; + } } diff --git a/core/tests/hdmitests/Android.mk b/core/tests/hdmitests/Android.mk index 2ca31a6a240a..f155feba0588 100644 --- a/core/tests/hdmitests/Android.mk +++ b/core/tests/hdmitests/Android.mk @@ -20,7 +20,7 @@ LOCAL_MODULE_TAGS := tests # Include all test java files LOCAL_SRC_FILES := $(call all-java-files-under, src) -LOCAL_STATIC_JAVA_LIBRARIES := androidx.test.rules frameworks-base-testutils +LOCAL_STATIC_JAVA_LIBRARIES := androidx.test.rules frameworks-base-testutils truth-prebuilt LOCAL_JAVA_LIBRARIES := android.test.runner LOCAL_PACKAGE_NAME := HdmiCecTests diff --git a/core/tests/hdmitests/src/android/hardware/hdmi/HdmiUtilsTest.java b/core/tests/hdmitests/src/android/hardware/hdmi/HdmiUtilsTest.java new file mode 100644 index 000000000000..fdc6b847d055 --- /dev/null +++ b/core/tests/hdmitests/src/android/hardware/hdmi/HdmiUtilsTest.java @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.hdmi; + +import static com.google.common.truth.Truth.assertThat; + +import androidx.test.filters.SmallTest; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; +/** + * Tests for {@link HdmiUtils}. + */ +@RunWith(JUnit4.class) +@SmallTest +public class HdmiUtilsTest { + @Test + public void testInvalidAddress() { + assertThat(HdmiUtils.getHdmiAddressRelativePosition(0, -1)) + .isEqualTo(HdmiUtils.HDMI_RELATIVE_POSITION_UNKNOWN); + assertThat(HdmiUtils.getHdmiAddressRelativePosition(0xFFFF, 0xFFFF)) + .isEqualTo(HdmiUtils.HDMI_RELATIVE_POSITION_UNKNOWN); + assertThat(HdmiUtils.getHdmiAddressRelativePosition(0xFFFFF, 0)) + .isEqualTo(HdmiUtils.HDMI_RELATIVE_POSITION_UNKNOWN); + } + + @Test + public void testSameAddress() { + assertThat(HdmiUtils.getHdmiAddressRelativePosition(0x1000, 0x1000)) + .isEqualTo(HdmiUtils.HDMI_RELATIVE_POSITION_SAME); + } + + @Test + public void testDirectlyAbove() { + assertThat(HdmiUtils.getHdmiAddressRelativePosition(0x1000, 0x1200)) + .isEqualTo(HdmiUtils.HDMI_RELATIVE_POSITION_DIRECTLY_ABOVE); + } + + @Test + public void testDirectlyAbove_rootDevice() { + assertThat(HdmiUtils.getHdmiAddressRelativePosition(0x0000, 0x2000)) + .isEqualTo(HdmiUtils.HDMI_RELATIVE_POSITION_DIRECTLY_ABOVE); + } + + @Test + public void testDirectlyAbove_leafDevice() { + assertThat(HdmiUtils.getHdmiAddressRelativePosition(0x1240, 0x1245)) + .isEqualTo(HdmiUtils.HDMI_RELATIVE_POSITION_DIRECTLY_ABOVE); + } + + @Test + public void testAbove() { + assertThat(HdmiUtils.getHdmiAddressRelativePosition(0x1000, 0x1210)) + .isEqualTo(HdmiUtils.HDMI_RELATIVE_POSITION_ABOVE); + } + + @Test + public void testAbove_rootDevice() { + assertThat(HdmiUtils.getHdmiAddressRelativePosition(0x0000, 0x1200)) + .isEqualTo(HdmiUtils.HDMI_RELATIVE_POSITION_ABOVE); + } + + @Test + public void testDirectlyBelow() { + assertThat(HdmiUtils.getHdmiAddressRelativePosition(0x2250, 0x2200)) + .isEqualTo(HdmiUtils.HDMI_RELATIVE_POSITION_DIRECTLY_BELOW); + } + + @Test + public void testDirectlyBelow_rootDevice() { + assertThat(HdmiUtils.getHdmiAddressRelativePosition(0x5000, 0x0000)) + .isEqualTo(HdmiUtils.HDMI_RELATIVE_POSITION_DIRECTLY_BELOW); + } + + @Test + public void testDirectlyBelow_leafDevice() { + assertThat(HdmiUtils.getHdmiAddressRelativePosition(0x3249, 0x3240)) + .isEqualTo(HdmiUtils.HDMI_RELATIVE_POSITION_DIRECTLY_BELOW); + } + + @Test + public void testBelow() { + assertThat(HdmiUtils.getHdmiAddressRelativePosition(0x5143, 0x5100)) + .isEqualTo(HdmiUtils.HDMI_RELATIVE_POSITION_BELOW); + } + + @Test + public void testBelow_rootDevice() { + assertThat(HdmiUtils.getHdmiAddressRelativePosition(0x3420, 0x0000)) + .isEqualTo(HdmiUtils.HDMI_RELATIVE_POSITION_BELOW); + } + + @Test + public void testSibling() { + assertThat(HdmiUtils.getHdmiAddressRelativePosition(0x4000, 0x5000)) + .isEqualTo(HdmiUtils.HDMI_RELATIVE_POSITION_SIBLING); + } + + @Test + public void testSibling_leafDevice() { + assertThat(HdmiUtils.getHdmiAddressRelativePosition(0x798A, 0x798F)) + .isEqualTo(HdmiUtils.HDMI_RELATIVE_POSITION_SIBLING); + } + + @Test + public void testDifferentBranch() { + assertThat(HdmiUtils.getHdmiAddressRelativePosition(0x798A, 0x7970)) + .isEqualTo(HdmiUtils.HDMI_RELATIVE_POSITION_DIFFERENT_BRANCH); + } + + @Test + public void isValidPysicalAddress_true() { + assertThat(HdmiUtils.isValidPhysicalAddress(0)).isTrue(); + assertThat(HdmiUtils.isValidPhysicalAddress(0xFFFE)).isTrue(); + assertThat(HdmiUtils.isValidPhysicalAddress(0x1200)).isTrue(); + } + + @Test + public void isValidPysicalAddress_outOfRange() { + assertThat(HdmiUtils.isValidPhysicalAddress(-1)).isFalse(); + assertThat(HdmiUtils.isValidPhysicalAddress(0xFFFF)).isFalse(); + assertThat(HdmiUtils.isValidPhysicalAddress(0x10000)).isFalse(); + } + + @Test + public void isValidPysicalAddress_nonTrailingZeros() { + assertThat(HdmiUtils.isValidPhysicalAddress(0x0001)).isFalse(); + assertThat(HdmiUtils.isValidPhysicalAddress(0x0213)).isFalse(); + } +} diff --git a/media/java/android/media/tv/TvInputInfo.java b/media/java/android/media/tv/TvInputInfo.java index 5cb8fb8bee3b..30907a5cf205 100644 --- a/media/java/android/media/tv/TvInputInfo.java +++ b/media/java/android/media/tv/TvInputInfo.java @@ -33,7 +33,10 @@ import android.content.res.TypedArray; import android.content.res.XmlResourceParser; import android.graphics.drawable.Drawable; import android.graphics.drawable.Icon; +import android.hardware.hdmi.HdmiControlManager; import android.hardware.hdmi.HdmiDeviceInfo; +import android.hardware.hdmi.HdmiUtils; +import android.hardware.hdmi.HdmiUtils.HdmiAddressRelativePosition; import android.net.Uri; import android.os.Bundle; import android.os.Parcel; @@ -49,7 +52,6 @@ import android.util.Xml; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; -import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.lang.annotation.Retention; @@ -145,6 +147,8 @@ public final class TvInputInfo implements Parcelable { // Attributes specific to HDMI private final HdmiDeviceInfo mHdmiDeviceInfo; private final boolean mIsConnectedToHdmiSwitch; + @HdmiAddressRelativePosition + private final int mHdmiConnectionRelativePosition; private final String mParentId; private final Bundle mExtras; @@ -260,7 +264,9 @@ public final class TvInputInfo implements Parcelable { private TvInputInfo(ResolveInfo service, String id, int type, boolean isHardwareInput, CharSequence label, int labelResId, Icon icon, Icon iconStandby, Icon iconDisconnected, String setupActivity, boolean canRecord, int tunerCount, HdmiDeviceInfo hdmiDeviceInfo, - boolean isConnectedToHdmiSwitch, String parentId, Bundle extras) { + boolean isConnectedToHdmiSwitch, + @HdmiAddressRelativePosition int hdmiConnectionRelativePosition, String parentId, + Bundle extras) { mService = service; mId = id; mType = type; @@ -275,6 +281,7 @@ public final class TvInputInfo implements Parcelable { mTunerCount = tunerCount; mHdmiDeviceInfo = hdmiDeviceInfo; mIsConnectedToHdmiSwitch = isConnectedToHdmiSwitch; + mHdmiConnectionRelativePosition = hdmiConnectionRelativePosition; mParentId = parentId; mExtras = extras; } @@ -419,6 +426,7 @@ public final class TvInputInfo implements Parcelable { /** * Returns {@code true}, if a CEC device for this TV input is connected to an HDMI switch, i.e., * the device isn't directly connected to a HDMI port. + * TODO(b/110094868): add @Deprecated for Q * @hide */ @SystemApi @@ -427,6 +435,16 @@ public final class TvInputInfo implements Parcelable { } /** + * Returns the relative position of this HDMI input. + * TODO(b/110094868): unhide for Q + * @hide + */ + @HdmiAddressRelativePosition + public int getHdmiConnectionRelativePosition() { + return mHdmiConnectionRelativePosition; + } + + /** * Checks if this TV input is marked hidden by the user in the settings. * * @param context Supplies a {@link Context} used to check if this TV input is hidden. @@ -555,6 +573,7 @@ public final class TvInputInfo implements Parcelable { && mTunerCount == obj.mTunerCount && Objects.equals(mHdmiDeviceInfo, obj.mHdmiDeviceInfo) && mIsConnectedToHdmiSwitch == obj.mIsConnectedToHdmiSwitch + && mHdmiConnectionRelativePosition == obj.mHdmiConnectionRelativePosition && TextUtils.equals(mParentId, obj.mParentId) && Objects.equals(mExtras, obj.mExtras); } @@ -589,6 +608,7 @@ public final class TvInputInfo implements Parcelable { dest.writeInt(mTunerCount); dest.writeParcelable(mHdmiDeviceInfo, flags); dest.writeByte(mIsConnectedToHdmiSwitch ? (byte) 1 : 0); + dest.writeInt(mHdmiConnectionRelativePosition); dest.writeString(mParentId); dest.writeBundle(mExtras); } @@ -630,6 +650,7 @@ public final class TvInputInfo implements Parcelable { mTunerCount = in.readInt(); mHdmiDeviceInfo = in.readParcelable(null); mIsConnectedToHdmiSwitch = in.readByte() == 1; + mHdmiConnectionRelativePosition = in.readInt(); mParentId = in.readString(); mExtras = in.readBundle(); } @@ -883,12 +904,17 @@ public final class TvInputInfo implements Parcelable { int type; boolean isHardwareInput = false; boolean isConnectedToHdmiSwitch = false; + @HdmiAddressRelativePosition + int hdmiConnectionRelativePosition = HdmiUtils.HDMI_RELATIVE_POSITION_UNKNOWN; if (mHdmiDeviceInfo != null) { id = generateInputId(componentName, mHdmiDeviceInfo); type = TYPE_HDMI; isHardwareInput = true; - isConnectedToHdmiSwitch = (mHdmiDeviceInfo.getPhysicalAddress() & 0x0FFF) != 0; + hdmiConnectionRelativePosition = getRelativePosition(mContext, mHdmiDeviceInfo); + isConnectedToHdmiSwitch = + hdmiConnectionRelativePosition + != HdmiUtils.HDMI_RELATIVE_POSITION_DIRECTLY_BELOW; } else if (mTvInputHardwareInfo != null) { id = generateInputId(componentName, mTvInputHardwareInfo); type = sHardwareTypeToTvInputType.get(mTvInputHardwareInfo.getType(), TYPE_TUNER); @@ -901,7 +927,8 @@ public final class TvInputInfo implements Parcelable { return new TvInputInfo(mResolveInfo, id, type, isHardwareInput, mLabel, mLabelResId, mIcon, mIconStandby, mIconDisconnected, mSetupActivity, mCanRecord == null ? false : mCanRecord, mTunerCount == null ? 0 : mTunerCount, - mHdmiDeviceInfo, isConnectedToHdmiSwitch, mParentId, mExtras); + mHdmiDeviceInfo, isConnectedToHdmiSwitch, hdmiConnectionRelativePosition, + mParentId, mExtras); } private static String generateInputId(ComponentName name) { @@ -923,6 +950,16 @@ public final class TvInputInfo implements Parcelable { + tvInputHardwareInfo.getDeviceId(); } + private static int getRelativePosition(Context context, HdmiDeviceInfo info) { + HdmiControlManager hcm = + (HdmiControlManager) context.getSystemService(Context.HDMI_CONTROL_SERVICE); + if (hcm == null) { + return HdmiUtils.HDMI_RELATIVE_POSITION_UNKNOWN; + } + return HdmiUtils.getHdmiAddressRelativePosition( + info.getPhysicalAddress(), hcm.getPhysicalAddress()); + } + private void parseServiceMetadata(int inputType) { ServiceInfo si = mResolveInfo.serviceInfo; PackageManager pm = mContext.getPackageManager(); |