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
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:
--- /dev/null
+/**
+ * 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;
+ }
+}
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;
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;
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();
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);
}
}
private void loadMediaStateConfig(String mediaStateJSONConfig) {
+ List<CommandOption> 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
static class AndroidDebugBridgeMediaStatePackageConfig {
public String name = "";
+ public @Nullable String label;
public String mode = "";
public List<Integer> wakeLockPlayStates = List.of();
+
+ public CommandOption toCommandOption() {
+ return new CommandOption(name, label == null ? name : label);
+ }
}
}
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
@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);
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;
}