| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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.taobao.weex.ui.module; |
| |
| import static com.taobao.weex.bridge.WXBridgeManager.KEY_ARGS; |
| import static com.taobao.weex.bridge.WXBridgeManager.KEY_METHOD; |
| import static com.taobao.weex.bridge.WXBridgeManager.METHOD_CALLBACK; |
| import static com.taobao.weex.bridge.WXBridgeManager.METHOD_CALL_JS; |
| import static com.taobao.weex.common.WXJSBridgeMsgType.MODULE_INTERVAL; |
| import static com.taobao.weex.common.WXJSBridgeMsgType.MODULE_TIMEOUT; |
| |
| import android.os.Handler; |
| import android.os.Message; |
| import android.support.annotation.FloatRange; |
| import android.support.annotation.IntDef; |
| import android.support.annotation.IntRange; |
| import android.support.annotation.VisibleForTesting; |
| import android.util.SparseArray; |
| |
| import com.taobao.weex.WXEnvironment; |
| import com.taobao.weex.WXSDKManager; |
| import com.taobao.weex.annotation.JSMethod; |
| import com.taobao.weex.bridge.WXBridgeManager; |
| import com.taobao.weex.bridge.WXHashMap; |
| import com.taobao.weex.bridge.WXJSObject; |
| import com.taobao.weex.common.Destroyable; |
| import com.taobao.weex.common.WXModule; |
| import com.taobao.weex.utils.WXJsonUtils; |
| import com.taobao.weex.utils.WXLogUtils; |
| import java.lang.annotation.Retention; |
| import java.lang.annotation.RetentionPolicy; |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import com.taobao.weex.utils.WXUtils; |
| |
| public class WXTimerModule extends WXModule implements Destroyable, Handler.Callback { |
| |
| @IntDef({MODULE_TIMEOUT, MODULE_INTERVAL}) |
| @Retention(RetentionPolicy.SOURCE) |
| @interface MessageType {} |
| |
| private final static String TAG = "timer"; |
| private Handler handler; |
| private SparseArray<Integer> antiIntAutoBoxing; |
| |
| public WXTimerModule() { |
| handler = new Handler(WXBridgeManager.getInstance().getJSLooper(), this); |
| antiIntAutoBoxing = new SparseArray<>(); |
| } |
| |
| |
| @JSMethod(uiThread = false) |
| public void setTimeout(@IntRange(from = 1) int funcId, @FloatRange(from = 0) float delay) { |
| if(mWXSDKInstance != null) { |
| postOrHoldMessage(MODULE_TIMEOUT, funcId, (int) delay, WXUtils.parseInt(mWXSDKInstance.getInstanceId())); |
| WXSDKManager.getInstance().postOnUiThread(new Runnable() { |
| @Override |
| public void run() { |
| if (null != mWXSDKInstance){ |
| mWXSDKInstance.getWXPerformance().timerInvokeCount++; |
| } |
| } |
| },0); |
| } |
| } |
| |
| @JSMethod(uiThread = false) |
| public void setInterval(@IntRange(from = 1) int funcId, @FloatRange(from = 0) float interval) { |
| if(mWXSDKInstance != null) { |
| postOrHoldMessage(MODULE_INTERVAL, funcId, (int) interval, WXUtils.parseInt(mWXSDKInstance.getInstanceId())); |
| WXSDKManager.getInstance().postOnUiThread(new Runnable() { |
| @Override |
| public void run() { |
| if (null != mWXSDKInstance){ |
| mWXSDKInstance.getWXPerformance().timerInvokeCount++; |
| } |
| } |
| },0); |
| } |
| } |
| |
| @JSMethod(uiThread = false) |
| public void clearTimeout(@IntRange(from = 1) int funcId) { |
| if (funcId <= 0) { |
| return; |
| } |
| removeOrHoldMessage(MODULE_TIMEOUT, funcId); |
| } |
| |
| @JSMethod(uiThread = false) |
| public void clearInterval(@IntRange(from = 1) int funcId) { |
| if (funcId <= 0) { |
| return; |
| } |
| removeOrHoldMessage(MODULE_INTERVAL, funcId); |
| } |
| |
| @Override |
| public void destroy() { |
| if (handler != null) { |
| if(WXEnvironment.isApkDebugable()) { |
| WXLogUtils.d(TAG, "Timer Module removeAllMessages: "); |
| } |
| handler.removeCallbacksAndMessages(null); |
| antiIntAutoBoxing.clear(); |
| } |
| } |
| |
| @Override |
| public boolean handleMessage(Message msg) { |
| boolean ret = false; |
| WXJSObject[] args; |
| if (msg != null) { |
| int what = msg.what; |
| if(WXEnvironment.isApkDebugable()) { |
| WXLogUtils.d(TAG, "Timer Module handleMessage : " + msg.what); |
| } |
| switch (what) { |
| case MODULE_TIMEOUT: |
| if (msg.obj == null) { |
| break; |
| } |
| args = createTimerArgs(msg.arg1, (Integer) msg.obj, false); |
| WXBridgeManager.getInstance().invokeExecJS(String.valueOf(msg.arg1), null, METHOD_CALL_JS, args, true); |
| ret = true; |
| break; |
| case MODULE_INTERVAL: |
| if (msg.obj == null) { |
| break; |
| } |
| postMessage(MODULE_INTERVAL, (Integer) msg.obj, msg.arg2, msg.arg1); |
| args = createTimerArgs(msg.arg1, (Integer) msg.obj, true); |
| WXBridgeManager.getInstance().invokeExecJS(String.valueOf(msg.arg1), null, METHOD_CALL_JS, args, true); |
| ret = true; |
| break; |
| default: |
| break; |
| } |
| } |
| return ret; |
| } |
| |
| @VisibleForTesting |
| void setHandler(Handler handler) { |
| this.handler = handler; |
| } |
| |
| private WXJSObject[] createTimerArgs(int instanceId, int funcId, boolean keepAlive) { |
| ArrayList<Object> argsList = new ArrayList<>(); |
| argsList.add(funcId); |
| argsList.add(new HashMap<>()); |
| argsList.add(keepAlive); |
| WXHashMap<String, Object> task = new WXHashMap<>(); |
| task.put(KEY_METHOD, METHOD_CALLBACK); |
| task.put(KEY_ARGS, argsList); |
| Object[] tasks = {task}; |
| return new WXJSObject[]{ |
| new WXJSObject(WXJSObject.String, String.valueOf(instanceId)), |
| new WXJSObject(WXJSObject.JSON, |
| WXJsonUtils.fromObjectToJSONString(tasks))}; |
| } |
| |
| private void postOrHoldMessage(@MessageType final int what,final int funcId,final int interval,final int instanceId) { |
| if(mWXSDKInstance.isPreRenderMode()) { |
| postMessage(what,funcId,interval,instanceId); |
| } else { |
| postMessage(what,funcId,interval,instanceId); |
| } |
| } |
| |
| private void removeOrHoldMessage(@MessageType final int what,final int funcId) { |
| if(mWXSDKInstance.isPreRenderMode()) { |
| handler.removeMessages(what, antiIntAutoBoxing.get(funcId, funcId)); |
| } else { |
| handler.removeMessages(what, antiIntAutoBoxing.get(funcId, funcId)); |
| } |
| } |
| |
| private void postMessage(@MessageType int what, |
| @IntRange(from = 1) int funcId, |
| @IntRange(from = 0) int interval, int instanceId) { |
| if (interval < 0 || funcId <= 0) { |
| WXLogUtils.e(TAG, "interval < 0 or funcId <=0"); |
| } else { |
| if(antiIntAutoBoxing.get(funcId) == null) { |
| antiIntAutoBoxing.put(funcId, funcId); |
| } |
| Message message = handler |
| .obtainMessage(what, instanceId, interval, antiIntAutoBoxing.get(funcId)); |
| handler.sendMessageDelayed(message, interval); |
| } |
| } |
| } |