2 * Copyright (c) 2010-2023 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
7 * This program and the accompanying materials are made available under the
8 * terms of the Eclipse Public License 2.0 which is available at
9 * http://www.eclipse.org/legal/epl-2.0
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.androidtv.internal.protocol.googletv;
15 import static org.openhab.binding.androidtv.internal.AndroidTVBindingConstants.*;
16 import static org.openhab.binding.androidtv.internal.protocol.googletv.GoogleTVConstants.*;
18 import org.eclipse.jdt.annotation.NonNullByDefault;
21 * Contains static methods for constructing LEAP messages
23 * @author Ben Rosenblum - Initial contribution
26 public class GoogleTVRequest {
28 public static String encodeMessage(String message) {
29 StringBuilder reply = new StringBuilder();
30 char[] charArray = message.toCharArray();
31 for (int i = 0; i < charArray.length; i = i + 2) {
32 String st = "" + charArray[i] + "" + charArray[i + 1];
33 char ch = (char) Integer.parseInt(st, 16);
36 return reply.toString();
39 public static String decodeMessage(String message) {
40 StringBuilder sb = new StringBuilder();
41 char ch[] = message.toCharArray();
42 for (int i = 0; i < ch.length; i++) {
43 String hexString = Integer.toHexString(ch[i]);
44 if (hexString.length() % 2 > 0) {
52 public static String pinRequest(String pin) {
54 if (PIN_REQUEST.equals(pin)) {
55 return loginRequest(3);
57 // 080210c801c202 22 0a 20 0e066c3d1c3a6686edb6b2648ff25fcb3f0bf9cc81deeee9fad1a26073645e17
58 // 080210c801c202 22 0a 20 530bb7c7ba06069997285aff6e0106adfb19ab23c18a7422f5f643b35a6467b3
59 // -------------------------SHA HASH OF PIN
61 int length = pin.length() / 2;
62 String len1 = GoogleTVRequest.fixMessage(Integer.toHexString(length + 2));
63 String len2 = GoogleTVRequest.fixMessage(Integer.toHexString(length));
64 return "080210c801c202" + len1 + "0a" + len2 + pin;
68 public static String loginRequest(int messageId) {
71 // Send app and device name
72 // 080210c801522d 0a 19 636f6d2e676f6f676c652e616e64726f69642e766964656f73 12 10
73 // 73616d73756e6720534d2d4739393855
74 // ------------------LEN com.google.android.videos----------------------------LEN samsung SM-G998U
75 message = "080210c801522d0a19636f6d2e676f6f676c652e616e64726f69642e766964656f73121073616d73756e6720534d2d4739393855";
76 } else if (messageId == 2) {
77 // Unknown but required
78 // 080210c801a201 0e 0a 04 08031006 0a 04 08031004 1802
79 // ---------------LEN---LEN------------LEN
80 message = "080210c801a2010e0a04080310060a04080310041802";
81 } else if (messageId == 3) {
83 // ---------------LEN---LEN
84 // 080210c801a201 08 12 04 08031006 1801
85 // 080210c801f201 08 0a 04 08031006 1001
86 message = "080210c801f201080a04080310061001";
87 } else if (messageId == 4) {
88 // 0a41087e123d0a 08 534d2d4739393855 12 07 73616d73756e67 18 01 22 02 3133 2a
89 // ---------------LEN--SM-G998U----------LEN--samsung---------
90 // 19 636f6d2e676f6f676c652e616e64726f69642e766964656f73 32
91 // LEN-com.google.android.videos----------------------------
95 // "0a41087e123d0a08534d2d4739393855120773616d73756e671801220231332a19636f6d2e676f6f676c652e616e64726f69642e766964656f733207342e33382e3138";
97 // 0a5708fe0412520a 08 534d2d4739393855 12 07 73616d73756e67 18 01 22 02 3133 2a
98 // -----------------LEN--SM-G998U----------LEN--samsung---------
99 // 19 636f6d2e676f6f676c652e616e64726f69642e766964656f73 32
100 // LEN-com.google.android.videos---------------------------
101 // 1c 342e33392e3538342e3532393538383538332e372d72656c65617365
102 // LEN-4.39.584.529588583.7-release
104 // "0a5708fe0412520a08534d2d4739393855120773616d73756e671801220231332a19636f6d2e676f6f676c652e616e64726f69642e766964656f73321c342e33392e3538342e3532393538383538332e372d72656c65617365";
106 // 0a5708fe0412520a 08 534d2d4739393855 12 07 73616d73756e67 18 01 22 02 3133 2a
107 // -----------------LEN--SM-G998U----------LEN--samsung---------
108 // 19 636f6d2e676f6f676c652e616e64726f69642e766964656f73 32
109 // LEN-com.google.android.videos---------------------------
110 // 1c 342e33392e3634342e3533343836353739392e332d72656c65617365
111 // LEN-4.39.644.534865799.3-release
112 message = "0a5708fe0412520a08534d2d4739393855120773616d73756e671801220231332a19636f6d2e676f6f676c652e616e64726f69642e766964656f73321c342e33392e3634342e3533343836353739392e332d72656c65617365";
113 } else if (messageId == 5) {
114 // Unknown. Sent after "1200" received
115 message = "1202087e";
120 public static String keepAlive(String request) {
121 // 42 07 08 01 10 e4f1 8d01
124 // 42 08 08 7f 10 b4 908a a819
127 // 42 09 08 8001 10 ed b78a a819
130 char[] charArray = request.toCharArray();
131 StringBuilder sb = new StringBuilder();
133 sb.setLength(sb.toString().length() - 6);
136 int sbLen = sb.toString().length();
137 st = "" + charArray[sbLen - 2] + charArray[sbLen - 1];
138 if (!DELIMITER_10.equals(st)) {
139 sb.setLength(sbLen - 2);
141 } while (!DELIMITER_10.equals(st));
142 sb.setLength(sb.toString().length() - 2);
144 StringBuilder sbReply = new StringBuilder();
145 for (int i = 4; i < sb.toString().length(); i++) {
146 sbReply.append(charArray[i]);
148 return "4a" + fixMessage(Integer.toHexString(sbReply.toString().length() / 2)) + sbReply.toString();
151 public static String fixMessage(String tempMsg) {
152 if (tempMsg.length() % 2 > 0) {
153 tempMsg = "0" + tempMsg;