HDMI: Fix BCD handling error

isValidHour/isValidMinute accept a parameter as BCD encoded value, but they check it without translating to raw value, so valid hour/minute may be detected as an error;
e.g.
18:00 is within 23:00 but 0x18(24) is over 23
* 0x18 should be decoded  (0x10 >> 4) x 10 + 0x08 = 18

Fix to translate the parameter before checking by isWithinRange.

Bug: 357733495
Change-Id: Id0cfb1211048b1f2eaebf3db5814e3da0f34e5b9
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java b/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java
index 16b00de..18a6e3dd 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java
@@ -486,6 +486,7 @@
      * @return true if the hour is valid
      */
     private static boolean isValidHour(int value) {
+        value = bcdToDecimal(value);
         return isWithinRange(value, 0, 23);
     }
 
@@ -497,6 +498,7 @@
      * @return true if the minute is valid
      */
     private static boolean isValidMinute(int value) {
+        value = bcdToDecimal(value);
         return isWithinRange(value, 0, 59);
     }
 
@@ -508,10 +510,24 @@
      * @return true if the duration hours is valid
      */
     private static boolean isValidDurationHours(int value) {
+        value = bcdToDecimal(value);
         return isWithinRange(value, 0, 99);
     }
 
     /**
+     * Convert BCD value to decimal value.
+     *
+     * @param value BCD value
+     * @return decimal value
+     */
+    private static int bcdToDecimal(int value) {
+        int tens = (value & 0xF0) >> 4;
+        int ones = (value & 0x0F);
+
+        return tens * 10 + ones;
+    }
+
+    /**
      * Check if the given value is a valid recording sequence. A valid value is adheres to range
      * description defined in CEC 1.4 Specification : Operand Descriptions (Section 17)
      *
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageValidatorTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageValidatorTest.java
index ce7dbda..2446d2e 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageValidatorTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageValidatorTest.java
@@ -249,120 +249,120 @@
         assertMessageValidity("04:33:0C:08:10:1E:04:30:08:13:AD:06")
                 .isEqualTo(ERROR_PARAMETER_SHORT);
         // Out of range Day of Month
-        assertMessageValidity("04:34:20:0C:16:0F:08:37:00:02:EA:60:03").isEqualTo(ERROR_PARAMETER);
+        assertMessageValidity("04:34:20:0C:22:15:08:55:00:02:EA:60:03").isEqualTo(ERROR_PARAMETER);
         // Out of range Month of Year
-        assertMessageValidity("04:33:0C:00:10:1E:04:30:08:00:13:AD:06").isEqualTo(ERROR_PARAMETER);
+        assertMessageValidity("04:33:0C:00:16:30:04:48:08:00:13:AD:06").isEqualTo(ERROR_PARAMETER);
         // Out of range Start Time - Hour
-        assertMessageValidity("04:34:04:0C:18:0F:08:37:00:02:EA:60:03").isEqualTo(ERROR_PARAMETER);
+        assertMessageValidity("04:34:04:0C:24:15:08:55:00:02:EA:60:03").isEqualTo(ERROR_PARAMETER);
         // Out of range Start Time - Minute
-        assertMessageValidity("04:33:0C:08:10:50:04:30:08:00:13:AD:06").isEqualTo(ERROR_PARAMETER);
+        assertMessageValidity("04:33:0C:08:16:60:04:48:08:00:13:AD:06").isEqualTo(ERROR_PARAMETER);
         // Out of range Duration - Duration Hours
-        assertMessageValidity("04:34:04:0C:16:0F:64:37:00:02:EA:60:03").isEqualTo(ERROR_PARAMETER);
+        assertMessageValidity("04:34:04:0C:22:15:9A:55:00:02:EA:60:03").isEqualTo(ERROR_PARAMETER);
         // Out of range Duration - Minute
-        assertMessageValidity("04:33:0C:08:10:1E:04:64:08:00:13:AD:06").isEqualTo(ERROR_PARAMETER);
+        assertMessageValidity("04:33:0C:08:16:30:04:60:08:00:13:AD:06").isEqualTo(ERROR_PARAMETER);
         // Invalid Recording Sequence
-        assertMessageValidity("04:34:04:0C:16:0F:08:37:88:02:EA:60:03").isEqualTo(ERROR_PARAMETER);
+        assertMessageValidity("04:34:04:0C:22:15:08:55:88:02:EA:60:03").isEqualTo(ERROR_PARAMETER);
         // Invalid Recording Sequence
-        assertMessageValidity("04:33:0C:08:10:1E:04:30:A2:00:13:AD:06").isEqualTo(ERROR_PARAMETER);
+        assertMessageValidity("04:33:0C:08:16:30:04:48:A2:00:13:AD:06").isEqualTo(ERROR_PARAMETER);
         // Out of range Analogue Broadcast Type
-        assertMessageValidity("04:34:04:0C:16:0F:08:37:00:03:EA:60:03").isEqualTo(ERROR_PARAMETER);
+        assertMessageValidity("04:34:04:0C:22:15:08:55:00:03:EA:60:03").isEqualTo(ERROR_PARAMETER);
         // Out of range Analogue Frequency
-        assertMessageValidity("04:33:0C:08:10:1E:04:30:08:00:FF:FF:06").isEqualTo(ERROR_PARAMETER);
+        assertMessageValidity("04:33:0C:08:16:30:04:48:08:00:FF:FF:06").isEqualTo(ERROR_PARAMETER);
         // Out of range Broadcast System
-        assertMessageValidity("04:34:04:0C:16:0F:08:37:00:02:EA:60:20").isEqualTo(ERROR_PARAMETER);
+        assertMessageValidity("04:34:04:0C:22:15:08:55:00:02:EA:60:20").isEqualTo(ERROR_PARAMETER);
     }
 
     @Test
     public void isValid_setDigitalTimer_clearDigitalTimer() {
         // Services identified by Digital IDs - ARIB Broadcast System
-        assertMessageValidity("04:99:0C:08:15:05:04:1E:00:00:C4:C2:11:D8:75:30").isEqualTo(OK);
+        assertMessageValidity("04:99:0C:08:21:05:04:30:00:00:C4:C2:11:D8:75:30").isEqualTo(OK);
         // Service identified by Digital IDs - ATSC Broadcast System
-        assertMessageValidity("04:97:1E:07:12:20:50:28:01:01:8B:5E:39:5A").isEqualTo(OK);
+        assertMessageValidity("04:97:1E:07:18:32:80:40:01:01:8B:5E:39:5A").isEqualTo(OK);
         // Service identified by Digital IDs - DVB Broadcast System
-        assertMessageValidity("04:99:05:0C:06:0A:19:3B:40:19:8B:44:03:11:04:FC").isEqualTo(OK);
+        assertMessageValidity("04:99:05:0C:06:10:25:59:40:19:8B:44:03:11:04:FC").isEqualTo(OK);
         // Service identified by Channel - 1 part channel number
-        assertMessageValidity("04:97:12:06:0C:2D:5A:19:08:91:04:00:B1").isEqualTo(OK);
+        assertMessageValidity("04:97:12:06:12:45:90:25:08:91:04:00:B1").isEqualTo(OK);
         // Service identified by Channel - 2 part channel number
-        assertMessageValidity("04:99:15:09:00:0F:00:2D:04:82:09:C8:72:C8").isEqualTo(OK);
+        assertMessageValidity("04:99:15:09:00:15:00:45:04:82:09:C8:72:C8").isEqualTo(OK);
 
-        assertMessageValidity("4F:97:0C:08:15:05:04:1E:00:00:C4:C2:11:D8:75:30")
+        assertMessageValidity("4F:97:0C:08:21:05:04:30:00:00:C4:C2:11:D8:75:30")
                 .isEqualTo(ERROR_DESTINATION);
-        assertMessageValidity("F0:99:15:09:00:0F:00:2D:04:82:09:C8:72:C8").isEqualTo(ERROR_SOURCE);
+        assertMessageValidity("F0:99:15:09:00:15:00:45:04:82:09:C8:72:C8").isEqualTo(ERROR_SOURCE);
         assertMessageValidity("04:97:1E:12:20:58:01:01:8B:5E:39:5A")
                 .isEqualTo(ERROR_PARAMETER_SHORT);
         // Out of range Day of Month
-        assertMessageValidity("04:99:24:0C:06:0A:19:3B:40:19:8B:44:03:11:04:FC")
+        assertMessageValidity("04:99:24:0C:06:10:25:59:40:19:8B:44:03:11:04:FC")
                 .isEqualTo(ERROR_PARAMETER);
         // Out of range Month of Year
-        assertMessageValidity("04:97:12:10:0C:2D:5A:19:08:91:04:00:B1").isEqualTo(ERROR_PARAMETER);
+        assertMessageValidity("04:97:12:10:12:45:90:25:08:91:04:00:B1").isEqualTo(ERROR_PARAMETER);
         // Out of range Start Time - Hour
-        assertMessageValidity("04:99:0C:08:20:05:04:1E:00:00:C4:C2:11:D8:75:30")
+        assertMessageValidity("04:99:0C:08:24:05:04:30:00:00:C4:C2:11:D8:75:30")
                 .isEqualTo(ERROR_PARAMETER);
         // Out of range Start Time - Minute
-        assertMessageValidity("04:97:15:09:00:4B:00:2D:04:82:09:C8:72:C8")
+        assertMessageValidity("04:97:15:09:00:60:00:45:04:82:09:C8:72:C8")
                 .isEqualTo(ERROR_PARAMETER);
         // Out of range Duration - Duration Hours
-        assertMessageValidity("04:99:1E:07:12:20:78:28:01:01:8B:5E:39:5A")
+        assertMessageValidity("04:99:1E:07:18:32:9A:40:01:01:8B:5E:39:5A")
                 .isEqualTo(ERROR_PARAMETER);
         // Out of range Duration - Minute
-        assertMessageValidity("04:97:05:0C:06:0A:19:48:40:19:8B:44:03:11:04:FC")
+        assertMessageValidity("04:97:05:0C:06:10:25:60:40:19:8B:44:03:11:04:FC")
                 .isEqualTo(ERROR_PARAMETER);
         // Invalid Recording Sequence
-        assertMessageValidity("04:99:12:06:0C:2D:5A:19:90:91:04:00:B1").isEqualTo(ERROR_PARAMETER);
+        assertMessageValidity("04:99:12:06:12:45:90:25:90:91:04:00:B1").isEqualTo(ERROR_PARAMETER);
         // Invalid Recording Sequence
         assertMessageValidity("04:97:0C:08:15:05:04:1E:A1:00:C4:C2:11:D8:75:30")
                 .isEqualTo(ERROR_PARAMETER);
 
         // Invalid Digital Broadcast System
-        assertMessageValidity("04:99:1E:07:12:20:50:28:01:04:8B:5E:39:5A")
+        assertMessageValidity("04:99:1E:07:18:32:80:40:01:04:8B:5E:39:5A")
                 .isEqualTo(ERROR_PARAMETER);
         // Invalid Digital Broadcast System
-        assertMessageValidity("04:97:05:0C:06:0A:19:3B:40:93:8B:44:03:11:04:FC")
+        assertMessageValidity("04:97:05:0C:06:10:25:59:40:93:8B:44:03:11:04:FC")
                 .isEqualTo(ERROR_PARAMETER);
         // Insufficient data for ARIB Broadcast system
-        assertMessageValidity("04:99:0C:08:15:05:04:1E:00:00:C4:C2:11:D8:75")
+        assertMessageValidity("04:99:0C:08:21:05:04:30:00:00:C4:C2:11:D8:75")
                 .isEqualTo(ERROR_PARAMETER);
         // Insufficient data for ATSC Broadcast system
-        assertMessageValidity("04:97:1E:07:12:20:50:28:01:01:8B:5E:39").isEqualTo(ERROR_PARAMETER);
+        assertMessageValidity("04:97:1E:07:18:32:80:40:01:01:8B:5E:39").isEqualTo(ERROR_PARAMETER);
         // Insufficient data for DVB Broadcast system
-        assertMessageValidity("04:99:05:0C:06:0A:19:3B:40:19:8B:44:03:11:04")
+        assertMessageValidity("04:99:05:0C:06:10:25:59:40:19:8B:44:03:11:04")
                 .isEqualTo(ERROR_PARAMETER);
         // Insufficient data for 2 part channel number
-        assertMessageValidity("04:97:15:09:00:0F:00:2D:04:82:09:C8:72").isEqualTo(ERROR_PARAMETER);
+        assertMessageValidity("04:97:15:09:00:15:00:45:04:82:09:C8:72").isEqualTo(ERROR_PARAMETER);
         // Invalid Channel Number format
-        assertMessageValidity("04:99:12:06:0C:2D:5A:19:08:91:0D:00:B1").isEqualTo(ERROR_PARAMETER);
+        assertMessageValidity("04:99:12:06:12:45:90:25:08:91:0D:00:B1").isEqualTo(ERROR_PARAMETER);
     }
 
     @Test
     public void isValid_setExternalTimer_clearExternalTimer() {
-        assertMessageValidity("40:A1:0C:08:15:05:04:1E:02:04:20").isEqualTo(OK);
-        assertMessageValidity("40:A2:14:09:12:28:4B:19:10:05:10:00").isEqualTo(OK);
+        assertMessageValidity("40:A1:0C:08:21:05:04:30:02:04:20").isEqualTo(OK);
+        assertMessageValidity("40:A2:14:09:18:40:75:25:10:05:10:00").isEqualTo(OK);
 
-        assertMessageValidity("4F:A1:0C:08:15:05:04:1E:02:04:20").isEqualTo(ERROR_DESTINATION);
-        assertMessageValidity("F4:A2:14:09:12:28:4B:19:10:05:10:00").isEqualTo(ERROR_SOURCE);
-        assertMessageValidity("40:A1:0C:08:15:05:04:1E:02:04").isEqualTo(ERROR_PARAMETER_SHORT);
+        assertMessageValidity("4F:A1:0C:08:21:05:04:30:02:04:20").isEqualTo(ERROR_DESTINATION);
+        assertMessageValidity("F4:A2:14:09:18:40:75:25:10:05:10:00").isEqualTo(ERROR_SOURCE);
+        assertMessageValidity("40:A1:0C:08:21:05:04:30:02:04").isEqualTo(ERROR_PARAMETER_SHORT);
         // Out of range Day of Month
-        assertMessageValidity("40:A2:28:09:12:28:4B:19:10:05:10:00").isEqualTo(ERROR_PARAMETER);
+        assertMessageValidity("40:A2:28:09:18:40:75:25:10:05:10:00").isEqualTo(ERROR_PARAMETER);
         // Out of range Month of Year
-        assertMessageValidity("40:A1:0C:0F:15:05:04:1E:02:04:20").isEqualTo(ERROR_PARAMETER);
+        assertMessageValidity("40:A1:0C:0F:21:05:04:30:02:04:20").isEqualTo(ERROR_PARAMETER);
         // Out of range Start Time - Hour
-        assertMessageValidity("40:A2:14:09:1A:28:4B:19:10:05:10:00").isEqualTo(ERROR_PARAMETER);
+        assertMessageValidity("40:A2:14:09:24:40:75:25:10:05:10:00").isEqualTo(ERROR_PARAMETER);
         // Out of range Start Time - Minute
-        assertMessageValidity("40:A1:0C:08:15:48:04:1E:02:04:20").isEqualTo(ERROR_PARAMETER);
+        assertMessageValidity("40:A1:0C:08:21:60:04:30:02:04:20").isEqualTo(ERROR_PARAMETER);
         // Out of range Duration - Duration Hours
-        assertMessageValidity("40:A2:14:09:12:28:66:19:10:05:10:00").isEqualTo(ERROR_PARAMETER);
+        assertMessageValidity("40:A2:14:09:18:40:9A:25:10:05:10:00").isEqualTo(ERROR_PARAMETER);
         // Out of range Duration - Minute
-        assertMessageValidity("40:A1:0C:08:15:05:04:3F:02:04:20").isEqualTo(ERROR_PARAMETER);
+        assertMessageValidity("40:A1:0C:08:21:05:04:60:02:04:20").isEqualTo(ERROR_PARAMETER);
         // Invalid Recording Sequence
-        assertMessageValidity("40:A2:14:09:12:28:4B:19:84:05:10:00").isEqualTo(ERROR_PARAMETER);
+        assertMessageValidity("40:A2:14:09:18:40:75:25:84:05:10:00").isEqualTo(ERROR_PARAMETER);
         // Invalid Recording Sequence
         assertMessageValidity("40:A1:0C:08:15:05:04:1E:94:04:20").isEqualTo(ERROR_PARAMETER);
         // Invalid external source specifier
-        assertMessageValidity("40:A2:14:09:12:28:4B:19:10:08:10:00").isEqualTo(ERROR_PARAMETER);
+        assertMessageValidity("40:A2:14:09:18:40:75:25:10:08:10:00").isEqualTo(ERROR_PARAMETER);
         // Invalid External PLug
-        assertMessageValidity("04:A1:0C:08:15:05:04:1E:02:04:00").isEqualTo(ERROR_PARAMETER);
+        assertMessageValidity("04:A1:0C:08:21:05:04:30:02:04:00").isEqualTo(ERROR_PARAMETER);
         // Invalid Physical Address
-        assertMessageValidity("40:A2:14:09:12:28:4B:19:10:05:10:10").isEqualTo(ERROR_PARAMETER);
+        assertMessageValidity("40:A2:14:09:18:40:75:25:10:05:10:10").isEqualTo(ERROR_PARAMETER);
     }
 
     @Test
@@ -395,9 +395,9 @@
         // Non programmed - Invalid not programmed error info
         assertMessageValidity("40:35:DE").isEqualTo(ERROR_PARAMETER);
         // Programmed - Might not be enough space available - Invalid duration hours
-        assertMessageValidity("40:35:BB:96:1C").isEqualTo(ERROR_PARAMETER);
+        assertMessageValidity("40:35:BB:9A:28").isEqualTo(ERROR_PARAMETER);
         // Not programmed - Duplicate - Invalid duration minutes
-        assertMessageValidity("40:35:EE:52:4A").isEqualTo(ERROR_PARAMETER);
+        assertMessageValidity("40:35:EE:82:60").isEqualTo(ERROR_PARAMETER);
     }
 
     @Test