diff --git a/src/com/connectsdk/core/MediaInfo.java b/src/com/connectsdk/core/MediaInfo.java index b05c2cbf..d000f96b 100644 --- a/src/com/connectsdk/core/MediaInfo.java +++ b/src/com/connectsdk/core/MediaInfo.java @@ -39,6 +39,7 @@ public class MediaInfo { private String mimeType; private String description; private String title; + private Object customData; /** * list of imageInfo objects where [0] is icon, [1] is poster @@ -61,6 +62,7 @@ public static class Builder { private String description; private List allImages; private SubtitleInfo subtitleInfo; + private Object customData; // @endcond @@ -100,6 +102,11 @@ public Builder setSubtitleInfo(@NonNull SubtitleInfo subtitleInfo) { return this; } + public Builder setCustomData(@NonNull Object customData) { + this.customData = customData; + return this; + } + public MediaInfo build() { return new MediaInfo(this); } @@ -119,6 +126,7 @@ private MediaInfo(MediaInfo.Builder builder) { description = builder.description; subtitleInfo = builder.subtitleInfo; allImages = builder.allImages; + customData = builder.customData; } /** @@ -274,4 +282,14 @@ public void addImages(ImageInfo... images) { this.setImages(list); } + /** Gets the raw data associated to this MediaInfo. In most cases, this is a Map or JSONObject. */ + public Object getCustomData() { + return customData; + } + + /** Sets the raw data associated to this MediaInfo.. In most cases, this is a Map or JSONObject. */ + public void setCustomData(Object customData) { + this.customData = customData; + } + } diff --git a/src/com/connectsdk/device/ConnectableDevice.java b/src/com/connectsdk/device/ConnectableDevice.java index d63230e5..8c1bf2ef 100644 --- a/src/com/connectsdk/device/ConnectableDevice.java +++ b/src/com/connectsdk/device/ConnectableDevice.java @@ -129,6 +129,23 @@ public ConnectableDevice(JSONObject json) { setLastSeenOnWifi(json.optString(KEY_LAST_SEEN, null)); setLastConnected(json.optLong(KEY_LAST_CONNECTED, 0)); setLastDetection(json.optLong(KEY_LAST_DETECTED, 0)); + + //Deserialize the associated services as well + JSONObject jsonServices = json.optJSONObject(KEY_SERVICES); + if(jsonServices!=null) { + Iterator keys = jsonServices.keys(); + if (keys != null) { + while (keys.hasNext()) { + String key = (String) keys.next(); + JSONObject serviceObject = jsonServices.optJSONObject(key); + if (serviceObject!=null) { + DeviceService service = DeviceService.getService(serviceObject); + addService(service); + } + } + } + } + } public static ConnectableDevice createFromConfigString(String ipAddress, String friendlyName, String modelName, String modelNumber) { @@ -816,6 +833,9 @@ public void update(ServiceDescription description) { setModelName(description.getModelName()); setModelNumber(description.getModelNumber()); setLastConnected(description.getLastDetection()); + + if(description.getUUID()!=null && description.getUUID().length()>0) + setId(description.getUUID()); } public JSONObject toJSONObject() { diff --git a/src/com/connectsdk/discovery/DiscoveryManager.java b/src/com/connectsdk/discovery/DiscoveryManager.java index 21b26d98..ce1b5273 100644 --- a/src/com/connectsdk/discovery/DiscoveryManager.java +++ b/src/com/connectsdk/discovery/DiscoveryManager.java @@ -590,16 +590,16 @@ public void handleDeviceAdd(ConnectableDevice device) { compatibleDevices.put(device.getIpAddress(), device); - for (DiscoveryManagerListener listenter: discoveryListeners) { - listenter.onDeviceAdded(this, device); + for (DiscoveryManagerListener listener: discoveryListeners) { + listener.onDeviceAdded(this, device); } } public void handleDeviceUpdate(ConnectableDevice device) { if (deviceIsCompatible(device)) { if (device.getIpAddress() != null && compatibleDevices.containsKey(device.getIpAddress())) { - for (DiscoveryManagerListener listenter: discoveryListeners) { - listenter.onDeviceUpdated(this, device); + for (DiscoveryManagerListener listener: discoveryListeners) { + listener.onDeviceUpdated(this, device); } } else { @@ -613,8 +613,8 @@ public void handleDeviceUpdate(ConnectableDevice device) { } public void handleDeviceLoss(ConnectableDevice device) { - for (DiscoveryManagerListener listenter: discoveryListeners) { - listenter.onDeviceRemoved(this, device); + for (DiscoveryManagerListener listener: discoveryListeners) { + listener.onDeviceRemoved(this, device); } device.disconnect(); @@ -732,7 +732,6 @@ public void onServiceAdded(DiscoveryProvider provider, ServiceDescription servic if (device == null) { device = new ConnectableDevice(serviceDescription); - device.setIpAddress(serviceDescription.getIpAddress()); allDevices.put(serviceDescription.getIpAddress(), device); deviceIsNew = true; } @@ -850,6 +849,7 @@ public void addServiceDescriptionToDevice(ServiceDescription desc, ConnectableDe if (deviceService != null) { deviceService.setServiceDescription(desc); device.addService(deviceService); + device.setServiceDescription(desc); } } // @endcond diff --git a/src/com/connectsdk/service/AirPlayService.java b/src/com/connectsdk/service/AirPlayService.java index 46eb038e..ab82e995 100644 --- a/src/com/connectsdk/service/AirPlayService.java +++ b/src/com/connectsdk/service/AirPlayService.java @@ -494,6 +494,16 @@ public void playMedia(String url, String mimeType, String title, @Override public void playMedia(MediaInfo mediaInfo, boolean shouldLoop, LaunchListener listener) { + playMedia(mediaInfo, shouldLoop, 0, listener); + } + + @Override + public void playMedia(MediaInfo mediaInfo, boolean shouldLoop, long startPosition, LaunchListener listener) { + playMedia(mediaInfo, shouldLoop, startPosition, null, listener); + } + + @Override + public void playMedia(MediaInfo mediaInfo, boolean shouldLoop, long startPosition, Object customData, LaunchListener listener) { String mediaUrl = null; String mimeType = null; String title = null; diff --git a/src/com/connectsdk/service/DLNAService.java b/src/com/connectsdk/service/DLNAService.java index 5911571e..107a5c08 100644 --- a/src/com/connectsdk/service/DLNAService.java +++ b/src/com/connectsdk/service/DLNAService.java @@ -358,8 +358,17 @@ public void playMedia(String url, String mimeType, String title, String descript } @Override - public void playMedia(MediaInfo mediaInfo, boolean shouldLoop, - LaunchListener listener) { + public void playMedia(MediaInfo mediaInfo, boolean shouldLoop, LaunchListener listener) { + playMedia(mediaInfo, shouldLoop, 0, null, listener); + } + + @Override + public void playMedia(MediaInfo mediaInfo, boolean shouldLoop, long startPosition, LaunchListener listener) { + playMedia(mediaInfo, shouldLoop, startPosition, null, listener); + } + + @Override + public void playMedia(MediaInfo mediaInfo, boolean shouldLoop, long startPosition, Object customData, LaunchListener listener) { String mediaUrl = null; SubtitleInfo subtitle = null; String mimeType = null; diff --git a/src/com/connectsdk/service/NetcastTVService.java b/src/com/connectsdk/service/NetcastTVService.java index 90471146..52296229 100644 --- a/src/com/connectsdk/service/NetcastTVService.java +++ b/src/com/connectsdk/service/NetcastTVService.java @@ -1558,6 +1558,16 @@ public void playMedia(String url, String mimeType, String title, String descript @Override public void playMedia(MediaInfo mediaInfo, boolean shouldLoop, final MediaPlayer.LaunchListener listener) { + playMedia(mediaInfo, shouldLoop, 0, listener); + } + + @Override + public void playMedia(MediaInfo mediaInfo, boolean shouldLoop, long startPosition, LaunchListener listener) { + playMedia(mediaInfo, shouldLoop, startPosition, null, listener); + } + + @Override + public void playMedia(MediaInfo mediaInfo, boolean shouldLoop, long startPosition, Object customData, final LaunchListener listener) { if (getDLNAService() != null) { final MediaPlayer.LaunchListener launchListener = new LaunchListener() { diff --git a/src/com/connectsdk/service/RokuService.java b/src/com/connectsdk/service/RokuService.java index 8853a17a..213c72a7 100644 --- a/src/com/connectsdk/service/RokuService.java +++ b/src/com/connectsdk/service/RokuService.java @@ -735,8 +735,17 @@ public void playMedia(String url, String mimeType, String title, } @Override - public void playMedia(MediaInfo mediaInfo, boolean shouldLoop, - MediaPlayer.LaunchListener listener) { + public void playMedia(MediaInfo mediaInfo, boolean shouldLoop, MediaPlayer.LaunchListener listener) { + playMedia(mediaInfo, shouldLoop, 0, listener); + } + + @Override + public void playMedia(MediaInfo mediaInfo, boolean shouldLoop, long startPosition, LaunchListener listener) { + playMedia(mediaInfo, shouldLoop, startPosition, null, listener); + } + + @Override + public void playMedia(MediaInfo mediaInfo, boolean shouldLoop, long startPosition, Object customData, LaunchListener listener) { String mediaUrl = null; String mimeType = null; String title = null; diff --git a/src/com/connectsdk/service/WebOSTVService.java b/src/com/connectsdk/service/WebOSTVService.java index 2e5c9e0b..4ec01da7 100644 --- a/src/com/connectsdk/service/WebOSTVService.java +++ b/src/com/connectsdk/service/WebOSTVService.java @@ -304,6 +304,11 @@ private DeviceService getDLNAService() { return service; } + @Override + public String getWebAppId() { + return MEDIA_PLAYER_ID; + } + public static DiscoveryFilter discoveryFilter() { return new DiscoveryFilter(ID, "urn:lge-com:service:webos-second-screen:1"); } @@ -1293,8 +1298,17 @@ public void playMedia(String url, String mimeType, String title, String descript } @Override - public void playMedia(MediaInfo mediaInfo, boolean shouldLoop, - MediaPlayer.LaunchListener listener) { + public void playMedia(MediaInfo mediaInfo, boolean shouldLoop, MediaPlayer.LaunchListener listener) { + playMedia(mediaInfo, shouldLoop, 0, listener); + } + + @Override + public void playMedia(MediaInfo mediaInfo, boolean shouldLoop, long startPosition, LaunchListener listener) { + playMedia(mediaInfo, shouldLoop, startPosition, null, listener); + } + + @Override + public void playMedia(MediaInfo mediaInfo, boolean shouldLoop, long startPosition, Object customData, LaunchListener listener) { if ("4.0.0".equalsIgnoreCase(this.serviceDescription.getVersion())) { playMediaByNativeApp(mediaInfo, shouldLoop, listener); } else { diff --git a/src/com/connectsdk/service/capability/MediaPlayer.java b/src/com/connectsdk/service/capability/MediaPlayer.java index a45715c0..710e74b0 100644 --- a/src/com/connectsdk/service/capability/MediaPlayer.java +++ b/src/com/connectsdk/service/capability/MediaPlayer.java @@ -25,6 +25,8 @@ import com.connectsdk.service.command.ServiceSubscription; import com.connectsdk.service.sessions.LaunchSession; +import org.json.JSONObject; + public interface MediaPlayer extends CapabilityMethods { public final static String Any = "MediaPlayer.Any"; @@ -82,6 +84,10 @@ public interface MediaPlayer extends CapabilityMethods { public void playMedia(MediaInfo mediaInfo, boolean shouldLoop, LaunchListener listener); + public void playMedia(MediaInfo mediaInfo, boolean shouldLoop, long startPosition, LaunchListener listener); + + public void playMedia(MediaInfo mediaInfo, boolean shouldLoop, long startPosition, Object customData, LaunchListener listener); + public void closeMedia(LaunchSession launchSession, ResponseListener listener); /** diff --git a/src/com/connectsdk/service/capability/WebAppLauncher.java b/src/com/connectsdk/service/capability/WebAppLauncher.java index 81d94804..f5eac08b 100644 --- a/src/com/connectsdk/service/capability/WebAppLauncher.java +++ b/src/com/connectsdk/service/capability/WebAppLauncher.java @@ -59,6 +59,7 @@ public interface WebAppLauncher extends CapabilityMethods { }; public WebAppLauncher getWebAppLauncher(); + public String getWebAppId(); public CapabilityPriorityLevel getWebAppLauncherCapabilityLevel(); public void launchWebApp(String webAppId, LaunchListener listener); diff --git a/src/com/connectsdk/service/sessions/WebAppSession.java b/src/com/connectsdk/service/sessions/WebAppSession.java index ddd77b3f..5050c820 100644 --- a/src/com/connectsdk/service/sessions/WebAppSession.java +++ b/src/com/connectsdk/service/sessions/WebAppSession.java @@ -418,8 +418,17 @@ public void playMedia(String url, String mimeType, String title, String descript } @Override - public void playMedia(MediaInfo mediaInfo, boolean shouldLoop, - MediaPlayer.LaunchListener listener) { + public void playMedia(MediaInfo mediaInfo, boolean shouldLoop, MediaPlayer.LaunchListener listener) { + Util.postError(listener, ServiceCommandError.notSupported()); + } + + @Override + public void playMedia(MediaInfo mediaInfo, boolean shouldLoop, long startPosition, MediaPlayer.LaunchListener listener) { + Util.postError(listener, ServiceCommandError.notSupported()); + } + + @Override + public void playMedia(MediaInfo mediaInfo, boolean shouldLoop, long startPosition, Object customData, MediaPlayer.LaunchListener listener) { Util.postError(listener, ServiceCommandError.notSupported()); } diff --git a/test/src/com/connectsdk/core/MediaInfoTest.java b/test/src/com/connectsdk/core/MediaInfoTest.java index b2636651..562a8232 100644 --- a/test/src/com/connectsdk/core/MediaInfoTest.java +++ b/test/src/com/connectsdk/core/MediaInfoTest.java @@ -23,6 +23,8 @@ import junit.framework.Assert; +import org.json.JSONException; +import org.json.JSONObject; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricGradleTestRunner; @@ -54,6 +56,14 @@ public void testMediaInfoBuilderWithAllParameters() { String mimeType = "video/mp4"; String description = "description"; String iconUrl = "http://iconurl"; + JSONObject customData = new JSONObject(){{ + try { + put("data1", 1); + put("data2", 2); + } catch (JSONException e) { + e.printStackTrace(); + } + }}; SubtitleInfo subtitle = new SubtitleInfo.Builder("").build(); String title = "title"; @@ -63,6 +73,7 @@ public void testMediaInfoBuilderWithAllParameters() { .setIcon(iconUrl) .setSubtitleInfo(subtitle) .setTitle(title) + .setCustomData(customData) .build(); Assert.assertEquals(url, mediaInfo.getUrl()); @@ -72,6 +83,7 @@ public void testMediaInfoBuilderWithAllParameters() { Assert.assertEquals(1, mediaInfo.getImages().size()); Assert.assertEquals(subtitle, mediaInfo.getSubtitleInfo()); Assert.assertEquals(title, mediaInfo.getTitle()); + Assert.assertEquals(customData, mediaInfo.getCustomData()); } @Test diff --git a/test/src/com/connectsdk/device/ConnectableDeviceTest.java b/test/src/com/connectsdk/device/ConnectableDeviceTest.java index d809dee5..a798f8d1 100644 --- a/test/src/com/connectsdk/device/ConnectableDeviceTest.java +++ b/test/src/com/connectsdk/device/ConnectableDeviceTest.java @@ -1,7 +1,10 @@ package com.connectsdk.device; + import com.connectsdk.BuildConfig; import com.connectsdk.discovery.DiscoveryManager; +import com.connectsdk.discovery.DiscoveryManagerListener; +import com.connectsdk.discovery.provider.SSDPDiscoveryProvider; import com.connectsdk.service.AirPlayService; import com.connectsdk.service.DIALService; import com.connectsdk.service.DLNAService; @@ -16,6 +19,7 @@ import junit.framework.Assert; +import org.json.JSONObject; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -28,6 +32,9 @@ import java.util.ArrayList; import java.util.List; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + @RunWith(RobolectricGradleTestRunner.class) @Config(constants = BuildConfig.class, sdk = 21) public class ConnectableDeviceTest { @@ -136,6 +143,64 @@ public void testNonePairingType() throws IOException { Assert.assertEquals(DeviceService.PairingType.PIN_CODE, device.getServiceByName(AirPlayService.ID).getPairingType()); } + @Test + public void testDeviceIdWhenServiceHasUUID(){ + String uuid = "myServiceUUID"; + String ip = "192.168.0.1"; + String name = "Test Name"; + String serviceId = DIALService.ID; + ServiceDescription serviceDescription = new ServiceDescription("_testservicetype._tcp.local.", uuid, ip); + serviceDescription.setServiceID(serviceId); + serviceDescription.setFriendlyName(name); + SSDPDiscoveryProvider provider = mock(SSDPDiscoveryProvider.class); + DiscoveryManager.getInstance().registerDeviceService(DIALService.class, SSDPDiscoveryProvider.class); + DiscoveryManager.getInstance().onServiceAdded(provider, serviceDescription); + + ConnectableDevice device = DiscoveryManager.getInstance().getAllDevices().get(serviceDescription.getIpAddress()); + Assert.assertNotNull(device); + Assert.assertEquals(device.getId(), uuid); + } + + @Test + public void testServiceDescriptionIsSetAfterFirstDiscovery(){ + String uuid = "myServiceUUID"; + String ip = "192.168.0.1"; + String name = "Test Name"; + String serviceId = DIALService.ID; + ServiceDescription serviceDescription = new ServiceDescription("_testservicetype._tcp.local.", uuid, ip); + serviceDescription.setServiceID(serviceId); + serviceDescription.setFriendlyName(name); + DiscoveryManager manager = DiscoveryManager.getInstance(); + SSDPDiscoveryProvider provider = mock(SSDPDiscoveryProvider.class); + DiscoveryManagerListener listener = mock(DiscoveryManagerListener.class); + manager.addListener(listener); + manager.registerDeviceService(DIALService.class, SSDPDiscoveryProvider.class); + + //When + manager.onServiceAdded(provider, serviceDescription); + + //Then + ConnectableDevice device = DiscoveryManager.getInstance().getAllDevices().get(serviceDescription.getIpAddress()); + verify(listener).onDeviceAdded(manager, device); + Assert.assertNotNull(device.getServiceDescription()); + } + + @Test + public void testServicesSerialization() throws IOException { + // given + ServiceDescription serviceDesc = createServiceDescription(WebOSTVService.ID, WebOSTVService.ID); + device.services.put(WebOSTVService.ID, new WebOSTVService(serviceDesc, new ServiceConfig(serviceDesc))); + serviceDesc = createServiceDescription(NetcastTVService.ID, NetcastTVService.ID); + device.services.put(NetcastTVService.ID, new NetcastTVService(serviceDesc, new ServiceConfig(serviceDesc))); + + // when + JSONObject json = device.toJSONObject(); + ConnectableDevice newDevice = new ConnectableDevice(json); + + // then + Assert.assertEquals(device.services.size(), newDevice.services.size()); + } + private void addAllCoreServicesToDevice() throws IOException { DeviceService webOSService = new WebOSTVService(createServiceDescription(WebOSTVService.ID), Mockito.mock(ServiceConfig.class)); DeviceService netCastService = new NetcastTVService(createServiceDescription(NetcastTVService.ID), Mockito.mock(ServiceConfig.class)); @@ -152,15 +217,18 @@ private void addAllCoreServicesToDevice() throws IOException { } private ServiceDescription createServiceDescription(String serviceId) { + return createServiceDescription(serviceId, ""); + } + + private ServiceDescription createServiceDescription(String serviceId, String UUID) { ServiceDescription description = new ServiceDescription(); description.setFriendlyName(""); description.setManufacturer(""); - description.setUUID(""); + description.setUUID(UUID); description.setModelDescription(""); description.setModelName(""); description.setModelNumber(""); description.setServiceID(serviceId); return description; } - } diff --git a/test/src/com/connectsdk/discovery/provider/ssdp/SSDPDeviceTest.java b/test/src/com/connectsdk/discovery/provider/ssdp/SSDPDeviceTest.java index 86677a2f..63f3e510 100644 --- a/test/src/com/connectsdk/discovery/provider/ssdp/SSDPDeviceTest.java +++ b/test/src/com/connectsdk/discovery/provider/ssdp/SSDPDeviceTest.java @@ -9,6 +9,7 @@ import org.xml.sax.SAXParseException; import java.io.IOException; +import java.net.ConnectException; import java.net.MalformedURLException; import java.net.UnknownHostException; @@ -84,7 +85,7 @@ public void testCreateDeviceWithWrongUrl() { try { new SSDPDevice("http://unknown.host", null); Assert.fail("MalformedURLException should be thrown"); - } catch (UnknownHostException e) { + } catch (UnknownHostException | ConnectException e) { // OK } catch (Exception e) { Assert.fail("MalformedURLException should be thrown"); diff --git a/test/src/com/connectsdk/service/DLNAServiceSendCommandTest.java b/test/src/com/connectsdk/service/DLNAServiceSendCommandTest.java index dfefb7d4..ce09503c 100644 --- a/test/src/com/connectsdk/service/DLNAServiceSendCommandTest.java +++ b/test/src/com/connectsdk/service/DLNAServiceSendCommandTest.java @@ -22,6 +22,7 @@ import com.connectsdk.BuildConfig; import com.connectsdk.core.TestUtil; +import com.connectsdk.discovery.DiscoveryManager; import com.connectsdk.etc.helper.HttpConnection; import com.connectsdk.service.capability.listeners.ResponseListener; import com.connectsdk.service.command.ServiceCommand; @@ -36,6 +37,7 @@ import org.junit.runner.RunWith; import org.mockito.Mockito; import org.robolectric.RobolectricGradleTestRunner; +import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; import org.robolectric.shadows.ShadowLooper; @@ -69,6 +71,7 @@ HttpConnection createHttpConnection(String target) throws IOException { @Before public void setUp() { + DiscoveryManager.init(RuntimeEnvironment.application); httpConnection = Mockito.mock(HttpConnection.class); service = new StubDLNAService(Mockito.mock(ServiceDescription.class), Mockito.mock(ServiceConfig.class));