diff --git a/bundles/org.openhab.binding.androidtv/src/main/java/org/openhab/binding/androidtv/internal/AndroidTVHandler.java b/bundles/org.openhab.binding.androidtv/src/main/java/org/openhab/binding/androidtv/internal/AndroidTVHandler.java index f4393632425..6904d8b21c1 100644 --- a/bundles/org.openhab.binding.androidtv/src/main/java/org/openhab/binding/androidtv/internal/AndroidTVHandler.java +++ b/bundles/org.openhab.binding.androidtv/src/main/java/org/openhab/binding/androidtv/internal/AndroidTVHandler.java @@ -61,13 +61,15 @@ public class AndroidTVHandler extends BaseThingHandler { private static final int THING_STATUS_FREQUENCY = 250; private final AndroidTVDynamicCommandDescriptionProvider commandDescriptionProvider; + private final AndroidTVTranslationProvider translationProvider; private final ThingTypeUID thingTypeUID; private final String thingID; public AndroidTVHandler(Thing thing, AndroidTVDynamicCommandDescriptionProvider commandDescriptionProvider, - ThingTypeUID thingTypeUID) { + AndroidTVTranslationProvider translationProvider, ThingTypeUID thingTypeUID) { super(thing); this.commandDescriptionProvider = commandDescriptionProvider; + this.translationProvider = translationProvider; this.thingTypeUID = thingTypeUID; this.thingID = this.getThing().getUID().getId(); } @@ -76,6 +78,10 @@ public class AndroidTVHandler extends BaseThingHandler { thing.setProperty(property, value); } + public AndroidTVTranslationProvider getTranslationProvider() { + return translationProvider; + } + public String getThingID() { return this.thingID; } @@ -113,21 +119,17 @@ public class AndroidTVHandler extends BaseThingHandler { if (googletvConnectionManager != null) { if (!googletvConnectionManager.getLoggedIn()) { - statusMessage = "GoogleTV: " + googletvConnectionManager.getStatusMessage(); failed = true; - } else { - statusMessage = "GoogleTV: ONLINE"; } + statusMessage = "GoogleTV: " + googletvConnectionManager.getStatusMessage(); } if (THING_TYPE_SHIELDTV.equals(thingTypeUID)) { if (shieldtvConnectionManager != null) { if (!shieldtvConnectionManager.getLoggedIn()) { - statusMessage = statusMessage + " | ShieldTV: " + shieldtvConnectionManager.getStatusMessage(); failed = true; - } else { - statusMessage = statusMessage + " | ShieldTV: ONLINE"; } + statusMessage = statusMessage + " | ShieldTV: " + shieldtvConnectionManager.getStatusMessage(); } } diff --git a/bundles/org.openhab.binding.androidtv/src/main/java/org/openhab/binding/androidtv/internal/AndroidTVHandlerFactory.java b/bundles/org.openhab.binding.androidtv/src/main/java/org/openhab/binding/androidtv/internal/AndroidTVHandlerFactory.java index d5690ddc4e5..38581ad6b68 100644 --- a/bundles/org.openhab.binding.androidtv/src/main/java/org/openhab/binding/androidtv/internal/AndroidTVHandlerFactory.java +++ b/bundles/org.openhab.binding.androidtv/src/main/java/org/openhab/binding/androidtv/internal/AndroidTVHandlerFactory.java @@ -18,6 +18,8 @@ import java.util.Set; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; +import org.openhab.core.i18n.LocaleProvider; +import org.openhab.core.i18n.TranslationProvider; import org.openhab.core.thing.Thing; import org.openhab.core.thing.ThingTypeUID; import org.openhab.core.thing.binding.BaseThingHandlerFactory; @@ -41,11 +43,14 @@ public class AndroidTVHandlerFactory extends BaseThingHandlerFactory { THING_TYPE_SHIELDTV); private final AndroidTVDynamicCommandDescriptionProvider commandDescriptionProvider; + private final AndroidTVTranslationProvider translationProvider; @Activate public AndroidTVHandlerFactory( - final @Reference AndroidTVDynamicCommandDescriptionProvider commandDescriptionProvider) { + final @Reference AndroidTVDynamicCommandDescriptionProvider commandDescriptionProvider, + final @Reference TranslationProvider i18nProvider, final @Reference LocaleProvider localeProvider) { this.commandDescriptionProvider = commandDescriptionProvider; + this.translationProvider = new AndroidTVTranslationProvider(i18nProvider, localeProvider); } @Override @@ -56,6 +61,6 @@ public class AndroidTVHandlerFactory extends BaseThingHandlerFactory { @Override protected @Nullable ThingHandler createHandler(Thing thing) { ThingTypeUID thingTypeUID = thing.getThingTypeUID(); - return new AndroidTVHandler(thing, commandDescriptionProvider, thingTypeUID); + return new AndroidTVHandler(thing, commandDescriptionProvider, translationProvider, thingTypeUID); } } diff --git a/bundles/org.openhab.binding.androidtv/src/main/java/org/openhab/binding/androidtv/internal/AndroidTVTranslationProvider.java b/bundles/org.openhab.binding.androidtv/src/main/java/org/openhab/binding/androidtv/internal/AndroidTVTranslationProvider.java new file mode 100644 index 00000000000..1b9fd182128 --- /dev/null +++ b/bundles/org.openhab.binding.androidtv/src/main/java/org/openhab/binding/androidtv/internal/AndroidTVTranslationProvider.java @@ -0,0 +1,54 @@ +/** + * Copyright (c) 2010-2023 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.androidtv.internal; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.core.i18n.LocaleProvider; +import org.openhab.core.i18n.TranslationProvider; +import org.osgi.framework.Bundle; +import org.osgi.framework.FrameworkUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * {@link AndroidTVTranslationProvider} provides i18n message lookup. + * + * @author Ben Rosenblum - Initial contribution + */ +@NonNullByDefault +public class AndroidTVTranslationProvider { + + private final Bundle bundle; + private final TranslationProvider i18nProvider; + private final LocaleProvider localeProvider; + private final Logger logger = LoggerFactory.getLogger(AndroidTVTranslationProvider.class); + + public AndroidTVTranslationProvider(TranslationProvider i18nProvider, LocaleProvider localeProvider) { + this.bundle = FrameworkUtil.getBundle(this.getClass()); + this.i18nProvider = i18nProvider; + this.localeProvider = localeProvider; + } + + public String getText(String key, @Nullable Object... arguments) { + @Nullable + String text = i18nProvider.getText(bundle, key, null, localeProvider.getLocale(), arguments); + if (text != null) { + logger.trace("Translated: {} as {}", key, text); + return text; + } else { + logger.trace("Failed to translate: {}", key); + return key; + } + } +} diff --git a/bundles/org.openhab.binding.androidtv/src/main/java/org/openhab/binding/androidtv/internal/protocol/googletv/GoogleTVConnectionManager.java b/bundles/org.openhab.binding.androidtv/src/main/java/org/openhab/binding/androidtv/internal/protocol/googletv/GoogleTVConnectionManager.java index d6046545994..92ac284549f 100644 --- a/bundles/org.openhab.binding.androidtv/src/main/java/org/openhab/binding/androidtv/internal/protocol/googletv/GoogleTVConnectionManager.java +++ b/bundles/org.openhab.binding.androidtv/src/main/java/org/openhab/binding/androidtv/internal/protocol/googletv/GoogleTVConnectionManager.java @@ -60,6 +60,7 @@ import javax.net.ssl.X509TrustManager; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; import org.openhab.binding.androidtv.internal.AndroidTVHandler; +import org.openhab.binding.androidtv.internal.AndroidTVTranslationProvider; import org.openhab.binding.androidtv.internal.utils.AndroidTVPKI; import org.openhab.core.OpenHAB; import org.openhab.core.library.types.NextPreviousType; @@ -97,6 +98,7 @@ public class GoogleTVConnectionManager { private final AndroidTVHandler handler; private GoogleTVConfiguration config; + private final AndroidTVTranslationProvider translationProvider; private @NonNullByDefault({}) SSLSocketFactory sslSocketFactory; private @Nullable SSLSocket sslSocket; @@ -166,6 +168,7 @@ public class GoogleTVConnectionManager { messageParser = new GoogleTVMessageParser(this); this.config = config; this.handler = handler; + this.translationProvider = handler.getTranslationProvider(); this.connectionManager = this; this.scheduler = handler.getScheduler(); this.encryptionKey = androidtvPKI.generateEncryptionKey(); @@ -177,6 +180,7 @@ public class GoogleTVConnectionManager { messageParser = new GoogleTVMessageParser(this); this.config = config; this.handler = handler; + this.translationProvider = handler.getTranslationProvider(); this.connectionManager = connectionManager; this.scheduler = handler.getScheduler(); this.encryptionKey = androidtvPKI.generateEncryptionKey(); @@ -298,16 +302,17 @@ public class GoogleTVConnectionManager { private void setStatus(boolean isLoggedIn) { if (isLoggedIn) { - setStatus(isLoggedIn, "ONLINE"); + setStatus(isLoggedIn, "online.online"); } else { - setStatus(isLoggedIn, "UNKNOWN"); + setStatus(isLoggedIn, "offline.unknown"); } } private void setStatus(boolean isLoggedIn, String statusMessage) { - if ((this.isLoggedIn != isLoggedIn) || (!this.statusMessage.equals(statusMessage))) { + String translatedMessage = translationProvider.getText(statusMessage); + if ((this.isLoggedIn != isLoggedIn) || (!this.statusMessage.equals(translatedMessage))) { this.isLoggedIn = isLoggedIn; - this.statusMessage = statusMessage; + this.statusMessage = translatedMessage; handler.checkThingStatus(); } } @@ -501,10 +506,10 @@ public class GoogleTVConnectionManager { shimAsyncInitializeTask = scheduler.submit(this::shimInitialize); } } catch (NoSuchAlgorithmException | IOException e) { - setStatus(false, "Error initializing keystore"); + setStatus(false, "offline.error-initalizing-keystore"); logger.debug("Error initializing keystore", e); } catch (UnrecoverableKeyException e) { - setStatus(false, "Key unrecoverable with supplied password"); + setStatus(false, "offline.key-unrecoverable-with-supplied-password"); } catch (GeneralSecurityException e) { logger.debug("General security exception", e); } catch (Exception e) { @@ -530,12 +535,12 @@ public class GoogleTVConnectionManager { logger.debug("{} - Connection to {}:{} {} successful", handler.getThingID(), config.ipAddress, config.port, config.mode); } catch (UnknownHostException e) { - setStatus(false, "Unknown host"); + setStatus(false, "offline.unknown-host"); logger.debug("{} - Unknown host {}", handler.getThingID(), config.ipAddress); return; } catch (IllegalArgumentException e) { // port out of valid range - setStatus(false, "Invalid port number"); + setStatus(false, "offline.invalid-port-number"); logger.debug("{} - Invalid port number {}:{}", handler.getThingID(), config.ipAddress, config.port); return; } catch (InterruptedIOException e) { @@ -546,7 +551,7 @@ public class GoogleTVConnectionManager { String message = e.getMessage(); if ((message != null) && (message.contains("certificate_unknown")) && (!config.mode.equals(PIN_MODE)) && (!config.shim)) { - setStatus(false, "PIN Process Incomplete"); + setStatus(false, "offline.pin-process-incomplete"); logger.debug("{} - GoogleTV PIN Process Incomplete", handler.getThingID()); reconnectTaskCancel(true); startChildConnectionManager(this.config.port + 1, PIN_MODE); @@ -562,8 +567,8 @@ public class GoogleTVConnectionManager { this.shimServerSocket = null; } } else { - setStatus(false, "Error opening GoogleTV SSL connection. Check log."); - logger.info("{} - Error opening GoogleTV SSL connection to {}:{} {}", handler.getThingID(), + setStatus(false, "offline.error-opening-ssl-connection-check-log"); + logger.info("{} - Error opening SSL connection to {}:{} {}", handler.getThingID(), config.ipAddress, config.port, e.getMessage()); disconnect(false); scheduleConnectRetry(config.reconnect); // Possibly a temporary problem. Try again later. @@ -571,7 +576,7 @@ public class GoogleTVConnectionManager { return; } - setStatus(false, "Initializing"); + setStatus(false, "offline.initializing"); logger.trace("{} - Starting Reader Thread for {}:{}", handler.getThingID(), config.ipAddress, config.port); @@ -826,7 +831,7 @@ public class GoogleTVConnectionManager { synchronized (connectionLock) { if (!this.disposing) { logger.debug("{} - Attempting to reconnect to the GoogleTV", handler.getThingID()); - setStatus(false, "reconnecting"); + setStatus(false, "offline.reconnecting"); disconnect(false); connect(); } @@ -852,12 +857,12 @@ public class GoogleTVConnectionManager { } } catch (InterruptedIOException e) { logger.debug("Interrupted while sending to GoogleTV"); - setStatus(false, "Interrupted"); + setStatus(false, "offline.interrupted"); break; // exit loop and terminate thread } catch (IOException e) { logger.warn("{} - Communication error, will try to reconnect GoogleTV. Error: {}", handler.getThingID(), e.getMessage()); - setStatus(false, "Communication error, will try to reconnect"); + setStatus(false, "offline.communication-error-will-try-to-reconnect"); sendQueue.add(command); // Requeue command this.isLoggedIn = false; reconnect(); @@ -944,12 +949,12 @@ public class GoogleTVConnectionManager { } } catch (InterruptedIOException e) { logger.debug("Interrupted while reading"); - setStatus(false, "Interrupted"); + setStatus(false, "offline.interrupted"); } catch (IOException e) { String message = e.getMessage(); if ((message != null) && (message.contains("certificate_unknown")) && (!config.mode.equals(PIN_MODE)) && (!config.shim)) { - setStatus(false, "PIN Process Incomplete"); + setStatus(false, "offline.pin-process-incomplete"); logger.debug("{} - GoogleTV PIN Process Incomplete", handler.getThingID()); reconnectTaskCancel(true); startChildConnectionManager(this.config.port + 1, PIN_MODE); @@ -966,11 +971,11 @@ public class GoogleTVConnectionManager { } } else { logger.debug("I/O error while reading from stream: {}", e.getMessage()); - setStatus(false, "I/O Error"); + setStatus(false, "offline.io-error"); } } catch (RuntimeException e) { logger.warn("Runtime exception in reader thread", e); - setStatus(false, "Runtime exception"); + setStatus(false, "offline.runtime-exception"); } finally { logger.debug("{} - Message reader thread exiting {}", handler.getThingID(), config.port); } @@ -1038,13 +1043,13 @@ public class GoogleTVConnectionManager { } } catch (InterruptedIOException e) { logger.debug("Interrupted while reading"); - setStatus(false, "Interrupted"); + setStatus(false, "offline.interrupted"); } catch (IOException e) { logger.debug("I/O error while reading from stream: {}", e.getMessage()); - setStatus(false, "I/O Error"); + setStatus(false, "offline.io-error"); } catch (RuntimeException e) { logger.warn("Runtime exception in reader thread", e); - setStatus(false, "Runtime exception"); + setStatus(false, "offline.runtime-exception"); } finally { logger.debug("Shim message reader thread exiting {}", config.port); } @@ -1263,7 +1268,7 @@ public class GoogleTVConnectionManager { if (config.mode.equals(DEFAULT_MODE)) { if ((!isLoggedIn) && (command.toString().equals("REQUEST")) && (childConnectionManager == null)) { - setStatus(false, "User Forced PIN Process"); + setStatus(false, "offline.user-forced-pin-process"); logger.debug("{} - User Forced PIN Process", handler.getThingID()); disconnect(true); startChildConnectionManager(config.port + 1, PIN_MODE); diff --git a/bundles/org.openhab.binding.androidtv/src/main/java/org/openhab/binding/androidtv/internal/protocol/shieldtv/ShieldTVConnectionManager.java b/bundles/org.openhab.binding.androidtv/src/main/java/org/openhab/binding/androidtv/internal/protocol/shieldtv/ShieldTVConnectionManager.java index 3fed339d5b6..c52937c9ac6 100644 --- a/bundles/org.openhab.binding.androidtv/src/main/java/org/openhab/binding/androidtv/internal/protocol/shieldtv/ShieldTVConnectionManager.java +++ b/bundles/org.openhab.binding.androidtv/src/main/java/org/openhab/binding/androidtv/internal/protocol/shieldtv/ShieldTVConnectionManager.java @@ -58,6 +58,7 @@ import javax.net.ssl.X509TrustManager; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; import org.openhab.binding.androidtv.internal.AndroidTVHandler; +import org.openhab.binding.androidtv.internal.AndroidTVTranslationProvider; import org.openhab.binding.androidtv.internal.utils.AndroidTVPKI; import org.openhab.core.OpenHAB; import org.openhab.core.library.types.StringType; @@ -87,6 +88,7 @@ public class ShieldTVConnectionManager { private final AndroidTVHandler handler; private ShieldTVConfiguration config; + private final AndroidTVTranslationProvider translationProvider; private @NonNullByDefault({}) SSLSocketFactory sslSocketFactory; private @Nullable SSLSocket sslSocket; @@ -148,6 +150,7 @@ public class ShieldTVConnectionManager { messageParser = new ShieldTVMessageParser(this); this.config = config; this.handler = handler; + this.translationProvider = handler.getTranslationProvider(); this.scheduler = handler.getScheduler(); this.encryptionKey = androidtvPKI.generateEncryptionKey(); initialize(); @@ -215,16 +218,17 @@ public class ShieldTVConnectionManager { private void setStatus(boolean isLoggedIn) { if (isLoggedIn) { - setStatus(isLoggedIn, "ONLINE"); + setStatus(isLoggedIn, "online.online"); } else { - setStatus(isLoggedIn, "UNKNOWN"); + setStatus(isLoggedIn, "offline.unknown"); } } private void setStatus(boolean isLoggedIn, String statusMessage) { - if ((this.isLoggedIn != isLoggedIn) || (!this.statusMessage.equals(statusMessage))) { + String translatedMessage = translationProvider.getText(statusMessage); + if ((this.isLoggedIn != isLoggedIn) || (!this.statusMessage.equals(translatedMessage))) { this.isLoggedIn = isLoggedIn; - this.statusMessage = statusMessage; + this.statusMessage = translatedMessage; handler.checkThingStatus(); } } @@ -399,10 +403,10 @@ public class ShieldTVConnectionManager { shimAsyncInitializeTask = scheduler.submit(this::shimInitialize); } } catch (NoSuchAlgorithmException | IOException e) { - setStatus(false, "Error initializing keystore"); + setStatus(false, "offline.error-initalizing-keystore"); logger.debug("Error initializing keystore", e); } catch (UnrecoverableKeyException e) { - setStatus(false, "Key unrecoverable with supplied password"); + setStatus(false, "offline.key-unrecoverable-with-supplied-password"); } catch (GeneralSecurityException e) { logger.debug("General security exception", e); } catch (Exception e) { @@ -424,26 +428,26 @@ public class ShieldTVConnectionManager { new InputStreamReader(sslSocket.getInputStream(), StandardCharsets.ISO_8859_1)); this.sslSocket = sslSocket; } catch (UnknownHostException e) { - setStatus(false, "Unknown host"); + setStatus(false, "offline.unknown-host"); return; } catch (IllegalArgumentException e) { // port out of valid range - setStatus(false, "Invalid port number"); + setStatus(false, "offline.invalid-port-number"); return; } catch (InterruptedIOException e) { logger.debug("Interrupted while establishing ShieldTV connection"); Thread.currentThread().interrupt(); return; } catch (IOException e) { - setStatus(false, "Error opening ShieldTV SSL connection. Check log."); - logger.info("{} - Error opening ShieldTV SSL connection to {}:{} {}", handler.getThingID(), - config.ipAddress, config.port, e.getMessage()); + setStatus(false, "offline.error-opening-ssl-connection-check-log"); + logger.info("{} - Error opening SSL connection to {}:{} {}", handler.getThingID(), config.ipAddress, + config.port, e.getMessage()); disconnect(false); scheduleConnectRetry(config.reconnect); // Possibly a temporary problem. Try again later. return; } - setStatus(false, "Initializing"); + setStatus(false, "offline.initializing"); Thread readerThread = new Thread(this::readerThreadJob, "ShieldTV reader " + handler.getThingID()); readerThread.setDaemon(true); @@ -640,7 +644,7 @@ public class ShieldTVConnectionManager { synchronized (connectionLock) { if (!this.disposing) { logger.debug("{} - Attempting to reconnect to the ShieldTV", handler.getThingID()); - setStatus(false, "reconnecting"); + setStatus(false, "offline.reconnecting"); disconnect(false); connect(); } @@ -666,12 +670,12 @@ public class ShieldTVConnectionManager { } } catch (InterruptedIOException e) { logger.debug("Interrupted while sending to ShieldTV"); - setStatus(false, "Interrupted"); + setStatus(false, "offline.interrupted"); break; // exit loop and terminate thread } catch (IOException e) { logger.warn("{} - Communication error, will try to reconnect ShieldTV. Error: {}", handler.getThingID(), e.getMessage()); - setStatus(false, "Communication error, will try to reconnect"); + setStatus(false, "offline.communication-error-will-try-to-reconnect"); sendQueue.add(command); // Requeue command this.isLoggedIn = false; reconnect(); @@ -785,13 +789,13 @@ public class ShieldTVConnectionManager { } } catch (InterruptedIOException e) { logger.debug("Interrupted while reading"); - setStatus(false, "Interrupted"); + setStatus(false, "offline.interrupted"); } catch (IOException e) { logger.debug("I/O error while reading from stream: {}", e.getMessage()); - setStatus(false, "I/O Error"); + setStatus(false, "offline.io-error"); } catch (RuntimeException e) { logger.warn("Runtime exception in reader thread", e); - setStatus(false, "Runtime exception"); + setStatus(false, "offline.runtime-exception"); } finally { logger.debug("{} - Message reader thread exiting", handler.getThingID()); } @@ -886,13 +890,13 @@ public class ShieldTVConnectionManager { } } catch (InterruptedIOException e) { logger.debug("Interrupted while reading"); - setStatus(false, "Interrupted"); + setStatus(false, "offline.interrupted"); } catch (IOException e) { logger.debug("I/O error while reading from stream: {}", e.getMessage()); - setStatus(false, "I/O Error"); + setStatus(false, "offline.io-error"); } catch (RuntimeException e) { logger.warn("Runtime exception in reader thread", e); - setStatus(false, "Runtime exception"); + setStatus(false, "offline.runtime-exception"); } finally { logger.debug("Message reader thread exiting"); } diff --git a/bundles/org.openhab.binding.androidtv/src/main/resources/OH-INF/i18n/androidtv.properties b/bundles/org.openhab.binding.androidtv/src/main/resources/OH-INF/i18n/androidtv.properties index d8a2799c291..91cb9eb79dd 100644 --- a/bundles/org.openhab.binding.androidtv/src/main/resources/OH-INF/i18n/androidtv.properties +++ b/bundles/org.openhab.binding.androidtv/src/main/resources/OH-INF/i18n/androidtv.properties @@ -66,4 +66,19 @@ channel-type.androidtv.player.description = Player Control offline.protocols-starting = Protocols Starting offline.googletv-address-not-specified = googletv address not specified offline.shieldtv-address-not-specified = shieldtv address not specified +offline.error-initalizing-keystore = Error initializing keystore +offline.key-unrecoverable-with-supplied-password = Key unrecoverable with supplied password +offline.unknown-host = Unknown host +offline.invalid-port-number = Invalid port number +offline.pin-process-incomplete = PIN Process Incomplete +offline.error-opening-ssl-connection-check-log = Error opening SSL connection. Check log. +offline.initializing = Initializing +offline.reconnecting = Reconnecting +offline.communication-error-will-try-to-reconnect = Communication error, will try to reconnect +offline.interrupted = Interrupted +offline.io-error = I/O Error +offline.runtime-exception = Runtime exception +offline.user-forced-pin-process = User Forced PIN Process +offline.unknown = Unknown +online.online = Online