diff options
Diffstat (limited to 'apps/SdkController/SdkControllerApp/src/com/android/tools/sdkcontroller/handlers')
4 files changed, 304 insertions, 168 deletions
diff --git a/apps/SdkController/SdkControllerApp/src/com/android/tools/sdkcontroller/handlers/BaseHandler.java b/apps/SdkController/SdkControllerApp/src/com/android/tools/sdkcontroller/handlers/BaseHandler.java index a89eefd..0e30c4d 100755 --- a/apps/SdkController/SdkControllerApp/src/com/android/tools/sdkcontroller/handlers/BaseHandler.java +++ b/apps/SdkController/SdkControllerApp/src/com/android/tools/sdkcontroller/handlers/BaseHandler.java @@ -18,8 +18,13 @@ package com.android.tools.sdkcontroller.handlers; import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.atomic.AtomicInteger;
import android.content.Context;
+import android.os.Message;
+import android.util.Log;
import com.android.tools.sdkcontroller.lib.EmulatorConnection;
import com.android.tools.sdkcontroller.lib.EmulatorListener;
@@ -31,9 +36,35 @@ import com.android.tools.sdkcontroller.service.ControllerService; * <p/>
* The {@link ControllerService} can deal with several handlers, each have a specific
* purpose as described by {@link HandlerType}.
+ * <p/>
+ * The {@link BaseHandler} class adds support for activities to connect by providing
+ * an {@link android.os.Handler} (which we'll call a "UI Handler" to differentiate it
+ * from our "Service Handler"). The service handler will provide events via this
+ * UI handler directly on the activity's UI thread.
+ * <p/>
+ * The {@link BaseHandler} keeps track of the current {@link EmulatorConnection} given
+ * via {@link #onStart(EmulatorConnection, Context)}.
+ * <p/>
+ * The {@link BaseHandler} provides a simple way for activities to send event messages
+ * back to the emulator by using {@link #sendEventToEmulator(String)}. This method
+ * is safe to call from any thread, even the UI thread.
*/
public abstract class BaseHandler {
+ protected static final boolean DEBUG = false;
+ protected static final String TAG = null;
+
+ private EmulatorConnection mConnection;
+
+ private final AtomicInteger mEventCount = new AtomicInteger(0);
+ private volatile boolean mRunEventQueue = true;
+ private final BlockingQueue<String> mEventQueue = new LinkedBlockingQueue<String>();
+ private static String EVENT_QUEUE_END = "@end@";
+ private final List<android.os.Handler> mUiHandlers = new ArrayList<android.os.Handler>();
+ private final HandlerType mHandlerType;
+ private final Thread mEventThread;
+ private int mPort;
+
/**
* The type of action that this handler manages.
*/
@@ -46,13 +77,48 @@ public abstract class BaseHandler { }
/**
- * Returns the type of this handler.
+ * Initializes a new base handler.
+ *
+ * @param type A non-null {@link HandlerType} value.
+ * @param port A non-null communication port number.
+ */
+ protected BaseHandler(HandlerType type, int port) {
+ mHandlerType = type;
+ mPort = port;
+
+ final String name = type.toString();
+ mEventThread = new Thread(new Runnable() {
+ @Override
+ public void run() {
+ if (DEBUG) Log.d(TAG, "EventThread.started-" + name);
+ while(mRunEventQueue) {
+ try {
+ String msg = mEventQueue.take();
+ if (msg != null && mConnection != null && !msg.equals(EVENT_QUEUE_END)) {
+ mConnection.sendNotification(msg);
+ mEventCount.incrementAndGet();
+ }
+ } catch (InterruptedException e) {
+ Log.e(TAG, "EventThread-" + name, e);
+ }
+ }
+ if (DEBUG) Log.d(TAG, "EventThread.terminate-" + name);
+ }
+ }, "EventThread-" + name);
+ }
+
+ /**
+ * Returns the type of this handler, as given to the constructor.
+ *
* @return One of the {@link HandlerType} values.
*/
- public abstract HandlerType getType();
+ public HandlerType getType() {
+ return mHandlerType;
+ }
/**
- * The communication port used by this handler to communicate with the emulator.
+ * Returns he communication port used by this handler to communicate with the emulator,
+ * as given to the constructor.
* <p/>
* Note that right now we have 2 handlers that each use their own port. The goal is
* to move to a single-connection mechanism where all the handlers' data will be
@@ -60,13 +126,28 @@ public abstract class BaseHandler { *
* @return A non-null port value.
*/
- public abstract int getPort();
+ public int getPort() {
+ return mPort;
+ }
+
+ /**
+ * Returns the last {@link EmulatorConnection} passed to
+ * {@link #onStart(EmulatorConnection, Context)}.
+ * It becomes null when {@link #onStop()} is called.
+ *
+ * @return The current {@link EmulatorConnection}.
+ */
+ public EmulatorConnection getConnection() {
+ return mConnection;
+ }
/**
* Called once the {@link EmulatorConnection} has been successfully initialized.
* <p/>
* Note that this will <em>not</em> be called if the {@link EmulatorConnection}
* fails to bind to the underlying socket.
+ * <p/>
+ * This base implementation keeps tracks of the connection.
*
* @param connection The connection that has just been created.
* A handler might want to use this to send data to the emulator via
@@ -74,13 +155,45 @@ public abstract class BaseHandler { * need to be particularly careful in <em>not</em> sending network data
* from the main UI thread.
* @param context The controller service' context.
+ * @see #getConnection()
*/
- public abstract void onStart(EmulatorConnection connection, Context context);
+ public void onStart(EmulatorConnection connection, Context context) {
+ assert connection != null;
+ mConnection = connection;
+ mRunEventQueue = true;
+ mEventThread.start();
+ }
/**
* Called once the {@link EmulatorConnection} is being disconnected.
+ * This nullifies the connection returned by {@link #getConnection()}.
*/
- public abstract void onStop();
+ public void onStop() {
+ // Stop the message queue
+ mConnection = null;
+ if (mRunEventQueue) {
+ mRunEventQueue = false;
+ mEventQueue.offer(EVENT_QUEUE_END);
+ }
+ }
+
+ public int getEventSentCount() {
+ return mEventCount.get();
+ }
+
+ /**
+ * Utility for handlers or activities to sends a string event to the emulator.
+ * This method is safe for the activity to call from any thread, including the UI thread.
+ *
+ * @param msg Event message. Must not be null.
+ */
+ public void sendEventToEmulator(String msg) {
+ try {
+ mEventQueue.put(msg);
+ } catch (InterruptedException e) {
+ Log.e(TAG, "EventQueue.put", e);
+ }
+ }
// ------------
// Interaction from the emulator connection towards the handler
@@ -103,51 +216,61 @@ public abstract class BaseHandler { // Interaction from handler towards listening UI
/**
- * Interface to be implemented by activities that use this handler.
- * This is used by the handler to send event data to any UI.
+ * Indicates whether the given UI handler is already registered with the handler.
+ *
+ * @param uiHandler The UI handler.
+ * @return True if the UI handler is not null and already registered.
*/
- public interface UiListener {
- public void onHandlerEvent(int event, Object...params);
+ public boolean hasUiHandler(android.os.Handler uiHandler) {
+ return uiHandler != null && mUiHandlers.contains(uiHandler);
}
- private final List<UiListener> mUiListeners = new ArrayList<UiListener>();
-
/**
- * Registers a new UI listener.
+ * Registers a new UI handler.
*
- * @param listener A non-null UI listener to register.
- * Ignored if the listener is null or already registered.
+ * @param uiHandler A non-null UI handler to register.
+ * Ignored if the UI handler is null or already registered.
*/
- public void addUiListener(UiListener listener) {
- assert listener != null;
- if (listener != null) {
- if (!mUiListeners.contains(listener)) {
- mUiListeners.add(listener);
+ public void addUiHandler(android.os.Handler uiHandler) {
+ assert uiHandler != null;
+ if (uiHandler != null) {
+ if (!mUiHandlers.contains(uiHandler)) {
+ mUiHandlers.add(uiHandler);
}
}
}
-
/**
- * Unregisters an UI listener.
+ * Unregisters an UI handler.
*
- * @param listener A non-null UI listener to unregister.
+ * @param uiHandler A non-null UI listener to unregister.
* Ignored if the listener is null or already registered.
*/
- public void removeUiListener(UiListener listener) {
- assert listener != null;
- mUiListeners.remove(listener);
+ public void removeUiHandler(android.os.Handler uiHandler) {
+ assert uiHandler != null;
+ mUiHandlers.remove(uiHandler);
+ }
+
+ /**
+ * Protected method to be used by handlers to send an event to all UI handlers.
+ *
+ * @param event An integer event code with no specific parameters.
+ * To be defined by the handler itself.
+ */
+ protected void notifyUiHandlers(int event) {
+ for (android.os.Handler uiHandler : mUiHandlers) {
+ uiHandler.sendEmptyMessage(event);
+ }
}
/**
- * Protected method to be used by handlers to send an event to any listening UI.
+ * Protected method to be used by handlers to send an event to all UI handlers.
*
- * @param event The event code. To be defined by the handler itself.
- * @param params Any parameters that the handler defines for this event.
+ * @param msg An event with parameters. To be defined by the handler itself.
*/
- protected void notifyUi(int event, Object...params) {
- for (UiListener listener : mUiListeners) {
- listener.onHandlerEvent(event, params);
+ protected void notifyUiHandlers(Message msg) {
+ for (android.os.Handler uiHandler : mUiHandlers) {
+ uiHandler.sendMessage(msg);
}
}
diff --git a/apps/SdkController/SdkControllerApp/src/com/android/tools/sdkcontroller/handlers/MultiTouchHandler.java b/apps/SdkController/SdkControllerApp/src/com/android/tools/sdkcontroller/handlers/MultiTouchHandler.java new file mode 100755 index 0000000..6f64485 --- /dev/null +++ b/apps/SdkController/SdkControllerApp/src/com/android/tools/sdkcontroller/handlers/MultiTouchHandler.java @@ -0,0 +1,121 @@ +/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed 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.android.tools.sdkcontroller.handlers;
+
+import android.content.Context;
+import android.graphics.Point;
+import android.os.Message;
+import android.util.Log;
+
+import com.android.tools.sdkcontroller.lib.EmulatorConnection;
+
+
+public class MultiTouchHandler extends BaseHandler {
+
+ @SuppressWarnings("hiding")
+ private static final String TAG = MultiTouchHandler.class.getSimpleName();
+ /**
+ * A new frame buffer has been received from the emulator.
+ * Parameter {@code obj} is a {@code byte[] array} containing the screen data.
+ */
+ public static final int EVENT_FRAME_BUFFER = 1;
+ /**
+ * A multi-touch "start" command has been received from the emulator.
+ * Parameter {@code obj} is the string parameter from the start command.
+ */
+ public static final int EVENT_MT_START = 2;
+ /**
+ * A multi-touch "stop" command has been received from the emulator.
+ * There is no {@code obj} parameter associated.
+ */
+ public static final int EVENT_MT_STOP = 3;
+
+ private static final Point mViewSize = new Point(0, 0);
+
+ public MultiTouchHandler() {
+ super(HandlerType.MultiTouch, EmulatorConnection.MULTITOUCH_PORT);
+ }
+
+ public void setViewSize(int width, int height) {
+ mViewSize.set(width, height);
+ }
+
+ @Override
+ public void onStart(EmulatorConnection connection, Context context) {
+ super.onStart(connection, context);
+ }
+
+ @Override
+ public void onStop() {
+ super.onStop();
+ }
+
+ /**
+ * Called when a query is received from the emulator. NOTE: This method is
+ * called from the I/O loop.
+ *
+ * @param query Name of the query received from the emulator. The allowed
+ * queries are: - 'start' - Starts delivering touch screen events
+ * to the emulator. - 'stop' - Stops delivering touch screen
+ * events to the emulator.
+ * @param param Query parameters.
+ * @return Zero-terminated reply string. String must be formatted as such:
+ * "ok|ko[:reply data]"
+ */
+ @Override
+ public String onEmulatorQuery(String query, String param) {
+ if (query.contentEquals("start")) {
+ Message msg = Message.obtain();
+ msg.what = EVENT_MT_START;
+ msg.obj = param;
+ notifyUiHandlers(msg);
+ return "ok:" + mViewSize.x + "x" + mViewSize.y + "\0";
+
+ } else if (query.contentEquals("stop")) {
+ notifyUiHandlers(EVENT_MT_STOP);
+ return "ok\0";
+
+ } else {
+ Log.e(TAG, "Unknown query " + query + "(" + param + ")");
+ return "ko:Unknown query\0";
+ }
+ }
+
+ /**
+ * Called when a BLOB query is received from the emulator.
+ * <p/>
+ * This query is used to deliver framebuffer updates in the emulator. The
+ * blob contains an update header, followed by the bitmap containing updated
+ * rectangle. The header is defined as MTFrameHeader structure in
+ * external/qemu/android/multitouch-port.h
+ * <p/>
+ * NOTE: This method is called from the I/O loop, so all communication with
+ * the emulator will be "on hold" until this method returns.
+ *
+ * @param array contains BLOB data for the query.
+ * @return Empty string: this query doesn't require any response.
+ */
+ @Override
+ public String onEmulatorBlobQuery(byte[] array) {
+ Message msg = Message.obtain();
+ msg.what = EVENT_FRAME_BUFFER;
+ msg.obj = array;
+ notifyUiHandlers(msg);
+ return "";
+ }
+
+}
diff --git a/apps/SdkController/SdkControllerApp/src/com/android/tools/sdkcontroller/handlers/MultitouchHandler.java b/apps/SdkController/SdkControllerApp/src/com/android/tools/sdkcontroller/handlers/MultitouchHandler.java deleted file mode 100755 index a6032c9..0000000 --- a/apps/SdkController/SdkControllerApp/src/com/android/tools/sdkcontroller/handlers/MultitouchHandler.java +++ /dev/null @@ -1,60 +0,0 @@ -/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed 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.android.tools.sdkcontroller.handlers;
-
-import android.content.Context;
-
-import com.android.tools.sdkcontroller.lib.EmulatorConnection;
-
-
-public class MultitouchHandler extends BaseHandler {
-
- @Override
- public HandlerType getType() {
- return HandlerType.MultiTouch;
- }
-
- @Override
- public int getPort() {
- return EmulatorConnection.MULTITOUCH_PORT;
- }
-
- @Override
- public void onStart(EmulatorConnection connection, Context context) {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void onStop() {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public String onEmulatorQuery(String query, String param) {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public String onEmulatorBlobQuery(byte[] array) {
- // TODO Auto-generated method stub
- return null;
- }
-
-}
diff --git a/apps/SdkController/SdkControllerApp/src/com/android/tools/sdkcontroller/handlers/SensorsHandler.java b/apps/SdkController/SdkControllerApp/src/com/android/tools/sdkcontroller/handlers/SensorsHandler.java index d093e04..f23e38a 100755 --- a/apps/SdkController/SdkControllerApp/src/com/android/tools/sdkcontroller/handlers/SensorsHandler.java +++ b/apps/SdkController/SdkControllerApp/src/com/android/tools/sdkcontroller/handlers/SensorsHandler.java @@ -18,15 +18,13 @@ package com.android.tools.sdkcontroller.handlers; import java.util.ArrayList;
import java.util.List;
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.atomic.AtomicInteger;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
+import android.os.Message;
import android.util.Log;
import com.android.tools.sdkcontroller.lib.EmulatorConnection;
@@ -34,41 +32,28 @@ import com.android.tools.sdkcontroller.lib.EmulatorConnection; public class SensorsHandler extends BaseHandler {
+ @SuppressWarnings("hiding")
private static String TAG = SensorsHandler.class.getSimpleName();
+ @SuppressWarnings("hiding")
private static boolean DEBUG = true;
- private static String EVENT_QUEUE_END = "@end@";
/**
* Sensor "enabled by emulator" state has changed.
- * Parameters are [0]=MonitoredSensor, [1]=Boolean isEnabledByEmulator.
+ * Parameter {@code obj} is the {@link MonitoredSensor}.
*/
public static final int SENSOR_STATE_CHANGED = 1;
/**
* Sensor display value has changed.
- * Parameters are [0]=MonitoredSensor, [1]=String value
+ * Parameter {@code obj} is the {@link MonitoredSensor}.
*/
public static final int SENSOR_DISPLAY_MODIFIED = 2;
/** Array containing monitored sensors. */
private final List<MonitoredSensor> mSensors = new ArrayList<MonitoredSensor>();
- private EmulatorConnection mConnection;
private SensorManager mSenMan;
- private final AtomicInteger mEventCount = new AtomicInteger(0);
- private volatile boolean mRunEventQueue = true;
- private final BlockingQueue<String> mEventQueue = new LinkedBlockingQueue<String>();
-
public SensorsHandler() {
- }
-
- @Override
- public HandlerType getType() {
- return HandlerType.Sensor;
- }
-
- @Override
- public int getPort() {
- return EmulatorConnection.SENSORS_PORT;
+ super(HandlerType.Sensor, EmulatorConnection.SENSORS_PORT);
}
/**
@@ -81,16 +66,9 @@ public class SensorsHandler extends BaseHandler { return mSensors;
}
- public int getEventSentCount() {
- return mEventCount.get();
- }
-
@Override
public void onStart(EmulatorConnection connection, Context context) {
- assert connection != null;
- mConnection = connection;
- mRunEventQueue = true;
- mEventThread.start();
+ super.onStart(connection, context);
// Iterate through the available sensors, adding them to the array.
SensorManager sm = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
@@ -119,12 +97,7 @@ public class SensorsHandler extends BaseHandler { @Override
public void onStop() {
stopSensors();
- // Stop the message queue
- mConnection = null;
- if (mRunEventQueue) {
- mRunEventQueue = false;
- mEventQueue.offer(EVENT_QUEUE_END);
- }
+ super.onStop();
}
/**
@@ -275,38 +248,6 @@ public class SensorsHandler extends BaseHandler { * Internals
**************************************************************************/
- private final Thread mEventThread = new Thread(new Runnable() {
- @Override
- public void run() {
- if (DEBUG) Log.d(TAG, "EventThread.started");
- while(mRunEventQueue) {
- try {
- String msg = mEventQueue.take();
- if (msg != null && mConnection != null && !msg.equals(EVENT_QUEUE_END)) {
- mConnection.sendNotification(msg);
- mEventCount.incrementAndGet();
- }
- } catch (InterruptedException e) {
- Log.e(TAG, "EventThread", e);
- }
- }
- if (DEBUG) Log.d(TAG, "EventThread.terminate");
- }
- }, "eventThread");
-
- /**
- * Sends sensor's event to the emulator.
- *
- * @param msg Sensor's event message.
- */
- private void sendSensorEvent(String msg) {
- try {
- mEventQueue.put(msg);
- } catch (InterruptedException e) {
- Log.e(TAG, "NotifQueue.put", e);
- }
- }
-
/**
* Start listening to all monitored sensors.
*/
@@ -570,7 +511,11 @@ public class SensorsHandler extends BaseHandler { if (DEBUG) Log.d(TAG, ">>> Sensor " + getEmulatorFriendlyName() + " is enabled.");
mEnabledByEmulator = true;
mValue = "";
- notifyUi(SENSOR_STATE_CHANGED, this, mEnabledByEmulator);
+
+ Message msg = Message.obtain();
+ msg.what = SENSOR_STATE_CHANGED;
+ msg.obj = this;
+ notifyUiHandlers(msg);
}
/**
@@ -578,10 +523,14 @@ public class SensorsHandler extends BaseHandler { * the UI thread.
*/
private void disableSensor() {
- Log.e(TAG, "<<< Sensor " + getEmulatorFriendlyName() + " is disabled.");
+ if (DEBUG) Log.w(TAG, "<<< Sensor " + getEmulatorFriendlyName() + " is disabled.");
mEnabledByEmulator = false;
mValue = "Disabled by emulator";
- notifyUi(SENSOR_STATE_CHANGED, this, mEnabledByEmulator);
+
+ Message msg = Message.obtain();
+ msg.what = SENSOR_STATE_CHANGED;
+ msg.obj = this;
+ notifyUiHandlers(msg);
}
private class OurSensorEventListener implements SensorEventListener {
@@ -594,26 +543,29 @@ public class SensorsHandler extends BaseHandler { // Display current sensor value, and format message that will be
// sent to the emulator.
final int nArgs = event.values.length;
- String msg;
+ String str;
String val;
if (nArgs == 3) {
val = String.format(mTextFmt, event.values[0], event.values[1],event.values[2]);
- msg = String.format(mMsgFmt, event.values[0], event.values[1], event.values[2]);
+ str = String.format(mMsgFmt, event.values[0], event.values[1], event.values[2]);
} else if (nArgs == 2) {
val = String.format(mTextFmt, event.values[0], event.values[1]);
- msg = String.format(mMsgFmt, event.values[0], event.values[1]);
+ str = String.format(mMsgFmt, event.values[0], event.values[1]);
} else if (nArgs == 1) {
val = String.format(mTextFmt, event.values[0]);
- msg = String.format(mMsgFmt, event.values[0]);
+ str = String.format(mMsgFmt, event.values[0]);
} else {
Log.e(TAG, "Unexpected number of values " + event.values.length
+ " in onSensorChanged for sensor " + mSensor.getName());
return;
}
mValue = val;
- sendSensorEvent(msg);
+ sendEventToEmulator(str);
- notifyUi(SENSOR_DISPLAY_MODIFIED, this, val);
+ Message msg = Message.obtain();
+ msg.what = SENSOR_DISPLAY_MODIFIED;
+ msg.obj = this;
+ notifyUiHandlers(msg);
}
/**
|