/*
* Created by LuaView.
* Copyright (c) 2017, Alibaba Group. All rights reserved.
*
* This source code is licensed under the MIT.
* For the full copyright and license information,please view the LICENSE file in the root directory of this source tree.
*/
package com.taobao.luaview.global;
import com.taobao.luaview.cache.AppCache;
import com.taobao.luaview.fun.base.BaseMethodMapper;
import com.taobao.luaview.fun.binder.constants.AlignBinder;
import com.taobao.luaview.fun.binder.constants.EllipsizeBinder;
import com.taobao.luaview.fun.binder.constants.FontStyleBinder;
import com.taobao.luaview.fun.binder.constants.FontWeightBinder;
import com.taobao.luaview.fun.binder.constants.GravityBinder;
import com.taobao.luaview.fun.binder.constants.InterpolatorBinder;
import com.taobao.luaview.fun.binder.constants.PaintStyleBinder;
import com.taobao.luaview.fun.binder.constants.PinnedBinder;
import com.taobao.luaview.fun.binder.constants.ScaleTypeBinder;
import com.taobao.luaview.fun.binder.constants.TextAlignBinder;
import com.taobao.luaview.fun.binder.constants.TouchEventBinder;
import com.taobao.luaview.fun.binder.constants.ViewEffectBinder;
import com.taobao.luaview.fun.binder.indicator.UICircleViewPagerIndicatorBinder;
import com.taobao.luaview.fun.binder.indicator.UICustomViewPagerIndicatorBinder;
import com.taobao.luaview.fun.binder.kit.ActionBarBinder;
import com.taobao.luaview.fun.binder.kit.AudioBinder;
import com.taobao.luaview.fun.binder.kit.DataBinder;
import com.taobao.luaview.fun.binder.kit.FileBinder;
import com.taobao.luaview.fun.binder.kit.JsonBinder;
import com.taobao.luaview.fun.binder.kit.SystemBinder;
import com.taobao.luaview.fun.binder.kit.TimerBinder;
import com.taobao.luaview.fun.binder.kit.UnicodeBinder;
import com.taobao.luaview.fun.binder.kit.VibratorBinder;
import com.taobao.luaview.fun.binder.net.HttpBinder;
import com.taobao.luaview.fun.binder.ui.SpannableStringBinder;
import com.taobao.luaview.fun.binder.ui.UIAlertBinder;
import com.taobao.luaview.fun.binder.ui.UIAnimatorBinder;
import com.taobao.luaview.fun.binder.ui.UIAnimatorSetBinder;
import com.taobao.luaview.fun.binder.ui.UIButtonBinder;
import com.taobao.luaview.fun.binder.ui.UICustomViewBinder;
import com.taobao.luaview.fun.binder.ui.UIEditTextBinder;
import com.taobao.luaview.fun.binder.ui.UIHorizontalScrollViewBinder;
import com.taobao.luaview.fun.binder.ui.UIImageViewBinder;
import com.taobao.luaview.fun.binder.ui.UIListViewBinder;
import com.taobao.luaview.fun.binder.ui.UILoadingDialogBinder;
import com.taobao.luaview.fun.binder.ui.UILoadingViewBinder;
import com.taobao.luaview.fun.binder.ui.UIRecyclerViewBinder;
import com.taobao.luaview.fun.binder.ui.UIRefreshLayoutBinder;
import com.taobao.luaview.fun.binder.ui.UIRefreshListViewBinder;
import com.taobao.luaview.fun.binder.ui.UIRefreshRecyclerViewBinder;
import com.taobao.luaview.fun.binder.ui.UITextViewBinder;
import com.taobao.luaview.fun.binder.ui.UIToastBinder;
import com.taobao.luaview.fun.binder.ui.UIViewGroupBinder;
import com.taobao.luaview.fun.binder.ui.UIViewPagerBinder;
import com.taobao.luaview.fun.binder.ui.UIWebViewBinder;
import com.taobao.luaview.fun.mapper.LuaViewLib;
import com.taobao.luaview.fun.mapper.ui.NewIndexFunction;
import com.taobao.luaview.scriptbundle.asynctask.SimpleTask;
import com.taobao.luaview.scriptbundle.asynctask.SimpleTask0;
import com.taobao.luaview.vm.extend.luadc.LuaDC;
import org.luaj.vm2.Globals;
import org.luaj.vm2.LuaError;
import org.luaj.vm2.LuaTable;
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.lib.LibFunction;
import org.luaj.vm2.lib.jse.JsePlatform;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* LuaView Lib管理等
*
* @author song
* @date 15/8/14
*/
public class LuaViewManager {
private static final String CACHE_METATABLES = AppCache.CACHE_METATABLES;
public static Globals sStaticGlobals;//使用该全局Globals来加速加载,需要提前创建Globals
/**
* pre create globals
*
* @return
*/
public static synchronized void preCreateGlobals() {
synchronized (LuaViewManager.class) {
if (sStaticGlobals == null) {
new SimpleTask0() {
@Override
public void doTask() {
synchronized (LuaViewManager.class) {
if (sStaticGlobals == null) {
sStaticGlobals = setupGlobals(new Globals());
}
}
}
}.executeInPool();
}
}
}
/**
* 创建Globals
* 根据是否用lua-to-java bytecode来处理(如果使用LuaJC的话则会使用库bcel 533k)
*
* @return
*/
public static Globals createGlobals() {
if (sStaticGlobals != null) {
synchronized (sStaticGlobals) {
Globals result = sStaticGlobals;
sStaticGlobals = null;
return result;
}
} else {
return setupGlobals(new Globals());
}
}
/**
* 创建Globals
* 根据是否用lua-to-java bytecode来处理(如果使用LuaJC的话则会使用库bcel 533k)
*
* @return
*/
public static Globals createGlobalsAsync() {
if (sStaticGlobals != null) {
synchronized (sStaticGlobals) {
Globals result = sStaticGlobals;
sStaticGlobals = null;
return result;
}
} else {
final Globals globals = new Globals();
new SimpleTask<Globals>() {
@Override
public void doTask(Globals... params) {
setupGlobals(params != null && params.length > 0 ? params[0] : null);
}
}.executeSerial(globals);//TODO 这里放到serial线程中执行,而不是executeInPool中执行,为了保证后续的执行时序列
return globals;
}
}
/**
* setup global values
*
* @param globals
*/
private static Globals setupGlobals(Globals globals) {
if (globals != null) {
if (LuaViewConfig.isOpenDebugger()) {
JsePlatform.debugGlobals(globals);
} else {
JsePlatform.standardGlobals(globals);//加载系统libs TODO 性能瓶颈
}
if (LuaViewConfig.isUseLuaDC()) {
LuaDC.install(globals);
}
loadLuaViewLibs(globals);//加载用户lib TODO 性能瓶颈
globals.isInited = true;
}
return globals;
}
/**
* tryLazyLoad Android API lib
* TODO 能否做到按需加载,而不是首次进来加载全部binder
*
* @param globals
*/
private static void loadLuaViewLibs(final Globals globals) {
//ui
globals.tryLazyLoad(new UITextViewBinder());
globals.tryLazyLoad(new UIEditTextBinder());
globals.tryLazyLoad(new UIButtonBinder());
globals.tryLazyLoad(new UIImageViewBinder());
globals.tryLazyLoad(new UIViewGroupBinder());
globals.tryLazyLoad(new UIListViewBinder());
globals.tryLazyLoad(new UIRecyclerViewBinder());
globals.tryLazyLoad(new UIRefreshListViewBinder());
globals.tryLazyLoad(new UIRefreshRecyclerViewBinder());
globals.tryLazyLoad(new UIViewPagerBinder());
globals.tryLazyLoad(new UICustomViewPagerIndicatorBinder());
globals.tryLazyLoad(new UICircleViewPagerIndicatorBinder());
globals.tryLazyLoad(new UIHorizontalScrollViewBinder());
globals.tryLazyLoad(new UIAlertBinder());
globals.tryLazyLoad(new UILoadingViewBinder());
globals.tryLazyLoad(new UILoadingDialogBinder());
globals.tryLazyLoad(new UIToastBinder());
globals.tryLazyLoad(new SpannableStringBinder());
globals.tryLazyLoad(new UIWebViewBinder());
globals.tryLazyLoad(new UICustomViewBinder());
globals.tryLazyLoad(new UIRefreshLayoutBinder());
//animation
globals.tryLazyLoad(new UIAnimatorBinder());
globals.tryLazyLoad(new UIAnimatorSetBinder());
//net
globals.tryLazyLoad(new HttpBinder());
//kit
globals.tryLazyLoad(new TimerBinder());
globals.tryLazyLoad(new SystemBinder());
globals.tryLazyLoad(new ActionBarBinder());
globals.tryLazyLoad(new FileBinder());
globals.tryLazyLoad(new UnicodeBinder());
globals.tryLazyLoad(new DataBinder());
globals.tryLazyLoad(new JsonBinder());
globals.tryLazyLoad(new AudioBinder());
globals.tryLazyLoad(new VibratorBinder());
//常量
globals.tryLazyLoad(new AlignBinder());
globals.tryLazyLoad(new TextAlignBinder());
globals.tryLazyLoad(new FontWeightBinder());
globals.tryLazyLoad(new FontStyleBinder());
globals.tryLazyLoad(new ScaleTypeBinder());
globals.tryLazyLoad(new GravityBinder());
globals.tryLazyLoad(new EllipsizeBinder());
globals.tryLazyLoad(new InterpolatorBinder());
globals.tryLazyLoad(new ViewEffectBinder());//view特效
globals.tryLazyLoad(new PinnedBinder());
globals.tryLazyLoad(new PaintStyleBinder());
globals.tryLazyLoad(new TouchEventBinder());
}
//----------------------------------------bind methods------------------------------------------
/**
* bind lua function using methods
*
* @param factory
* @param methods
*/
public static LuaTable bindMethods(Class<? extends LibFunction> factory, Method[] methods) {
if (methods != null) {
return bindMethods(factory, Arrays.asList(methods));
}
return new LuaTable();
}
/**
* bind lua functions using method
*
* @param factory
* @param methods
* @return
*/
public static LuaTable bindMethods(Class<? extends LibFunction> factory, List<Method> methods) {
LuaTable env = new LuaTable();
try {
if (methods != null) {
for (int i = 0; i < methods.size(); i++) {
LibFunction f = factory.newInstance();
f.opcode = -1;
f.method = methods.get(i);
f.name = methods.get(i).getName();
env.set(f.name, f);
}
}
} catch (Exception e) {
throw new LuaError("[Bind Failed] " + e);
} finally {
return env;
}
}
/**
* bind lua functions using opcode
*
* @param factory
* @param methods
* @return
*/
public static LuaTable bind(Class<? extends LibFunction> factory, List<String> methods) {
LuaTable env = new LuaTable();
try {
if (methods != null) {
for (int i = 0; i < methods.size(); i++) {
LibFunction f = factory.newInstance();
f.opcode = i;
f.method = null;
f.name = methods.get(i);
env.set(f.name, f);
}
}
} catch (Exception e) {
throw new LuaError("[Bind Failed] " + e);
} finally {
return env;
}
}
/**
* bind lua functions using opcode
*
* @param factory
* @param methods
* @return
*/
public static LuaTable bind(Class<? extends LibFunction> factory, String[] methods) {
LuaTable env = new LuaTable();
try {
if (methods != null) {
for (int i = 0; i < methods.length; i++) {
LibFunction f = factory.newInstance();
f.opcode = i;
f.method = null;
f.name = methods[i];
env.set(f.name, f);
}
}
} catch (Exception e) {
throw new LuaError("[Bind Failed] " + e);
} finally {
return env;
}
}
//-----------------------------------------metatable--------------------------------------------
/**
* create metatable for libs
*
* @return
*/
public static LuaTable createMetatable(Class<? extends LibFunction> libClass) {
LuaTable result = AppCache.getCache(CACHE_METATABLES).get(libClass);//get from cache
if (result == null) {
LuaTable libTable = null;
if (LuaViewConfig.isUseNoReflection()) {
final List<String> methodNames = getMapperMethodNames(libClass);
libTable = LuaViewManager.bind(libClass, methodNames);
} else {
final List<Method> methods = getMapperMethods(libClass);
libTable = LuaViewManager.bindMethods(libClass, methods);
}
result = LuaValue.tableOf(new LuaValue[]{LuaValue.INDEX, libTable, LuaValue.NEWINDEX, new NewIndexFunction(libTable)});
//update cache
AppCache.getCache(CACHE_METATABLES).put(libClass, result);
}
return result;
}
/**
* 获取所有方法的名字
*
* @param clazz
* @return
*/
private static List<String> getMapperMethodNames(final Class clazz) {
try {
if (clazz != null) {
Object obj = clazz.newInstance();
if (obj instanceof BaseMethodMapper) {
return ((BaseMethodMapper) obj).getAllFunctionNames();
}
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 获取所有方法
*
* @param clazz
* @return
*/
private static List<Method> getMapperMethods(final Class clazz) {
final List<Method> methods = new ArrayList<Method>();
getMapperMethodsByClazz(methods, clazz);
return methods.size() > 0 ? methods : null;
}
private static void getMapperMethodsByClazz(final List<Method> result, final Class clazz) {
if (clazz != null && clazz.isAnnotationPresent(LuaViewLib.class)) {//XXXMapper
getMapperMethodsByClazz(result, clazz.getSuperclass());//处理super
final Method[] methods = clazz.getDeclaredMethods();
if (methods != null && methods.length > 0) {
for (final Method method : methods) {//add self
if (method.getModifiers() == Modifier.PUBLIC) {//public 方法才行
result.add(method);
}
}
}
}
}
}