/*
* Copyright (C) 2014 The AppCan Open Source Project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package org.zywx.wbpalmstar.engine.universalex;
import android.content.Context;
import android.os.Build;
import android.support.annotation.Keep;
import com.google.gson.reflect.TypeToken;
import org.json.JSONException;
import org.json.JSONObject;
import org.zywx.wbpalmstar.base.BDebug;
import org.zywx.wbpalmstar.base.vo.AppCanJsVO;
import org.zywx.wbpalmstar.engine.AppCan;
import org.zywx.wbpalmstar.engine.DataHelper;
import org.zywx.wbpalmstar.engine.EBrowserView;
import org.zywx.wbpalmstar.engine.ELinkedList;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
public class EUExManager {
private final static String RETURN_RESULT_FORMAT = "{\"code\": %d, \"result\": %s}";
private Context mContext;
private ELinkedList<EUExBase> mThirdPlugins;
public EUExManager(Context context) {
mContext = context;
mThirdPlugins = new ELinkedList<EUExBase>();
}
public void addJavascriptInterface(EBrowserView brwView) {
EUExWidgetOne widgetOne = new EUExWidgetOne(mContext, brwView);
widgetOne.setUexName(EUExWidgetOne.tag);
EUExWindow window = new EUExWindow(mContext, brwView);
window.setUexName(EUExWindow.tag);
EUExWidget widget = new EUExWidget(mContext, brwView);
widget.setUexName(EUExWidget.tag);
if (Build.VERSION.SDK_INT >= 11) {
brwView.removeJavascriptInterface("searchBoxJavaBridge_");
brwView.removeJavascriptInterface("accessibility");
brwView.removeJavascriptInterface("accessibilityTraversal");
}
mThirdPlugins.add(widgetOne);
mThirdPlugins.add(window);
mThirdPlugins.add(widget);
// third-party plugin
Map<String, ThirdPluginObject> thirdPlugins = getPlugins();
// String symbol = "_";
Set<Map.Entry<String, ThirdPluginObject>> pluginSet = thirdPlugins.entrySet();
for (Map.Entry<String, ThirdPluginObject> entry : pluginSet) {
String uName = entry.getKey();
ThirdPluginObject scriptObj = entry.getValue();
EUExBase objectIntance = null;
try {
if (scriptObj.isGlobal && scriptObj.pluginObj != null) {
objectIntance = scriptObj.pluginObj;
} else {
Constructor<?> init = scriptObj.jobject;
objectIntance = (EUExBase) init.newInstance(mContext, brwView);
}
}catch (Exception e) {
if (BDebug.DEBUG){
e.printStackTrace();
}
}
if (null != objectIntance) {
// String uexName = uName + symbol;
objectIntance.setUexName(uName);
if (scriptObj.isGlobal) {
scriptObj.pluginObj = objectIntance;
} else {
mThirdPlugins.add(objectIntance);
}
}
}
}
public Map<String, ThirdPluginObject> getPlugins() {
ThirdPluginMgr tpm = AppCan.getInstance().getThirdPlugins();
return tpm.getPlugins();
}
/**
* 解析String 根据插件名找到对应的插件调用插件
* @return 返回结果,json格式
*/
@Keep
public String dispatch(String parseStr) throws JSONException {
BDebug.json( parseStr);
AppCanJsVO appCanJs = DataHelper.gson.fromJson(parseStr, new TypeToken<AppCanJsVO>(){}.getType());
String pluginName = appCanJs.uexName;
String methodName = appCanJs.method;
List<Object> appCanJsArgs = appCanJs.args;
List<String> appCanJsTypes = appCanJs.types;
int length = appCanJsArgs.size();
String[] params = new String[length];
for (int i = 0; i < length; i++) {
String type = appCanJsTypes.get(i);
String arg;
if (appCanJsArgs.get(i) instanceof String){
arg= (String) appCanJsArgs.get(i);
}else if ("function".equals(type)){
if (appCanJsArgs.get(i) instanceof Double) {
arg = String.valueOf(((Double) appCanJsArgs.get(i)).intValue());//Gson 默认把int转成double
}else{
arg = String.valueOf(appCanJsArgs.get(i));
}
}else{
arg = DataHelper.gson.toJson(appCanJsArgs.get(i));
}
if ("undefined".equals(type) && "null".equals(arg)) {
params[i] = null;
} else {
params[i] = arg;
}
}
ELinkedList<EUExBase> plugins = getThirdPlugins();
for (EUExBase plugin : plugins) {
if (plugin.getUexName().equals(pluginName)) {
String resultStr =callMethod(plugin,
methodName, params);
if (null != resultStr) {
return resultStr;
}
}
}
// 调用单实例插件
Map<String, ThirdPluginObject> thirdPlugins = getPlugins();
ThirdPluginObject thirdPluginObject = thirdPlugins
.get(pluginName);
if (thirdPluginObject != null
&& thirdPluginObject.isGlobal
&& thirdPluginObject.pluginObj != null) {
String resultStr =callMethod(
thirdPluginObject.pluginObj,
methodName, params);
if (null != resultStr) {
return resultStr;
}
}
BDebug.e("plugin", pluginName, "not exist...");
return getReturn(204, "plugin " + pluginName + " not exist...");
}
public String callMethod(final EUExBase plugin, final String methodName, final String[] params) {
if (plugin.mDestroyed) {
BDebug.e("plugin", plugin.getUexName(), " has been destroyed");
return null;
}
try {
Method targetMethod = plugin.getClass().getMethod(methodName,
String[].class);
return getReturn(200,targetMethod.invoke(plugin, (Object) params));
} catch (NoSuchMethodException e) {
BDebug.e(methodName, " NoSuchMethodException");
return getReturn(201,"NoSuchMethodException:"+e.getMessage());
} catch (IllegalAccessException e) {
BDebug.e(plugin.getUexName(), methodName, e.toString());
return getReturn(202,"IllegalAccessException:"+e.getMessage());
} catch (InvocationTargetException e) {
BDebug.e(plugin.getUexName(),methodName, " InvocationTargetException");
if (BDebug.DEBUG) {
e.printStackTrace();
}
return getReturn(203,"InvocationTargetException:"+e.getMessage());
}
}
public static String getReturn (int stateCode, Object result) {
String insertRes;
if (result == null) {
insertRes = "null";
} else if (result instanceof String) {
result = ((String) result).replace("\"", "\\\"");
insertRes = "\"" + result + "\"";
} else if (!(result instanceof Integer)
&& !(result instanceof Long)
&& !(result instanceof Boolean)
&& !(result instanceof Float)
&& !(result instanceof Double)
&& !(result instanceof JSONObject)) { // 非数字或者非字符串的构造对象类型都要序列化后再拼接
insertRes = DataHelper.gson.toJson(result);
} else { //数字直接转化
insertRes = String.valueOf(result);
}
return String.format(Locale.getDefault(),RETURN_RESULT_FORMAT, stateCode, insertRes);
}
public void notifyReset() {
for (EUExBase uex : mThirdPlugins) {
uex.reset();
}
}
public void notifyDocChange() {
for (EUExBase uex : mThirdPlugins) {
uex.clean();
}
}
public void notifyStop() {
notifyDocChange();
for (EUExBase uex : mThirdPlugins) {
uex.stop();
}
}
public void notifyDestroy(EBrowserView view) {
notifyDocChange();
for (EUExBase uex : mThirdPlugins) {
if (Build.VERSION.SDK_INT >= 11) {
String uexName = uex.getUexName();
view.removeJavascriptInterface(uexName);
}
uex.destroy();
}
mThirdPlugins.clear();
mThirdPlugins = null;
mContext = null;
}
public ELinkedList<EUExBase> getThirdPlugins() {
return mThirdPlugins;
}
}