package com.dataart.android.devicehive.network; import java.util.HashMap; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; import android.os.Bundle; import android.os.Handler; import android.os.HandlerThread; import android.os.ResultReceiver; import android.util.Log; import com.dataart.android.devicehive.DeviceHive; /** * Result receiver which is used to communicate(receive results) with service. */ public class DeviceHiveResultReceiver extends ResultReceiver { /** * Message with this code is sent when request is started. */ public final static int MSG_EXECUTE_REQUEST = 0x00000010; /** * Message with this code is sent to the result receiver when request is * finished regardless of whether it succeeds or fails. */ public final static int MSG_COMPLETE_REQUEST = 0x00000011; /** * Message with this code is sent to the result receiver when response of * the request is handled(parsed). */ public final static int MSG_HANDLED_RESPONSE = 0x00000012; /** * Message with this code is sent to the result receiver fails and returns * corresponding Http status code. */ public final static int MSG_STATUS_FAILURE = 0x00000013; /** * Message with this code is sent to the result receiver when request fails * due to connectivity loss or IO error that usually lead to exception to be * thrown. */ public final static int MSG_EXCEPTION = 0x0FFFFFFF; /** * Result listener interface. */ public static interface ResultListener { /** * Called when result receiver receives results from the service. * * @param code * Status code of the result. * @param tag * Tag value. * @param data * {@link Bundle} which contains command execution results. */ void onReceiveResult(int code, int tag, Bundle data); } private final static Handler mainThreadHandler = new Handler(); private final static Handler receiverHandler; static { final HandlerThread thread = new HandlerThread( DeviceHiveResultReceiver.class.getSimpleName() + "[Handler Thread]"); thread.start(); receiverHandler = new Handler(thread.getLooper()); } private static class ResultListenerConfig { private final ResultListener listener; private final boolean runOnMainThread; public ResultListenerConfig(ResultListener listener, boolean runOnMainThread) { this.listener = listener; this.runOnMainThread = runOnMainThread; } } private ResultListenerConfig resultListenerConfig = null; public DeviceHiveResultReceiver() { super(receiverHandler); } /** * Detach result listener from the result receiver. */ public void detachResultListener() { this.resultListenerConfig = null; } /** * Set result listener. * * @param listener * {@link ResultListener} instance. * @param runOnMainThread * Whether * {@link ResultListener#onReceiveResult(int, int, Bundle)} * should run on the main Thread. */ public void setResultListener(final ResultListener listener, final boolean runOnMainThread) { this.resultListenerConfig = new ResultListenerConfig(listener, runOnMainThread); } @Override protected void onReceiveResult(final int resultCode, final Bundle resultData) { if (resultListenerConfig != null) { final int commandTagId = getIdForTag(NetworkCommand .getCommandTag(resultData)); if (resultListenerConfig.runOnMainThread) { mainThreadHandler.post(new Runnable() { @Override public void run() { if (resultListenerConfig != null) { resultListenerConfig.listener.onReceiveResult( resultCode, commandTagId, resultData); } } }); } else { resultListenerConfig.listener.onReceiveResult(resultCode, commandTagId, resultData); } } else { Log.w(DeviceHive.TAG, String.format( "Received result in detached listener: %s, %s", resultCode, resultData)); } } /** * Get tag id for given command tag. Returns the same value for equal tag * strings. * * @param tag * Command tag. * @return Integer value corresponding to the tag. */ public static final int getIdForTag(final String tag) { Integer id = existingTags.get(tag); if (id == null) { id = tagIdCounter.incrementAndGet(); existingTags.put(tag, id); } return id.intValue(); } private final static AtomicInteger tagIdCounter = new AtomicInteger(0); private final static Map<String, Integer> existingTags = new HashMap<String, Integer>(); }