diff --git a/bundles/org.openhab.binding.androiddebugbridge/README.md b/bundles/org.openhab.binding.androiddebugbridge/README.md index 46139bb993d70..42549a5182553 100644 --- a/bundles/org.openhab.binding.androiddebugbridge/README.md +++ b/bundles/org.openhab.binding.androiddebugbridge/README.md @@ -50,6 +50,8 @@ You could customize the discovery process through the binding options. | refreshTime | int | Seconds between device status refreshes (default: 30) | | timeout | int | Command timeout in seconds (default: 5) | | recordDuration | int | Record input duration in seconds | +| deviceMaxVolume | int | Assumed max volume for devices with android versions that do not expose this value. | +| volumeSettingKey | String | Settings key for android versions where volume is gather using settings command (>=android 11). | | mediaStateJSONConfig | String | Expects a JSON array. Allow to configure the media state detection method per app. Described in the following section | ## Media State Detection diff --git a/bundles/org.openhab.binding.androiddebugbridge/src/main/java/org/openhab/binding/androiddebugbridge/internal/AndroidDebugBridgeConfiguration.java b/bundles/org.openhab.binding.androiddebugbridge/src/main/java/org/openhab/binding/androiddebugbridge/internal/AndroidDebugBridgeConfiguration.java index b9247ec39155a..1e82b6caa608d 100644 --- a/bundles/org.openhab.binding.androiddebugbridge/src/main/java/org/openhab/binding/androiddebugbridge/internal/AndroidDebugBridgeConfiguration.java +++ b/bundles/org.openhab.binding.androiddebugbridge/src/main/java/org/openhab/binding/androiddebugbridge/internal/AndroidDebugBridgeConfiguration.java @@ -42,6 +42,14 @@ public class AndroidDebugBridgeConfiguration { * Record input duration in seconds. */ public int recordDuration = 5; + /** + * Assumed max volume for devices with android versions that do not expose this value (>=android 11). + */ + public int deviceMaxVolume = 25; + /** + * Settings key for android versions where volume is gather using settings command (>=android 11). + */ + public String volumeSettingKey = "volume_music_hdmi"; /** * Configure media state detection behavior by package */ diff --git a/bundles/org.openhab.binding.androiddebugbridge/src/main/java/org/openhab/binding/androiddebugbridge/internal/AndroidDebugBridgeDevice.java b/bundles/org.openhab.binding.androiddebugbridge/src/main/java/org/openhab/binding/androiddebugbridge/internal/AndroidDebugBridgeDevice.java index c9588ce407713..8201b8240e0cf 100644 --- a/bundles/org.openhab.binding.androiddebugbridge/src/main/java/org/openhab/binding/androiddebugbridge/internal/AndroidDebugBridgeDevice.java +++ b/bundles/org.openhab.binding.androiddebugbridge/src/main/java/org/openhab/binding/androiddebugbridge/internal/AndroidDebugBridgeDevice.java @@ -97,22 +97,34 @@ public class AndroidDebugBridgeDevice { private int port = 5555; private int timeoutSec = 5; private int recordDuration; + private @Nullable Integer maxVolumeLevel = null; private @Nullable Socket socket; private @Nullable AdbConnection connection; private @Nullable Future commandFuture; private int majorVersionNumber = 0; private int minorVersionNumber = 0; private int patchVersionNumber = 0; + /** + * Assumed max volume for android versions that do not expose this value. + */ + private int deviceMaxVolume = 25; + private String volumeSettingKey = "volume_music_hdmi"; public AndroidDebugBridgeDevice(ScheduledExecutorService scheduler) { this.scheduler = scheduler; } - public void configure(String ip, int port, int timeout, int recordDuration) { + public void configure(AndroidDebugBridgeConfiguration config) { + configureConnection(config.ip, config.port, config.timeout); + this.recordDuration = config.recordDuration; + this.volumeSettingKey = config.volumeSettingKey; + this.deviceMaxVolume = config.deviceMaxVolume; + } + + public void configureConnection(String ip, int port, int timeout) { this.ip = ip; this.port = port; this.timeoutSec = timeout; - this.recordDuration = recordDuration; } public void sendKeyEvent(String eventCode) @@ -291,7 +303,16 @@ public int getPowerWakeLock() throws InterruptedException, AndroidDebugBridgeDev private void setVolume(int stream, int volume) throws AndroidDebugBridgeDeviceException, InterruptedException, TimeoutException, ExecutionException { - runAdbShell("media", "volume", "--show", "--stream", String.valueOf(stream), "--set", String.valueOf(volume)); + if (isAtLeastVersion(12)) { + runAdbShell("service", "call", "audio", "11", "i32", String.valueOf(stream), "i32", String.valueOf(volume), + "i32", "1"); + } else if (isAtLeastVersion(11)) { + runAdbShell("service", "call", "audio", "10", "i32", String.valueOf(stream), "i32", String.valueOf(volume), + "i32", "1"); + } else { + runAdbShell("media", "volume", "--show", "--stream", String.valueOf(stream), "--set", + String.valueOf(volume)); + } } public String getModel() throws AndroidDebugBridgeDeviceException, InterruptedException, @@ -353,17 +374,32 @@ private String getDeviceProp(String name) throws AndroidDebugBridgeDeviceExcepti private VolumeInfo getVolume(int stream) throws AndroidDebugBridgeDeviceException, InterruptedException, AndroidDebugBridgeDeviceReadException, TimeoutException, ExecutionException { - String volumeResp = runAdbShell("media", "volume", "--show", "--stream", String.valueOf(stream), "--get", "|", - "grep", "volume"); - Matcher matcher = VOLUME_PATTERN.matcher(volumeResp); - if (!matcher.find()) { - throw new AndroidDebugBridgeDeviceReadException("Unable to get volume info"); + if (isAtLeastVersion(11)) { + String volumeResp = runAdbShell("settings", "get", "system", volumeSettingKey); + var maxVolumeLevel = this.maxVolumeLevel; + if (maxVolumeLevel == null) { + try { + maxVolumeLevel = Integer.parseInt(getDeviceProp("ro.config.media_vol_steps")); + this.maxVolumeLevel = maxVolumeLevel; + } catch (NumberFormatException ignored) { + logger.debug("Max volume level not available, using 'deviceMaxVolume' config"); + maxVolumeLevel = deviceMaxVolume; + } + } + return new VolumeInfo(Integer.parseInt(volumeResp.replace("\n", "")), 0, maxVolumeLevel); + } else { + String volumeResp = runAdbShell("media", "volume", "--show", "--stream", String.valueOf(stream), "--get", + "|", "grep", "volume"); + Matcher matcher = VOLUME_PATTERN.matcher(volumeResp); + if (!matcher.find()) { + throw new AndroidDebugBridgeDeviceReadException("Unable to get volume info"); + } + var volumeInfo = new VolumeInfo(Integer.parseInt(matcher.group("current")), + Integer.parseInt(matcher.group("min")), Integer.parseInt(matcher.group("max"))); + logger.debug("Device {}:{} VolumeInfo: current {}, min {}, max {}", this.ip, this.port, volumeInfo.current, + volumeInfo.min, volumeInfo.max); + return volumeInfo; } - var volumeInfo = new VolumeInfo(Integer.parseInt(matcher.group("current")), - Integer.parseInt(matcher.group("min")), Integer.parseInt(matcher.group("max"))); - logger.debug("Device {}:{} VolumeInfo: current {}, min {}, max {}", this.ip, this.port, volumeInfo.current, - volumeInfo.min, volumeInfo.max); - return volumeInfo; } public String recordInputEvents() 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 5a1605721bea4..80c7b227dfda8 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 @@ -320,8 +320,7 @@ public void initialize() { if (mediaStateJSONConfig != null && !mediaStateJSONConfig.isEmpty()) { loadMediaStateConfig(mediaStateJSONConfig); } - adbConnection.configure(currentConfig.ip, currentConfig.port, currentConfig.timeout, - currentConfig.recordDuration); + adbConnection.configure(currentConfig); var androidVersion = thing.getProperties().get(Thing.PROPERTY_FIRMWARE_VERSION); if (androidVersion != null) { // configure android implementation to use diff --git a/bundles/org.openhab.binding.androiddebugbridge/src/main/java/org/openhab/binding/androiddebugbridge/internal/discovery/AndroidDebugBridgeDiscoveryService.java b/bundles/org.openhab.binding.androiddebugbridge/src/main/java/org/openhab/binding/androiddebugbridge/internal/discovery/AndroidDebugBridgeDiscoveryService.java index a64975f5c52e6..de744d5e89249 100644 --- a/bundles/org.openhab.binding.androiddebugbridge/src/main/java/org/openhab/binding/androiddebugbridge/internal/discovery/AndroidDebugBridgeDiscoveryService.java +++ b/bundles/org.openhab.binding.androiddebugbridge/src/main/java/org/openhab/binding/androiddebugbridge/internal/discovery/AndroidDebugBridgeDiscoveryService.java @@ -135,7 +135,7 @@ private void discoverWithADB(String ip, int port, String macAddress) throws InterruptedException, AndroidDebugBridgeDeviceException, AndroidDebugBridgeDeviceReadException, TimeoutException, ExecutionException { var device = new AndroidDebugBridgeDevice(scheduler); - device.configure(ip, port, 10, 0); + device.configureConnection(ip, port, 10); try { device.connect(); logger.debug("connected adb at {}:{}", ip, port); diff --git a/bundles/org.openhab.binding.androiddebugbridge/src/main/java/org/openhab/binding/androiddebugbridge/internal/discovery/AndroidTVMDNSDiscoveryParticipant.java b/bundles/org.openhab.binding.androiddebugbridge/src/main/java/org/openhab/binding/androiddebugbridge/internal/discovery/AndroidTVMDNSDiscoveryParticipant.java index 55923016066b7..96c5832c96c0a 100644 --- a/bundles/org.openhab.binding.androiddebugbridge/src/main/java/org/openhab/binding/androiddebugbridge/internal/discovery/AndroidTVMDNSDiscoveryParticipant.java +++ b/bundles/org.openhab.binding.androiddebugbridge/src/main/java/org/openhab/binding/androiddebugbridge/internal/discovery/AndroidTVMDNSDiscoveryParticipant.java @@ -34,8 +34,6 @@ import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Modified; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** * The {@link AndroidTVMDNSDiscoveryParticipant} is responsible for discovering new and removed Android TV devices. It @@ -50,7 +48,6 @@ public class AndroidTVMDNSDiscoveryParticipant implements MDNSDiscoveryParticipa private static final String SERVICE_TYPE = "_androidtvremote2._tcp.local."; private static final String MDNS_PROPERTY_MAC_ADDRESS = "bt"; - private final Logger logger = LoggerFactory.getLogger(AndroidTVMDNSDiscoveryParticipant.class); private boolean isAutoDiscoveryEnabled = true; diff --git a/bundles/org.openhab.binding.androiddebugbridge/src/main/resources/OH-INF/i18n/androiddebugbridge.properties b/bundles/org.openhab.binding.androiddebugbridge/src/main/resources/OH-INF/i18n/androiddebugbridge.properties index 4556f4cd8b740..dda2d597d8e24 100644 --- a/bundles/org.openhab.binding.androiddebugbridge/src/main/resources/OH-INF/i18n/androiddebugbridge.properties +++ b/bundles/org.openhab.binding.androiddebugbridge/src/main/resources/OH-INF/i18n/androiddebugbridge.properties @@ -21,6 +21,8 @@ thing-type.androiddebugbridge.android.description = Android Device Thing for And # thing types config +thing-type.config.androiddebugbridge.android.deviceMaxVolume.label = Device Max Volume +thing-type.config.androiddebugbridge.android.deviceMaxVolume.description = Assumed max volume for devices with android versions that do not expose this value (>=android 11). thing-type.config.androiddebugbridge.android.ip.label = IP Address thing-type.config.androiddebugbridge.android.ip.description = Device ip address. thing-type.config.androiddebugbridge.android.mediaStateJSONConfig.label = Media State Config @@ -33,6 +35,16 @@ thing-type.config.androiddebugbridge.android.refreshTime.label = Refresh Time thing-type.config.androiddebugbridge.android.refreshTime.description = Seconds between device status refreshes. thing-type.config.androiddebugbridge.android.timeout.label = Command Timeout thing-type.config.androiddebugbridge.android.timeout.description = Command timeout seconds. +thing-type.config.androiddebugbridge.android.volumeSettingKey.label = Volume Setting Key +thing-type.config.androiddebugbridge.android.volumeSettingKey.description = Settings key for android versions where the volume level is gathered using the 'settings' cli (>=android 11). +thing-type.config.androiddebugbridge.android.volumeSettingKey.option.volume_bluetooth_sco = volume bluetooth sco +thing-type.config.androiddebugbridge.android.volumeSettingKey.option.volume_music = volume music +thing-type.config.androiddebugbridge.android.volumeSettingKey.option.volume_music_bt_a2dp = volume music bt a2dp +thing-type.config.androiddebugbridge.android.volumeSettingKey.option.volume_music_hdmi = volume music hdmi +thing-type.config.androiddebugbridge.android.volumeSettingKey.option.volume_music_headphone = volume music headphone +thing-type.config.androiddebugbridge.android.volumeSettingKey.option.volume_music_headset = volume music headset +thing-type.config.androiddebugbridge.android.volumeSettingKey.option.volume_music_usb_headset = volume music usb headset +thing-type.config.androiddebugbridge.android.volumeSettingKey.option.volume_system = volume system # channel types diff --git a/bundles/org.openhab.binding.androiddebugbridge/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.androiddebugbridge/src/main/resources/OH-INF/thing/thing-types.xml index 79d8176741893..4814599276e38 100644 --- a/bundles/org.openhab.binding.androiddebugbridge/src/main/resources/OH-INF/thing/thing-types.xml +++ b/bundles/org.openhab.binding.androiddebugbridge/src/main/resources/OH-INF/thing/thing-types.xml @@ -58,6 +58,29 @@ JSON config that allows to modify the media state detection strategy for each app. Refer to the binding documentation. + + + Settings key for android versions where the volume level is gathered using the 'settings' cli + (>=android 11). + volume_music_hdmi + + + + + + + + + + + true + + + + Assumed max volume for devices with android versions that do not expose this value (>=android 11). + 25 + true +