From 11fa2e44db25644806fab13024da37edac91b127 Mon Sep 17 00:00:00 2001 From: Seokhee Lee Date: Mon, 7 Sep 2020 20:25:43 +0900 Subject: [PATCH] Add serviceIntegrationEnabled in DiscoveryManager serviceIntegrationEnabled variable is added in DiscoveryManager. If it is true, services in a device are managed by one device instance (default in the previous version). Otherwise, all services look like in different devices (default in the current version). The previous version showed all services in a device as a device item in the DevicePickerList and automatically selected a service for a capability requested by user. It could give simple device list and usage scenario for a device with multiple second screen services. However to support it more stably, more careful design is needed under various cases: - A service is not connected successfully. - A service with high CapabilityPriorityLevel does not work. --- .../connectsdk/device/ConnectableDevice.java | 32 +++++++++-- .../device/DevicePickerListView.java | 11 ++-- .../discovery/DiscoveryManager.java | 46 +++++++++++---- .../connectsdk/service/WebOSTVService.java | 5 +- .../airplay/AirPlayServiceSocketClient.java | 56 ++++++++++--------- 5 files changed, 104 insertions(+), 46 deletions(-) diff --git a/src/com/connectsdk/device/ConnectableDevice.java b/src/com/connectsdk/device/ConnectableDevice.java index d63230e5..d5696886 100644 --- a/src/com/connectsdk/device/ConnectableDevice.java +++ b/src/com/connectsdk/device/ConnectableDevice.java @@ -97,6 +97,10 @@ public class ConnectableDevice implements DeviceServiceListener { Map services; + private String serviceId; + + public boolean isConnecting = false; + public boolean featuresReady = false; public ConnectableDevice() { @@ -323,11 +327,18 @@ public List getListeners() { * It is always necessary to call connect on a ConnectableDevice, even if it contains no connectable DeviceServices. */ public void connect() { - for (DeviceService service : services.values()) { - if (!service.isConnected()) { - service.connect(); + new Thread(new Runnable() { + @Override + public void run() { + isConnecting = true; + for (DeviceService service : services.values()) { + if (!service.isConnected()) { + service.connect(); + } + } + isConnecting = false; } - } + }).start(); } /** @@ -365,7 +376,10 @@ public boolean isConnected() { } } - return connectedCount >= services.size(); + // In case of Service Integration, a device is assumed as connected, + // if a service in the device is connected. + return connectedCount >= 1; + //return connectedCount >= services.size(); } // @endcond @@ -927,4 +941,12 @@ private int getConnectedServiceCount() { } // @endcond + + public void setServiceId(String srvId) { + serviceId = srvId; + } + + public String getServiceId() { + return serviceId; + } } diff --git a/src/com/connectsdk/device/DevicePickerListView.java b/src/com/connectsdk/device/DevicePickerListView.java index 76b27eb0..095529e5 100644 --- a/src/com/connectsdk/device/DevicePickerListView.java +++ b/src/com/connectsdk/device/DevicePickerListView.java @@ -52,7 +52,7 @@ public void run() { } @Override - public void onDeviceAdded(DiscoveryManager manager, final ConnectableDevice device) { + public void onDeviceAdded(final DiscoveryManager manager, final ConnectableDevice device) { Util.runOnUI(new Runnable () { @Override public void run() { @@ -73,9 +73,12 @@ public void run() { if (d.getIpAddress().equals(device.getIpAddress())) { if (d.getFriendlyName().equals(device.getFriendlyName())) { - pickerAdapter.remove(d); - pickerAdapter.insert(device, i); - return; + if (!manager.isServiceIntegrationEnabled() && + d.getServiceId().equals(device.getServiceId())) { + pickerAdapter.remove(d); + pickerAdapter.insert(device, i); + return; + } } } diff --git a/src/com/connectsdk/discovery/DiscoveryManager.java b/src/com/connectsdk/discovery/DiscoveryManager.java index 3f924d47..853ad466 100644 --- a/src/com/connectsdk/discovery/DiscoveryManager.java +++ b/src/com/connectsdk/discovery/DiscoveryManager.java @@ -143,6 +143,36 @@ public enum PairingLevel { // @endcond + /** + * If serviceIntegrationEnabled is false (default), all services look like in different devices. + * If serviceIntegrationEnabled is true, services in a device are managed by one device instance. + */ + private boolean serviceIntegrationEnabled = false; + + public void setServiceIntegration(boolean value) { + serviceIntegrationEnabled = value; + } + + public boolean isServiceIntegrationEnabled() { + return serviceIntegrationEnabled; + } + + /** + * Use device name and IP for identification of device, + * because some devices have multiple device instances with same IP. + * (i.e., a device including docker containers with host network setting.) + * And if service integration is false (default), all services look like different devices. + */ + private String getDeviceKey(ConnectableDevice device) { + if (isServiceIntegrationEnabled()) return device.getFriendlyName() + device.getIpAddress(); + return device.getFriendlyName() + device.getIpAddress() + device.getServiceId(); + } + + private String getDeviceKey(ServiceDescription srvDesc) { + if (isServiceIntegrationEnabled()) return srvDesc.getFriendlyName() + srvDesc.getIpAddress(); + return srvDesc.getFriendlyName() + srvDesc.getIpAddress() + srvDesc.getServiceID(); + } + /** * Initilizes the Discovery manager with a valid context. This should be done as soon as possible and it should use getApplicationContext() as the Discovery manager could persist longer than the current Activity. * @@ -321,8 +351,7 @@ public void setCapabilityFilters(List capabilityFilters) { for (ConnectableDevice device: allDevices.values()) { if (deviceIsCompatible(device)) { - String devKey = device.getFriendlyName() + device.getIpAddress(); - compatibleDevices.put(devKey, device); + compatibleDevices.put(getDeviceKey(device), device); handleDeviceAdd(device); } @@ -595,8 +624,7 @@ public void handleDeviceAdd(ConnectableDevice device) { if (!deviceIsCompatible(device)) return; - String devKey = device.getFriendlyName() + device.getIpAddress(); - compatibleDevices.put(devKey, device); + compatibleDevices.put(getDeviceKey(device), device); for (DiscoveryManagerListener listenter: discoveryListeners) { listenter.onDeviceAdded(this, device); @@ -604,7 +632,7 @@ public void handleDeviceAdd(ConnectableDevice device) { } public void handleDeviceUpdate(ConnectableDevice device) { - String devKey = device.getFriendlyName() + device.getIpAddress(); + String devKey = getDeviceKey(device); if (deviceIsCompatible(device)) { if (device.getIpAddress() != null && compatibleDevices.containsKey(devKey)) { @@ -724,10 +752,7 @@ public void onCapabilityUpdated(ConnectableDevice device, List added, Li public void onServiceAdded(DiscoveryProvider provider, ServiceDescription serviceDescription) { Log.d(Util.T, "Service added: " + serviceDescription.getFriendlyName() + " (" + serviceDescription.getServiceID() + ")"); - // Use device name and IP for identification of device, - // because some devices have multiple device instances with same IP. - // (i.e., a device including docker containers with host network setting.) - String devKey = serviceDescription.getFriendlyName() + serviceDescription.getIpAddress(); + String devKey = getDeviceKey(serviceDescription); boolean deviceIsNew = !allDevices.containsKey(devKey); ConnectableDevice device = null; @@ -754,6 +779,7 @@ public void onServiceAdded(DiscoveryProvider provider, ServiceDescription servic device.setFriendlyName(serviceDescription.getFriendlyName()); device.setLastDetection(Util.getTime()); device.setLastKnownIPAddress(serviceDescription.getIpAddress()); + device.setServiceId(serviceDescription.getServiceID()); // TODO: Implement the currentSSID Property in DiscoveryManager // device.setLastSeenOnWifi(currentSSID); @@ -783,7 +809,7 @@ public void onServiceRemoved(DiscoveryProvider provider, ServiceDescription serv Log.d(Util.T, "onServiceRemoved: friendlyName: " + serviceDescription.getFriendlyName()); - String devKey = serviceDescription.getFriendlyName() + serviceDescription.getIpAddress(); + String devKey = getDeviceKey(serviceDescription); ConnectableDevice device = allDevices.get(devKey); if (device != null) { diff --git a/src/com/connectsdk/service/WebOSTVService.java b/src/com/connectsdk/service/WebOSTVService.java index 20b1c79c..a603ed58 100644 --- a/src/com/connectsdk/service/WebOSTVService.java +++ b/src/com/connectsdk/service/WebOSTVService.java @@ -224,10 +224,11 @@ public static DiscoveryFilter discoveryFilter() { @Override public boolean isConnected() { + if (this.socket == null) return false; if (DiscoveryManager.getInstance().getPairingLevel().compareTo(PairingLevel.PROTECTED) >= 0) { - return this.socket != null && this.socket.isConnected() && this.socket.getClientKey() != null; + return this.socket.isConnected() && this.socket.getClientKey() != ""; } else { - return this.socket != null && this.socket.isConnected(); + return this.socket.isConnected(); } } diff --git a/src/com/connectsdk/service/airplay/AirPlayServiceSocketClient.java b/src/com/connectsdk/service/airplay/AirPlayServiceSocketClient.java index 58839ed2..2381e100 100644 --- a/src/com/connectsdk/service/airplay/AirPlayServiceSocketClient.java +++ b/src/com/connectsdk/service/airplay/AirPlayServiceSocketClient.java @@ -74,17 +74,13 @@ public void pair(final String pin) { public void run() { try { airPlayAuth.doPairing(pin); - } catch (Exception ex) { - ex.printStackTrace(); - } - - try { socket = airPlayAuth.authenticate(); state = State.REGISTERED; if (mListener != null) { mListener.onConnect(); } } catch (Exception ex) { + state = State.INITIAL; ex.printStackTrace(); mListener.onRegistrationFailed(new ServiceCommandError(ex.toString())); } @@ -102,27 +98,37 @@ public void connect() { state = State.CONNECTING; } - new Thread(new Runnable() { - @Override - public void run() { - try { - socket = airPlayAuth.authenticate(); - state = State.REGISTERED; - if (mListener != null) { - mListener.onConnect(); - } - } catch (Exception e) { - try { - airPlayAuth.startPairing(); - if (mListener != null) - mListener.onBeforeRegister(mPairingType); - } catch (Exception ex) { - ex.printStackTrace(); - mListener.onRegistrationFailed(new ServiceCommandError(ex.toString())); - } + try { + socket = airPlayAuth.authenticate(); + state = State.REGISTERED; + if (mListener != null) { + mListener.onConnect(); + } + } catch (Exception e) { + try { + airPlayAuth.startPairing(); + if (mListener != null) + mListener.onBeforeRegister(mPairingType); + } catch (Exception ex) { + ex.printStackTrace(); + mListener.onRegistrationFailed(new ServiceCommandError(ex.toString())); + } + } + + int count = 0; + while(state == State.CONNECTING){ + try { + count++; + Thread.sleep(100); + if (count > 200) { + mListener.onRegistrationFailed(new ServiceCommandError("Pairing Timeout")); + break; } + } catch (InterruptedException e) { + e.printStackTrace(); + mListener.onRegistrationFailed(new ServiceCommandError(e.toString())); } - }).start(); + } } public void disconnect() { @@ -131,7 +137,7 @@ public void disconnect() { airPlayAuth = null; state = State.INITIAL; try { - socket.close(); + if (socket != null) socket.close(); } catch (IOException e) { e.printStackTrace(); }