From: Christoph Weitkamp Date: Sun, 20 Mar 2022 07:56:58 +0000 (+0100) Subject: [androiddebugbridge] Added DynamicCommandOptionsProvider to populate 'start-package... X-Git-Url: https://git.basschouten.com/?a=commitdiff_plain;h=5a9e70ca6a818f167951b556cb5742aa4972f253;p=openhab-addons.git [androiddebugbridge] Added DynamicCommandOptionsProvider to populate 'start-package' Channel (#12491) Signed-off-by: Christoph Weitkamp --- diff --git a/bundles/org.openhab.binding.androiddebugbridge/README.md b/bundles/org.openhab.binding.androiddebugbridge/README.md index bc9ed776ac..034e07018f 100644 --- a/bundles/org.openhab.binding.androiddebugbridge/README.md +++ b/bundles/org.openhab.binding.androiddebugbridge/README.md @@ -63,9 +63,9 @@ The available modes are: The configuration depends on the application, device and version used. -This is a sample of the mediaStateJSONConfig thing configuration: +This is a sample of the mediaStateJSONConfig thing configuration - the `label` is optional: -`[{"name": "com.amazon.tv.launcher", "mode": "idle"},{"name": "org.jellyfin.androidtv", "mode": "wake_lock", "wakeLockPlayStates": [2,3]},{"name": "com.amazon.firetv.youtube", "mode": "wake_lock", "wakeLockPlayStates": [2]}]` +`[{"name": "com.amazon.tv.launcher", "mode": "idle"}, {"name": "org.jellyfin.androidtv", "mode": "wake_lock", "wakeLockPlayStates": [2,3]}, {"name": "com.amazon.firetv.youtube", "label":"YouTube", "mode": "wake_lock", "wakeLockPlayStates": [2]}]` ## Record/Send input events @@ -80,27 +80,26 @@ An example of what you can do: Please note that events could fail if the input method is removed, for example it could fail if you clone the events of a bluetooth controller and the remote goes offline. This is happening for me when recording the Fire TV remote events but not for my Xiaomi TV which also has a bt remote controller. - ## Channels -| channel | type | description | -|----------|--------|------------------------------| -| key-event | String | Send key event to android device. Possible values listed below | -| text | String | Send text to android device | -| tap | String | Send tap event to android device (format x,y) | -| url | String | Open url in browser | -| media-volume | Dimmer | Set or get media volume level on android device | -| media-control | Player | Control media on android device | -| start-package | String | Run application by package name | -| stop-package | String | Stop application by package name | -| stop-current-package | String | Stop current application | -| current-package | String | Package name of the top application in screen | -| record-input | String | Capture events, generate the equivalent command and store it under the provided name | -| recorded-input | String | Emulates previously captured input events by name | -| shutdown | String | Power off/reboot device (allowed values POWER_OFF, REBOOT) | -| awake-state | OnOff | Awake state value. | -| wake-lock | Number | Power wake lock value | -| screen-state | Switch | Screen power state | +| channel | type | description | +|----------------------|--------|-------------------------------------------------------------------------------------------------------------------------------| +| key-event | String | Send key event to android device. Possible values listed below | +| text | String | Send text to android device | +| tap | String | Send tap event to android device (format x,y) | +| url | String | Open url in browser | +| media-volume | Dimmer | Set or get media volume level on android device | +| media-control | Player | Control media on android device | +| start-package | String | Run application by package name. The commands for this Channel are populated dynamically based on the `mediaStateJSONConfig`. | +| stop-package | String | Stop application by package name | +| stop-current-package | String | Stop current application | +| current-package | String | Package name of the top application in screen | +| record-input | String | Capture events, generate the equivalent command and store it under the provided name | +| recorded-input | String | Emulates previously captured input events by name | +| shutdown | String | Power off/reboot device (allowed values POWER_OFF, REBOOT) | +| awake-state | OnOff | Awake state value. | +| wake-lock | Number | Power wake lock value | +| screen-state | Switch | Screen power state | #### Available key-event values: diff --git a/bundles/org.openhab.binding.androiddebugbridge/src/main/java/org/openhab/binding/androiddebugbridge/internal/AndroidDebugBridgeDynamicCommandDescriptionProvider.java b/bundles/org.openhab.binding.androiddebugbridge/src/main/java/org/openhab/binding/androiddebugbridge/internal/AndroidDebugBridgeDynamicCommandDescriptionProvider.java new file mode 100644 index 0000000000..75311dccef --- /dev/null +++ b/bundles/org.openhab.binding.androiddebugbridge/src/main/java/org/openhab/binding/androiddebugbridge/internal/AndroidDebugBridgeDynamicCommandDescriptionProvider.java @@ -0,0 +1,42 @@ +/** + * Copyright (c) 2010-2022 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.androiddebugbridge.internal; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.core.events.EventPublisher; +import org.openhab.core.thing.binding.BaseDynamicCommandDescriptionProvider; +import org.openhab.core.thing.i18n.ChannelTypeI18nLocalizationService; +import org.openhab.core.thing.link.ItemChannelLinkRegistry; +import org.openhab.core.thing.type.DynamicCommandDescriptionProvider; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; + +/** + * Dynamic provider of command options. + * + * @author Christoph Weitkamp - Initial contribution + */ +@Component(service = { DynamicCommandDescriptionProvider.class, + AndroidDebugBridgeDynamicCommandDescriptionProvider.class }) +@NonNullByDefault +public class AndroidDebugBridgeDynamicCommandDescriptionProvider extends BaseDynamicCommandDescriptionProvider { + @Activate + public AndroidDebugBridgeDynamicCommandDescriptionProvider(final @Reference EventPublisher eventPublisher, // + final @Reference ItemChannelLinkRegistry itemChannelLinkRegistry, // + final @Reference ChannelTypeI18nLocalizationService channelTypeI18nLocalizationService) { + this.eventPublisher = eventPublisher; + this.itemChannelLinkRegistry = itemChannelLinkRegistry; + this.channelTypeI18nLocalizationService = channelTypeI18nLocalizationService; + } +} diff --git a/bundles/org.openhab.binding.androiddebugbridge/src/main/java/org/openhab/binding/androiddebugbridge/internal/AndroidDebugBridgeHandler.java b/bundles/org.openhab.binding.androiddebugbridge/src/main/java/org/openhab/binding/androiddebugbridge/internal/AndroidDebugBridgeHandler.java index 2728f98c71..c442ebfca5 100644 --- a/bundles/org.openhab.binding.androiddebugbridge/src/main/java/org/openhab/binding/androiddebugbridge/internal/AndroidDebugBridgeHandler.java +++ b/bundles/org.openhab.binding.androiddebugbridge/src/main/java/org/openhab/binding/androiddebugbridge/internal/AndroidDebugBridgeHandler.java @@ -22,6 +22,7 @@ import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.regex.Pattern; +import java.util.stream.Collectors; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; @@ -38,6 +39,7 @@ import org.openhab.core.thing.ThingStatus; import org.openhab.core.thing.ThingStatusDetail; import org.openhab.core.thing.binding.BaseThingHandler; import org.openhab.core.types.Command; +import org.openhab.core.types.CommandOption; import org.openhab.core.types.RefreshType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -65,6 +67,8 @@ public class AndroidDebugBridgeHandler extends BaseThingHandler { private static final Gson GSON = new Gson(); private static final Pattern RECORD_NAME_PATTERN = Pattern.compile("^[A-Za-z0-9_]*$"); private final Logger logger = LoggerFactory.getLogger(AndroidDebugBridgeHandler.class); + + private final AndroidDebugBridgeDynamicCommandDescriptionProvider commandDescriptionProvider; private final AndroidDebugBridgeDevice adbConnection; private int maxMediaVolume = 0; private AndroidDebugBridgeConfiguration config = new AndroidDebugBridgeConfiguration(); @@ -72,8 +76,10 @@ public class AndroidDebugBridgeHandler extends BaseThingHandler { private AndroidDebugBridgeMediaStatePackageConfig @Nullable [] packageConfigs = null; private boolean deviceAwake = false; - public AndroidDebugBridgeHandler(Thing thing) { + public AndroidDebugBridgeHandler(Thing thing, + AndroidDebugBridgeDynamicCommandDescriptionProvider commandDescriptionProvider) { super(thing); + this.commandDescriptionProvider = commandDescriptionProvider; this.adbConnection = new AndroidDebugBridgeDevice(scheduler); } @@ -317,12 +323,18 @@ public class AndroidDebugBridgeHandler extends BaseThingHandler { } private void loadMediaStateConfig(String mediaStateJSONConfig) { + List commandOptions; try { - this.packageConfigs = GSON.fromJson(mediaStateJSONConfig, - AndroidDebugBridgeMediaStatePackageConfig[].class); + packageConfigs = GSON.fromJson(mediaStateJSONConfig, AndroidDebugBridgeMediaStatePackageConfig[].class); + commandOptions = Arrays.stream(packageConfigs) + .map(AndroidDebugBridgeMediaStatePackageConfig::toCommandOption) + .collect(Collectors.toUnmodifiableList()); } catch (JsonSyntaxException e) { logger.warn("unable to parse media state config: {}", e.getMessage()); + commandOptions = List.of(); } + commandDescriptionProvider.setCommandOptions(new ChannelUID(getThing().getUID(), START_PACKAGE_CHANNEL), + commandOptions); } @Override @@ -449,7 +461,12 @@ public class AndroidDebugBridgeHandler extends BaseThingHandler { static class AndroidDebugBridgeMediaStatePackageConfig { public String name = ""; + public @Nullable String label; public String mode = ""; public List wakeLockPlayStates = List.of(); + + public CommandOption toCommandOption() { + return new CommandOption(name, label == null ? name : label); + } } } diff --git a/bundles/org.openhab.binding.androiddebugbridge/src/main/java/org/openhab/binding/androiddebugbridge/internal/AndroidDebugBridgeHandlerFactory.java b/bundles/org.openhab.binding.androiddebugbridge/src/main/java/org/openhab/binding/androiddebugbridge/internal/AndroidDebugBridgeHandlerFactory.java index f2bd1710aa..404fd4b9a2 100644 --- a/bundles/org.openhab.binding.androiddebugbridge/src/main/java/org/openhab/binding/androiddebugbridge/internal/AndroidDebugBridgeHandlerFactory.java +++ b/bundles/org.openhab.binding.androiddebugbridge/src/main/java/org/openhab/binding/androiddebugbridge/internal/AndroidDebugBridgeHandlerFactory.java @@ -21,7 +21,9 @@ import org.openhab.core.thing.ThingTypeUID; import org.openhab.core.thing.binding.BaseThingHandlerFactory; import org.openhab.core.thing.binding.ThingHandler; import org.openhab.core.thing.binding.ThingHandlerFactory; +import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; /** * The {@link AndroidDebugBridgeHandlerFactory} is responsible for creating things and thing @@ -33,6 +35,14 @@ import org.osgi.service.component.annotations.Component; @Component(configurationPid = BINDING_CONFIGURATION_PID, service = ThingHandlerFactory.class) public class AndroidDebugBridgeHandlerFactory extends BaseThingHandlerFactory { + private final AndroidDebugBridgeDynamicCommandDescriptionProvider commandDescriptionProvider; + + @Activate + public AndroidDebugBridgeHandlerFactory( + final @Reference AndroidDebugBridgeDynamicCommandDescriptionProvider commandDescriptionProvider) { + this.commandDescriptionProvider = commandDescriptionProvider; + } + @Override public boolean supportsThingType(ThingTypeUID thingTypeUID) { return SUPPORTED_THING_TYPES.contains(thingTypeUID); @@ -42,7 +52,7 @@ public class AndroidDebugBridgeHandlerFactory extends BaseThingHandlerFactory { protected @Nullable ThingHandler createHandler(Thing thing) { ThingTypeUID thingTypeUID = thing.getThingTypeUID(); if (THING_TYPE_ANDROID_DEVICE.equals(thingTypeUID)) { - return new AndroidDebugBridgeHandler(thing); + return new AndroidDebugBridgeHandler(thing, commandDescriptionProvider); } return null; }