<commit_before>/*
 *  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.MediaInfo;
import com.connectsdk.core.SubtitleInfo;
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.MediaPlayer;
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());
    }
<commit_msg>[Android] Add showExternalInputPicker implementation<commit_after>/*
 *  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.MediaInfo;
import com.connectsdk.core.SubtitleInfo;
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;
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.MediaPlayer;
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());
    }

    @CommandMethod
    public void externalInputControl_showExternalInputPicker(JSCommand command, JSONObject args) {
        device.getCapability(ExternalInputControl.class)
                .launchInputPicker(command.getAppLaunchListener());
    }

    /* FivewayControl methods */

    @CommandMethod
    public void keyControl_up(JSCommand command, JSONObject args) throws JSONException {
        device.getKeyControl().up(command.getResponseListener());
    }

{'fraction_non_alphanumeric': 0.08538766622598958, 'fraction_numerical': 0.0013997978069834357, 'mean_word_length': 3.078655248969236, 'pattern_counts': {'":': 2, '<': 11, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3612884', 'n_tokens_mistral': 3270, 'n_tokens_neox': 3153, 'n_words': 754}