]> git.basschouten.com Git - openhab-addons.git/commitdiff
[androiddebugbridge] Fix volume channel for android 11/12 (#13828)
authorGiviMAD <GiviMAD@users.noreply.github.com>
Sat, 3 Dec 2022 16:40:29 +0000 (17:40 +0100)
committerGitHub <noreply@github.com>
Sat, 3 Dec 2022 16:40:29 +0000 (17:40 +0100)
* [androiddebugbridge] Fix volume channel for android 11/12
* [androiddebugbridge] Try get max volume level from device properties
* [androiddebugbridge] Fixes reported code analysis
* [androiddebugbridge] Fix comparison

Signed-off-by: Miguel Álvarez <miguelwork92@gmail.com>
bundles/org.openhab.binding.androiddebugbridge/README.md
bundles/org.openhab.binding.androiddebugbridge/src/main/java/org/openhab/binding/androiddebugbridge/internal/AndroidDebugBridgeConfiguration.java
bundles/org.openhab.binding.androiddebugbridge/src/main/java/org/openhab/binding/androiddebugbridge/internal/AndroidDebugBridgeDevice.java
bundles/org.openhab.binding.androiddebugbridge/src/main/java/org/openhab/binding/androiddebugbridge/internal/AndroidDebugBridgeHandler.java
bundles/org.openhab.binding.androiddebugbridge/src/main/java/org/openhab/binding/androiddebugbridge/internal/discovery/AndroidDebugBridgeDiscoveryService.java
bundles/org.openhab.binding.androiddebugbridge/src/main/java/org/openhab/binding/androiddebugbridge/internal/discovery/AndroidTVMDNSDiscoveryParticipant.java
bundles/org.openhab.binding.androiddebugbridge/src/main/resources/OH-INF/i18n/androiddebugbridge.properties
bundles/org.openhab.binding.androiddebugbridge/src/main/resources/OH-INF/thing/thing-types.xml

index 46139bb993d704f832c6647158b368edd2ccb63c..42549a5182553b8dbf3d7f19a317141c902a8880 100644 (file)
@@ -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
index b9247ec39155a486f8902ba385a01c3afbf71691..1e82b6caa608d8748c42d81161708617e7d40ad1 100644 (file)
@@ -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
      */
index c9588ce40771316d8295b420f9bbaf97f6c1f9af..8201b8240e0cf8699832ab761c1a983c5380e1d3 100644 (file)
@@ -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<String> 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 class AndroidDebugBridgeDevice {
 
     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 @@ public class AndroidDebugBridgeDevice {
 
     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()
index 5a1605721bea4474e738a14e18e1fc5da8931445..80c7b227dfda83e2f7a5357fef9963c4345f41e5 100644 (file)
@@ -320,8 +320,7 @@ public class AndroidDebugBridgeHandler extends BaseThingHandler {
         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
index a64975f5c52e6ae68ee36e6ec5db50685418b6b2..de744d5e892496a52f1abf56891fb8a46ed6718e 100644 (file)
@@ -135,7 +135,7 @@ public class AndroidDebugBridgeDiscoveryService extends AbstractDiscoveryService
             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);
index 55923016066b796b31ed7401476e6b54dec7b976..96c5832c96c0ac36ab68ebfe5368487801fea08b 100644 (file)
@@ -34,8 +34,6 @@ import org.osgi.service.component.ComponentContext;
 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;
 
index 4556f4cd8b740ef24a7f355613f1c4adbddc228a..dda2d597d8e2435e8895da7b17cacd632bb347ea 100644 (file)
@@ -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
 
index 79d817674189374785c63a431c81e5ff588a468a..4814599276e38e075753634c1a30924e1a3a7561 100644 (file)
                                <description>JSON config that allows to modify the media state detection strategy for each app. Refer to the binding
                                        documentation.</description>
                        </parameter>
+                       <parameter name="volumeSettingKey" type="text">
+                               <label>Volume Setting Key</label>
+                               <description>Settings key for android versions where the volume level is gathered using the 'settings' cli
+                                       (>=android 11).</description>
+                               <default>volume_music_hdmi</default>
+                               <options>
+                                       <option value="volume_bluetooth_sco">volume bluetooth sco</option>
+                                       <option value="volume_music">volume music</option>
+                                       <option value="volume_music_bt_a2dp">volume music bt a2dp</option>
+                                       <option value="volume_music_hdmi">volume music hdmi</option>
+                                       <option value="volume_music_headphone">volume music headphone</option>
+                                       <option value="volume_music_headset">volume music headset</option>
+                                       <option value="volume_music_usb_headset">volume music usb headset</option>
+                                       <option value="volume_system">volume system</option>
+                               </options>
+                               <advanced>true</advanced>
+                       </parameter>
+                       <parameter name="deviceMaxVolume" type="integer" min="1" max="100">
+                               <label>Device Max Volume</label>
+                               <description>Assumed max volume for devices with android versions that do not expose this value (>=android 11).</description>
+                               <default>25</default>
+                               <advanced>true</advanced>
+                       </parameter>
                </config-description>
        </thing-type>