Skip to content
This repository has been archived by the owner on Jun 3, 2021. It is now read-only.

* [android] Fixing clearTimeout and clearInterval doesn't work when funId is greater than 127 #439

Merged
merged 1 commit into from
Jun 13, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,56 +18,61 @@
*/
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.IntDef;
import android.support.annotation.IntRange;
import android.support.annotation.VisibleForTesting;

import android.util.SparseArray;
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.WXJSBridgeMsgType;
import com.taobao.weex.common.WXModule;
import com.taobao.weex.dom.action.Actions;
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 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;

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<>();
}

@VisibleForTesting
void setHandler(Handler handler) {
this.handler = handler;
}

@JSMethod(uiThread = false)
public void setTimeout(@IntRange(from = 1) int funcId, @IntRange(from = 0) int delay) {
if(mWXSDKInstance != null) {
postOrHoldMessage(WXJSBridgeMsgType.MODULE_TIMEOUT, funcId, delay, Integer.parseInt(mWXSDKInstance.getInstanceId()));
postOrHoldMessage(MODULE_TIMEOUT, funcId, delay, Integer.parseInt(mWXSDKInstance.getInstanceId()));
}
}

@JSMethod(uiThread = false)
public void setInterval(@IntRange(from = 1) int funcId, @IntRange(from = 0) int interval) {
if(mWXSDKInstance != null) {
postOrHoldMessage(WXJSBridgeMsgType.MODULE_INTERVAL, funcId, interval, Integer.parseInt(mWXSDKInstance.getInstanceId()));
postOrHoldMessage(MODULE_INTERVAL, funcId, interval, Integer.parseInt(mWXSDKInstance.getInstanceId()));
}
}

Expand All @@ -76,22 +81,23 @@ public void clearTimeout(@IntRange(from = 1) int funcId) {
if (funcId <= 0) {
return;
}
removeOrHoldMessage(WXJSBridgeMsgType.MODULE_TIMEOUT, funcId);
removeOrHoldMessage(MODULE_TIMEOUT, funcId);
}

@JSMethod(uiThread = false)
public void clearInterval(@IntRange(from = 1) int funcId) {
if (funcId <= 0) {
return;
}
removeOrHoldMessage(WXJSBridgeMsgType.MODULE_INTERVAL, funcId);
removeOrHoldMessage(MODULE_INTERVAL, funcId);
}

@Override
public void destroy() {
if (handler != null) {
WXLogUtils.d(TAG, "Timer Module removeAllMessages: ");
handler.removeCallbacksAndMessages(null);
antiIntAutoBoxing.clear();
}
}

Expand All @@ -103,19 +109,19 @@ public boolean handleMessage(Message msg) {
int what = msg.what;
WXLogUtils.d(TAG, "Timer Module handleMessage : " + msg.what);
switch (what) {
case WXJSBridgeMsgType.MODULE_TIMEOUT:
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 WXJSBridgeMsgType.MODULE_INTERVAL:
case MODULE_INTERVAL:
if (msg.obj == null) {
break;
}
postMessage(WXJSBridgeMsgType.MODULE_INTERVAL, (Integer) msg.obj, msg.arg2, msg.arg1);
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;
Expand All @@ -127,6 +133,11 @@ public boolean handleMessage(Message msg) {
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);
Expand All @@ -142,23 +153,7 @@ private WXJSObject[] createTimerArgs(int instanceId, int funcId, boolean keepAli
WXJsonUtils.fromObjectToJSONString(tasks))};
}

private void postMessage(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 {
Message message = Message.obtain();
message.what = what;
message.arg1 = instanceId;
message.arg2 = interval;
message.obj = funcId;
handler.sendMessageDelayed(message, interval);
}
}


private void postOrHoldMessage(final int what,final int funcId,final int interval,final int instanceId) {
private void postOrHoldMessage(@MessageType final int what,final int funcId,final int interval,final int instanceId) {
if(mWXSDKInstance.isPreRenderMode()) {
WXSDKManager.getInstance().getWXDomManager().postAction(mWXSDKInstance.getInstanceId(), Actions.getExecutableRenderAction(new Runnable() {
@Override
Expand All @@ -171,17 +166,31 @@ public void run() {
}
}

private void removeOrHoldMessage(final int what,final int funcId) {
private void removeOrHoldMessage(@MessageType final int what,final int funcId) {
if(mWXSDKInstance.isPreRenderMode()) {
WXSDKManager.getInstance().getWXDomManager().postAction(mWXSDKInstance.getInstanceId(), Actions.getExecutableRenderAction(new Runnable() {
@Override
public void run() {
handler.removeMessages(what, funcId);
handler.removeMessages(what, antiIntAutoBoxing.get(funcId, funcId));
}
}),false);
} else {
handler.removeMessages(what, funcId);
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);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,23 @@
*/
package com.taobao.weex.ui.module;

import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.when;

import android.os.Handler;
import android.os.Message;

import com.taobao.weappplus_sdk.BuildConfig;
import com.taobao.weex.InitConfig;
import com.taobao.weex.WXSDKEngine;
import com.taobao.weex.WXSDKInstanceTest;
import com.taobao.weex.bridge.WXBridgeManager;
import com.taobao.weex.bridge.WXBridgeManagerTest;
import com.taobao.weex.common.WXThread;

import java.util.concurrent.TimeUnit;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
Expand All @@ -43,20 +49,14 @@
import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowLooper;

import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.when;

@RunWith(RobolectricTestRunner.class)
@Config(constants = BuildConfig.class, sdk = 19)
@Config(constants = BuildConfig.class)
@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"})
@PrepareForTest(WXBridgeManager.class)
public class WXTimerModuleTest {

public final static int VALID_FUNC_ID = 20;
public final static int NO_CACHING_FUNC_ID = 565654;
public final static int INVALID_FUNC_ID = 0;
public final static int DELAY = 50;
public final static int IMMEDIATELY = 0;
Expand Down Expand Up @@ -95,27 +95,31 @@ public void testSetTimeoutImmediately() throws Exception {
Mockito.verify(module, times(1)).handleMessage(any(Message.class));
}

@SuppressWarnings("Range")
@Test
public void testSetTimeoutError1() throws Exception {
module.setTimeout(INVALID_FUNC_ID, DELAY);
mLooper.idle(DELAY);
Mockito.verify(module, never()).handleMessage(any(Message.class));
}

@SuppressWarnings("Range")
@Test
public void testSetTimeoutError2() throws Exception {
module.setTimeout(VALID_FUNC_ID, INVALID_DELAY);
mLooper.runToEndOfTasks();
Mockito.verify(module, never()).handleMessage(any(Message.class));
}

@SuppressWarnings("Range")
@Test
public void testSetIntervalError1() throws Exception {
module.setInterval(INVALID_FUNC_ID, DELAY);
mLooper.idle(DELAY);
Mockito.verify(module, never()).handleMessage(any(Message.class));
}

@SuppressWarnings("Range")
@Test
public void testSetIntervalError2() throws Exception {
module.setInterval(VALID_FUNC_ID, INVALID_DELAY);
Expand Down Expand Up @@ -163,15 +167,31 @@ public void testSetIntervalDelay() {
public void testClearTimeout() throws Exception {
module.setTimeout(VALID_FUNC_ID, DELAY);
module.clearTimeout(VALID_FUNC_ID);
mLooper.idle(DELAY);
mLooper.idle(DELAY, TimeUnit.MILLISECONDS);
Mockito.verify(module, never()).handleMessage(any(Message.class));
}

@Test
public void testClearInterval() throws Exception {
module.setInterval(VALID_FUNC_ID, DELAY);
module.clearInterval(VALID_FUNC_ID);
mLooper.idle(DELAY);
mLooper.idle(DELAY, TimeUnit.MILLISECONDS);
Mockito.verify(module, never()).handleMessage(any(Message.class));
}

@Test
public void setClearTimeout2(){
module.setTimeout(NO_CACHING_FUNC_ID, DELAY);
module.clearTimeout(NO_CACHING_FUNC_ID);
mLooper.idle(DELAY, TimeUnit.MILLISECONDS);
Mockito.verify(module, never()).handleMessage(any(Message.class));
}

@Test
public void setClearInterval2(){
module.setInterval(NO_CACHING_FUNC_ID, DELAY);
module.clearInterval(NO_CACHING_FUNC_ID);
mLooper.idle(DELAY, TimeUnit.MILLISECONDS);
Mockito.verify(module, never()).handleMessage(any(Message.class));
}
}