Java tutorial
/* * JSCommandDispatcher.java * Connect SDK * * Copyright (c) 2014 LG Electronics. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.connectsdk.cordova; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.HashMap; import java.util.List; import org.json.JSONException; import org.json.JSONObject; import android.util.Log; import com.connectsdk.core.AppInfo; import com.connectsdk.core.ChannelInfo; import com.connectsdk.core.ExternalInputInfo; import com.connectsdk.core.TextInputStatusInfo; import com.connectsdk.device.ConnectableDevice; import com.connectsdk.service.DeviceService; import com.connectsdk.service.WebOSTVService; import com.connectsdk.service.capability.ExternalInputControl.ExternalInputListListener; import com.connectsdk.service.capability.MediaControl; import com.connectsdk.service.capability.MediaControl.DurationListener; import com.connectsdk.service.capability.MediaControl.PositionListener; import com.connectsdk.service.capability.TextInputControl; import com.connectsdk.service.capability.WebAppLauncher; import com.connectsdk.service.command.ServiceCommandError; import com.connectsdk.service.command.ServiceSubscription; import com.connectsdk.service.sessions.LaunchSession; import com.connectsdk.service.sessions.WebAppSession; import com.connectsdk.service.sessions.WebAppSessionListener; public class JSCommandDispatcher { ConnectSDKCordova plugin; ConnectableDeviceWrapper deviceWrapper; ConnectableDevice device; HashMap<String, Method> methodCache = new HashMap<String, Method>(); // Annotation used to mark handlers @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) @interface CommandMethod { } class DispatcherException extends RuntimeException { private static final long serialVersionUID = 1L; public DispatcherException(String message) { super(message); } } JSCommandDispatcher(ConnectableDeviceWrapper deviceWrapper) { this.deviceWrapper = deviceWrapper; this.device = deviceWrapper.device; this.plugin = deviceWrapper.plugin; } Method getMethod(String interfaceName, String methodName) { String name = interfaceName + "_" + methodName; Method method = methodCache.get(name); if (method == null) { try { method = this.getClass().getMethod(name, JSCommand.class, JSONObject.class); if (method.isAnnotationPresent(CommandMethod.class)) { methodCache.put(name, method); } else { Log.d("ConnectSDKCordova", "attempted to access method " + method.getName() + " but method is not a command handler"); method = null; } } catch (NoSuchMethodException e) { } } return method; } public void dispatchCommand(String interfaceName, String methodName, JSCommand command, JSONObject args, boolean subscribe) { Method method = getMethod(interfaceName, methodName); if (method != null) { try { Object returnValue = method.invoke(this, command, args); if (returnValue != null && returnValue instanceof ServiceSubscription) { command.serviceSubscription = (ServiceSubscription<?>) returnValue; } } catch (InvocationTargetException e) { Throwable cause = e.getCause(); Exception wrappedException = new DispatcherException( "Exception calling " + methodName + ": " + cause.toString()); wrappedException.initCause(cause); wrappedException.printStackTrace(); command.error(wrappedException); } catch (Exception e) { e.printStackTrace(); command.error(e); } } else { Log.d("ConnectSDKCordova", "Method not implemented: " + interfaceName + "." + methodName); command.error("method not implemented"); } } /* ExternalInputControl methods */ @CommandMethod public void externalInputControl_getExternalInputList(final JSCommand command, JSONObject args) throws JSONException { device.getExternalInputControl().getExternalInputList(new ExternalInputListListener() { @Override public void onSuccess(List<ExternalInputInfo> list) { command.success(list); } @Override public void onError(ServiceCommandError error) { command.error(error); } }); } @CommandMethod public void externalInputControl_setExternalInput(JSCommand command, JSONObject args) throws JSONException { JSONObject externalInputInfoObj = args.getJSONObject("externalInputInfo"); String inputId = externalInputInfoObj.getString("id"); // FIXME ExternalInputInfo info = new ExternalInputInfo(); info.setId(inputId); device.getExternalInputControl().setExternalInput(info, command.getResponseListener()); } /* FivewayControl methods */ @CommandMethod public void keyControl_up(JSCommand command, JSONObject args) throws JSONException { device.getKeyControl().up(command.getResponseListener()); } @CommandMethod public void keyControl_down(JSCommand command, JSONObject args) throws JSONException { device.getKeyControl().down(command.getResponseListener()); } @CommandMethod public void keyControl_left(JSCommand command, JSONObject args) throws JSONException { device.getKeyControl().left(command.getResponseListener()); } @CommandMethod public void keyControl_right(JSCommand command, JSONObject args) throws JSONException { device.getKeyControl().right(command.getResponseListener()); } @CommandMethod public void keyControl_ok(JSCommand command, JSONObject args) throws JSONException { device.getKeyControl().ok(command.getResponseListener()); } @CommandMethod public void keyControl_back(JSCommand command, JSONObject args) throws JSONException { device.getKeyControl().back(command.getResponseListener()); } @CommandMethod public void keyControl_home(JSCommand command, JSONObject args) throws JSONException { device.getKeyControl().home(command.getResponseListener()); } /* TextInputControl methods */ @CommandMethod public void textInputControl_sendText(JSCommand command, JSONObject args) throws JSONException { String text = args.getString("input"); device.getTextInputControl().sendText(text); // FIXME keyboardControl needs a ResponseListener command.success(); } @CommandMethod public void textInputControl_sendEnter(JSCommand command, JSONObject args) throws JSONException { device.getTextInputControl().sendEnter(); // FIXME keyboardControl needs a ResponseListener command.success(); } @CommandMethod public void textInputControl_sendDelete(JSCommand command, JSONObject args) throws JSONException { device.getTextInputControl().sendDelete(); // FIXME keyboardControl needs a ResponseListener command.success(); } @CommandMethod public ServiceSubscription<?> textInputControl_subscribeTextInputStatus(final JSCommand command, JSONObject args) throws JSONException { return device.getTextInputControl() .subscribeTextInputStatus(new TextInputControl.TextInputStatusListener() { @Override public void onError(ServiceCommandError error) { command.error(error); } @Override public void onSuccess(TextInputStatusInfo status) { JSONObject response = new JSONObject(); try { response.put("isVisible", status.isFocused()); response.put("rawData", status.getRawData()); } catch (JSONException e) { e.printStackTrace(); } command.success(response); } }); } /* Launcher methods */ @CommandMethod public void launcher_launchApp(JSCommand command, JSONObject args) throws JSONException { String appId = args.getString("appId"); JSONObject params = args.optJSONObject("params"); AppInfo appInfo = new AppInfo(); appInfo.setId(appId); device.getLauncher().launchAppWithInfo(appInfo, params, command.getAppLaunchListener()); } @CommandMethod public void launcher_launchBrowser(JSCommand command, JSONObject args) throws JSONException { String url = args.optString("url", null); device.getLauncher().launchBrowser(url, command.getAppLaunchListener()); } @CommandMethod public void launcher_launchHulu(JSCommand command, JSONObject args) throws JSONException { String contentId = args.getString("contentId"); device.getLauncher().launchHulu(contentId, command.getAppLaunchListener()); } @CommandMethod public void launcher_launchNetflix(JSCommand command, JSONObject args) throws JSONException { String contentId = args.getString("contentId"); device.getLauncher().launchNetflix(contentId, command.getAppLaunchListener()); } @CommandMethod public void launcher_launchYouTube(JSCommand command, JSONObject args) throws JSONException { String contentId = args.getString("contentId"); device.getLauncher().launchYouTube(contentId, command.getAppLaunchListener()); } @CommandMethod public void launcher_getAppList(JSCommand command, JSONObject args) throws JSONException { device.getLauncher().getAppList(command.getAppListListener()); } /* MediaControl methods */ @CommandMethod public void mediaControl_play(JSCommand command, JSONObject args) throws JSONException { MediaControl mediaControl = getMediaControl(command, args); mediaControl.play(command.getResponseListener()); } @CommandMethod public void mediaControl_pause(JSCommand command, JSONObject args) throws JSONException { MediaControl mediaControl = getMediaControl(command, args); mediaControl.pause(command.getResponseListener()); } @CommandMethod public void mediaControl_stop(JSCommand command, JSONObject args) throws JSONException { MediaControl mediaControl = getMediaControl(command, args); mediaControl.stop(command.getResponseListener()); } @CommandMethod public void mediaControl_fastForward(JSCommand command, JSONObject args) throws JSONException { MediaControl mediaControl = getMediaControl(command, args); mediaControl.fastForward(command.getResponseListener()); } @CommandMethod public void mediaControl_rewind(JSCommand command, JSONObject args) throws JSONException { MediaControl mediaControl = getMediaControl(command, args); mediaControl.rewind(command.getResponseListener()); } @CommandMethod public void mediaControl_seek(JSCommand command, JSONObject args) throws JSONException { MediaControl mediaControl = getMediaControl(command, args); double positionSeconds = args.getDouble("position"); long positionMillis = (long) (1000L * positionSeconds); mediaControl.seek(positionMillis, command.getResponseListener()); } @CommandMethod public void mediaControl_getDuration(final JSCommand command, JSONObject args) throws JSONException { MediaControl mediaControl = getMediaControl(command, args); mediaControl.getDuration(new DurationListener() { @Override public void onSuccess(Long durationMillis) { command.success((double) durationMillis / 1000.0); } @Override public void onError(ServiceCommandError error) { command.error(error); } }); } @CommandMethod public void mediaControl_getPosition(final JSCommand command, JSONObject args) throws JSONException { MediaControl mediaControl = getMediaControl(command, args); mediaControl.getPosition(new PositionListener() { @Override public void onSuccess(Long positionMillis) { command.success((double) positionMillis / 1000.0); } @Override public void onError(ServiceCommandError error) { command.error(error); } }); } @CommandMethod public void mediaControl_subscribePlayState(final JSCommand command, JSONObject args) throws JSONException { MediaControl mediaControl = getMediaControl(command, args); mediaControl.subscribePlayState(command.getPlayStateListener()); } /* MediaPlayer methods */ @CommandMethod public void mediaPlayer_displayImage(JSCommand command, JSONObject args) throws JSONException { displayMedia(command, args, "image"); } @CommandMethod public void mediaPlayer_playMedia(JSCommand command, JSONObject args) throws JSONException { displayMedia(command, args, "video"); } /* MouseControl methods */ @CommandMethod public void mouseControl_connectMouse(JSCommand command, JSONObject args) throws JSONException { device.getMouseControl().connectMouse(); // FIXME check if this actually worked command.success(); } @CommandMethod public void mouseControl_move(JSCommand command, JSONObject args) throws JSONException { double dx = args.getDouble("dx"); double dy = args.getDouble("dy"); device.getMouseControl().move(dx, dy); // FIXME check if this actually worked command.success(); } @CommandMethod public void mouseControl_scroll(JSCommand command, JSONObject args) throws JSONException { double dx = args.getDouble("dx"); double dy = args.getDouble("dy"); device.getMouseControl().scroll(dx, dy); // FIXME check if this actually worked command.success(); } @CommandMethod public void mouseControl_click(JSCommand command, JSONObject args) throws JSONException { device.getMouseControl().click(); // FIXME check if this actually worked command.success(); } /* PowerControl methods */ @CommandMethod public void powerControl_powerOff(JSCommand command, JSONObject args) throws JSONException { device.getPowerControl().powerOff(command.getResponseListener()); } /* ToastControl methods */ @CommandMethod public void toastControl_showToast(JSCommand command, JSONObject args) throws JSONException { showToast(command, args, false); } @CommandMethod public void toastControl_showClickableToast(JSCommand command, JSONObject args) throws JSONException { showToast(command, args, true); } /* TVControl methods */ @CommandMethod public void TVControl_channelUp(JSCommand command, JSONObject args) throws JSONException { device.getTVControl().channelUp(command.getResponseListener()); } @CommandMethod public void TVControl_channelDown(JSCommand command, JSONObject args) throws JSONException { device.getTVControl().channelDown(command.getResponseListener()); } @CommandMethod public void TVControl_setChannel(JSCommand command, JSONObject args) throws JSONException { JSONObject channelInfoObj = args.getJSONObject("channelInfo"); String channelId = channelInfoObj.optString("id"); String channelNumber = channelInfoObj.optString("number"); ChannelInfo channelInfo = new ChannelInfo(); if (channelId != null && channelId.length() > 0) { channelInfo.setId(channelId); } else { channelInfo.setNumber(channelNumber); } device.getTVControl().setChannel(channelInfo, command.getResponseListener()); } @CommandMethod public void TVControl_getChannelList(JSCommand command, JSONObject args) throws JSONException { device.getTVControl().getChannelList(command.getChannelListListener()); } @CommandMethod public void TVControl_getCurrentChannel(JSCommand command, JSONObject args) throws JSONException { device.getTVControl().getCurrentChannel(command.getChannelListener()); } @CommandMethod public void TVControl_subscribeCurrentChannel(JSCommand command, JSONObject args) throws JSONException { device.getTVControl().subscribeCurrentChannel(command.getChannelListener()); } /* VolumeControl methods */ @CommandMethod public void volumeControl_getVolume(JSCommand command, JSONObject args) throws JSONException { device.getVolumeControl().getVolume(command.getVolumeListener()); } @CommandMethod public void volumeControl_setVolume(JSCommand command, JSONObject args) throws JSONException { float volume = (float) args.getDouble("volume"); device.getVolumeControl().setVolume(volume, command.getResponseListener()); } @CommandMethod public void volumeControl_volumeUp(JSCommand command, JSONObject args) throws JSONException { device.getVolumeControl().volumeUp(command.getResponseListener()); } @CommandMethod public void volumeControl_volumeDown(JSCommand command, JSONObject args) throws JSONException { device.getVolumeControl().volumeDown(command.getResponseListener()); } @CommandMethod public void volumeControl_getMute(JSCommand command, JSONObject args) throws JSONException { device.getVolumeControl().getMute(command.getMuteListener()); } @CommandMethod public void volumeControl_setMute(JSCommand command, JSONObject args) throws JSONException { boolean mute = args.getBoolean("mute"); device.getVolumeControl().setMute(mute, command.getResponseListener()); } @CommandMethod public ServiceSubscription<?> volumeControl_subscribeVolume(JSCommand command, JSONObject args) throws JSONException { return device.getVolumeControl().subscribeVolume(command.getVolumeListener()); } @CommandMethod public ServiceSubscription<?> volumeControl_subscribeMute(JSCommand command, JSONObject args) throws JSONException { return device.getVolumeControl().subscribeMute(command.getMuteListener()); } /* WebAppLauncher methods */ @CommandMethod public void webAppLauncher_launchWebApp(JSCommand command, JSONObject args) throws JSONException { String webAppId = args.getString("webAppId"); JSONObject params = args.optJSONObject("params"); if (params != null && device.hasCapability(WebAppLauncher.Launch_Params)) device.getWebAppLauncher().launchWebApp(webAppId, params, command.getWebAppLaunchListener()); else device.getWebAppLauncher().launchWebApp(webAppId, command.getWebAppLaunchListener()); } @CommandMethod public void webAppLauncher_joinWebApp(JSCommand command, JSONObject args) throws JSONException { String webAppId = args.getString("webAppId"); device.getWebAppLauncher().joinWebApp(webAppId, command.getWebAppLaunchListener()); } /* WebAppSession methods */ WebAppSessionWrapper getWebAppSessionWrapper(String objectId) { WebAppSessionWrapper wrapper = (WebAppSessionWrapper) plugin.getObjectWrapper(objectId); if (wrapper == null) { throw new DispatcherException( "WebAppSession no longer exists. Make sure to acquire() it during the success callback."); } return wrapper; } @CommandMethod public void webAppSession_connect(JSCommand command, JSONObject args) throws JSONException { String objectId = args.getString("objectId"); final WebAppSessionWrapper wrapper = getWebAppSessionWrapper(objectId); wrapper.session.setWebAppSessionListener(new WebAppSessionListener() { @Override public void onReceiveMessage(WebAppSession webAppSession, Object message) { wrapper.sendEvent("message", message); } @Override public void onWebAppSessionDisconnect(WebAppSession webAppSession) { wrapper.sendEvent("disconnect"); } }); wrapper.session.connect(command.getResponseListener()); } @CommandMethod public void webAppSession_disconnect(JSCommand command, JSONObject args) throws JSONException { String objectId = args.getString("objectId"); final WebAppSessionWrapper wrapper = getWebAppSessionWrapper(objectId); wrapper.session.disconnectFromWebApp(); command.success(); } @CommandMethod public void webAppSession_sendText(JSCommand command, JSONObject args) throws JSONException { String text = args.getString("text"); String objectId = args.getString("objectId"); final WebAppSessionWrapper wrapper = getWebAppSessionWrapper(objectId); wrapper.session.sendMessage(text, command.getResponseListener()); } @CommandMethod public void webAppSession_sendJSON(JSCommand command, JSONObject args) throws JSONException { JSONObject json = args.getJSONObject("jsonObject"); String objectId = args.getString("objectId"); final WebAppSessionWrapper wrapper = getWebAppSessionWrapper(objectId); wrapper.session.sendMessage(json, command.getResponseListener()); } /* Service-specific methods */ @CommandMethod public void webOSTVService_connectToApp(JSCommand command, JSONObject args) throws JSONException { WebOSTVService service = (WebOSTVService) device.getServiceByName(WebOSTVService.ID); String appId = args.getString("appId"); if (service != null) { service.connectToApp(appId, command.getWebAppLaunchListener()); } else { command.error("WebOSTVService not available for this device"); } } @CommandMethod public void webOSTVService_joinApp(JSCommand command, JSONObject args) throws JSONException { WebOSTVService service = (WebOSTVService) device.getServiceByName(WebOSTVService.ID); String appId = args.getString("appId"); if (service != null) { service.joinApp(appId, command.getWebAppLaunchListener()); } else { command.error("WebOSTVService not available for this device"); } } /* Special methods */ @CommandMethod public void CORDOVAPLUGIN_closeLaunchSession(JSCommand command, JSONObject args) throws JSONException { JSONObject obj = args.getJSONObject("launchSession"); LaunchSession session = getLaunchSession(obj); if (session != null) { session.close(command.getResponseListener()); } else { command.error("unknown launch session type; could not close"); } } /* Helper methods */ void displayMedia(JSCommand command, JSONObject args, String type) throws JSONException { String url = args.getString("url"); String mimeType = args.getString("mimeType"); String title = args.optString("title"); String description = args.optString("description"); String iconSrc = args.optString("iconUrl"); boolean shouldLoop = args.optBoolean("shouldLoop"); if ("image".equals(type)) { device.getMediaPlayer().displayImage(url, mimeType, title, description, iconSrc, command.getMediaLaunchListener()); } else { device.getMediaPlayer().playMedia(url, mimeType, title, description, iconSrc, shouldLoop, command.getMediaLaunchListener()); } } void showToast(JSCommand command, JSONObject args, boolean clickable) throws JSONException { String message = args.getString("message"); JSONObject options = args.optJSONObject("options"); String url = null; String appId = null; String iconData = null; String iconExtension = null; JSONObject params = null; if (options != null) { iconData = options.optString("iconData"); iconExtension = options.optString("iconExtension"); if (clickable) { url = options.optString("url"); appId = options.optString("appId"); params = options.optJSONObject("params"); } } if (clickable) { if (url != null) { device.getToastControl().showClickableToastForURL(message, url, iconData, iconExtension, command.getResponseListener()); } else if (appId != null) { AppInfo appInfo = new AppInfo(); appInfo.setId(appId); device.getToastControl().showClickableToastForApp(message, appInfo, params, iconData, iconExtension, command.getResponseListener()); } else { command.error("toast options must include url or appId when showing a clickable toast"); } } else { device.getToastControl().showToast(message, iconData, iconExtension, command.getResponseListener()); } } LaunchSession getLaunchSession(JSONObject obj) { LaunchSession session = LaunchSession.launchSessionFromJSONObject(obj); String serviceName = obj.optString("serviceName"); DeviceService service = serviceName != null ? device.getServiceByName(serviceName) : null; if (service != null) { session.setService(service); } return session; } MediaControl getMediaControl(JSCommand command, JSONObject args) throws JSONException { String objectId = args.optString("objectId"); if (objectId != null) { MediaControlWrapper wrapper = (MediaControlWrapper) plugin.getObjectWrapper(objectId); if (wrapper != null) { return wrapper.mediaControl; } else { throw new DispatcherException("MediaControl session no longer exists"); } } else { return device.getMediaControl(); } } }