aboutsummaryrefslogtreecommitdiffstats
path: root/apps
diff options
context:
space:
mode:
authorRaphael <raphael@google.com>2012-03-23 17:00:32 -0700
committerRaphael <raphael@google.com>2012-03-24 16:34:07 -0700
commit4719543b607f8169d65aed677d216291622f2d8c (patch)
tree5ce8f0b9b909f52cf371435c8f472396bab6ba91 /apps
parent630a91ea9631a33778037528200d77d49828404e (diff)
downloadsdk-4719543b607f8169d65aed677d216291622f2d8c.zip
sdk-4719543b607f8169d65aed677d216291622f2d8c.tar.gz
sdk-4719543b607f8169d65aed677d216291622f2d8c.tar.bz2
SdkController: limit sensor update rate.
This adds a sample rate field in the sensor activity. The sensor handler uses that to limit the updates sent to the emulator -- simply discard updates that come in too fast. Change-Id: Ia4ae2e71eda4ed844ddc9b8b0657df2306e03674
Diffstat (limited to 'apps')
-rwxr-xr-xapps/SdkController/SdkControllerApp/AndroidManifest.xml7
-rwxr-xr-xapps/SdkController/SdkControllerApp/res/layout/main.xml2
-rwxr-xr-xapps/SdkController/SdkControllerApp/res/layout/sensors.xml68
-rwxr-xr-xapps/SdkController/SdkControllerApp/res/values/strings.xml4
-rwxr-xr-xapps/SdkController/SdkControllerApp/src/com/android/tools/sdkcontroller/activities/SensorActivity.java67
-rwxr-xr-xapps/SdkController/SdkControllerApp/src/com/android/tools/sdkcontroller/handlers/SensorsHandler.java150
6 files changed, 219 insertions, 79 deletions
diff --git a/apps/SdkController/SdkControllerApp/AndroidManifest.xml b/apps/SdkController/SdkControllerApp/AndroidManifest.xml
index 6d690cd..dda070f 100755
--- a/apps/SdkController/SdkControllerApp/AndroidManifest.xml
+++ b/apps/SdkController/SdkControllerApp/AndroidManifest.xml
@@ -26,12 +26,15 @@
<activity
android:name=".activities.SensorActivity"
- android:launchMode="singleInstance" />
+ android:launchMode="singleInstance"
+ android:windowSoftInputMode="stateUnchanged"/>
<activity
android:name=".activities.MultiTouchActivity"
android:launchMode="singleInstance"
- android:screenOrientation="portrait" android:theme="@style/Theme.MultiTouch"/>
+ android:screenOrientation="portrait"
+ android:theme="@style/Theme.MultiTouch"
+ android:windowSoftInputMode="stateHidden"/>
<service
android:name=".service.ControllerService"
diff --git a/apps/SdkController/SdkControllerApp/res/layout/main.xml b/apps/SdkController/SdkControllerApp/res/layout/main.xml
index cee7b14..90faa67 100755
--- a/apps/SdkController/SdkControllerApp/res/layout/main.xml
+++ b/apps/SdkController/SdkControllerApp/res/layout/main.xml
@@ -34,7 +34,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
- android:layout_below="@+id/textIntro" />
+ />
<TextView
android:id="@+id/labelService"
diff --git a/apps/SdkController/SdkControllerApp/res/layout/sensors.xml b/apps/SdkController/SdkControllerApp/res/layout/sensors.xml
index b724aa4..ca48af5 100755
--- a/apps/SdkController/SdkControllerApp/res/layout/sensors.xml
+++ b/apps/SdkController/SdkControllerApp/res/layout/sensors.xml
@@ -20,11 +20,77 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
- android:orientation="vertical" >
+ android:orientation="vertical" xmlns:tools="http://schemas.android.com/tools">
+
+ <TableLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ >
+
+ <TableRow
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" >
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/sensors_sample_rate"
+ android:gravity="right"
+ android:layout_marginRight="8dp"
+ />
+
+ <EditText
+ android:id="@+id/textSampleRate"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:ems="4"
+ android:gravity="right"
+ android:imeOptions="actionNone|flagNoExtractUi|flagNoFullscreen|"
+ android:inputType="number"
+ android:text="50"
+ tools:ignore="HardcodedText" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/sensors_hz_per_sensor" />
+
+ </TableRow>
+
+ <TableRow
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" >
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:gravity="right"
+ android:layout_marginRight="8dp"
+ android:text="@string/sensors_actual_rate" />
+
+ <TextView
+ android:id="@+id/textActualRate"
+ android:gravity="right"
+ android:text="--"
+ tools:ignore="HardcodedText"
+ android:paddingLeft="8dp"
+ android:paddingRight="8dp"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/sensors_hz_average" />
+
+ </TableRow>
+
+ </TableLayout>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
+ android:layout_marginTop="16dp"
android:text="@string/sensors_top_description" />
<ScrollView
diff --git a/apps/SdkController/SdkControllerApp/res/values/strings.xml b/apps/SdkController/SdkControllerApp/res/values/strings.xml
index 2aad7ba..c76e95f 100755
--- a/apps/SdkController/SdkControllerApp/res/values/strings.xml
+++ b/apps/SdkController/SdkControllerApp/res/values/strings.xml
@@ -36,5 +36,9 @@
<string name="main_service_status_connected">Emulator Connected</string>
<string name="main_service_status_disconnected">Emulator Connected</string>
<string name="sensors_top_description">Available Sensors:</string>
+ <string name="sensors_sample_rate">Sample Rate</string>
+ <string name="sensors_hz_per_sensor">Hz per sensor</string>
+ <string name="sensors_actual_rate">Actual</string>
+ <string name="sensors_hz_average">Hz average</string>
</resources>
diff --git a/apps/SdkController/SdkControllerApp/src/com/android/tools/sdkcontroller/activities/SensorActivity.java b/apps/SdkController/SdkControllerApp/src/com/android/tools/sdkcontroller/activities/SensorActivity.java
index abd91f0..df92611 100755
--- a/apps/SdkController/SdkControllerApp/src/com/android/tools/sdkcontroller/activities/SensorActivity.java
+++ b/apps/SdkController/SdkControllerApp/src/com/android/tools/sdkcontroller/activities/SensorActivity.java
@@ -23,8 +23,11 @@ import java.util.Map;
import android.os.Bundle;
import android.os.Message;
import android.util.Log;
+import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
+import android.view.View.OnFocusChangeListener;
+import android.view.View.OnKeyListener;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.TableLayout;
@@ -51,14 +54,20 @@ public class SensorActivity extends BaseBindingActivity
public static String TAG = SensorActivity.class.getSimpleName();
private static boolean DEBUG = true;
+ private static final int MSG_UPDATE_ACTUAL_HZ = 0x31415;
+
private TableLayout mTableLayout;
private TextView mTextError;
private TextView mTextStatus;
+ private TextView mTextTargetHz;
+ private TextView mTextActualHz;
private SensorsHandler mSensorHandler;
private final Map<MonitoredSensor, DisplayInfo> mDisplayedSensors =
new HashMap<SensorsHandler.MonitoredSensor, SensorActivity.DisplayInfo>();
private final android.os.Handler mUiHandler = new android.os.Handler(this);
+ private int mTargetSampleRate;
+ private long mLastActualUpdateMs;
/** Called when the activity is first created. */
@Override
@@ -68,7 +77,23 @@ public class SensorActivity extends BaseBindingActivity
mTableLayout = (TableLayout) findViewById(R.id.tableLayout);
mTextError = (TextView) findViewById(R.id.textError);
mTextStatus = (TextView) findViewById(R.id.textStatus);
+ mTextTargetHz = (TextView) findViewById(R.id.textSampleRate);
+ mTextActualHz = (TextView) findViewById(R.id.textActualRate);
updateStatus("Waiting for connection");
+
+ mTextTargetHz.setOnKeyListener(new OnKeyListener() {
+ @Override
+ public boolean onKey(View v, int keyCode, KeyEvent event) {
+ updateSampleRate();
+ return false;
+ }
+ });
+ mTextTargetHz.setOnFocusChangeListener(new OnFocusChangeListener() {
+ @Override
+ public void onFocusChange(View v, boolean hasFocus) {
+ updateSampleRate();
+ }
+ });
}
@Override
@@ -151,6 +176,7 @@ public class SensorActivity extends BaseBindingActivity
mSensorHandler = (SensorsHandler) getServiceBinder().getHandler(HandlerType.Sensor);
if (mSensorHandler != null) {
mSensorHandler.addUiHandler(mUiHandler);
+ mUiHandler.sendEmptyMessage(MSG_UPDATE_ACTUAL_HZ);
assert mDisplayedSensors.isEmpty();
List<MonitoredSensor> sensors = mSensorHandler.getSensors();
@@ -248,8 +274,29 @@ public class SensorActivity extends BaseBindingActivity
}
if (mSensorHandler != null) {
updateStatus(Integer.toString(mSensorHandler.getEventSentCount()) + " events sent");
+
+ // Update the "actual rate" field if the value has changed
+ long ms = mSensorHandler.getActualUpdateMs();
+ if (ms != mLastActualUpdateMs) {
+ mLastActualUpdateMs = ms;
+ String hz = mLastActualUpdateMs <= 0 ? "--" :
+ Integer.toString((int) Math.ceil(1000. / ms));
+ mTextActualHz.setText(hz);
+ }
}
break;
+ case MSG_UPDATE_ACTUAL_HZ:
+ if (mSensorHandler != null) {
+ // Update the "actual rate" field if the value has changed
+ long ms = mSensorHandler.getActualUpdateMs();
+ if (ms != mLastActualUpdateMs) {
+ mLastActualUpdateMs = ms;
+ String hz = mLastActualUpdateMs <= 0 ? "--" :
+ Integer.toString((int) Math.ceil(1000. / ms));
+ mTextActualHz.setText(hz);
+ }
+ mUiHandler.sendEmptyMessageDelayed(MSG_UPDATE_ACTUAL_HZ, 1000 /*1s*/);
+ }
}
return true; // we consumed this message
}
@@ -269,4 +316,24 @@ public class SensorActivity extends BaseBindingActivity
mTextError.setVisibility(error.length() == 0 ? View.GONE : View.VISIBLE);
mTextError.setText(error);
}
+
+ private void updateSampleRate() {
+ String str = mTextTargetHz.getText().toString();
+ try {
+ int hz = Integer.parseInt(str.trim());
+
+ // Cap the value. 50 Hz is a reasonable value for the emulator.
+ // Allow a bit more since modern hardware can do it.
+ if (hz <= 0 || hz > 100) {
+ hz = 100;
+ }
+
+ if (hz != mTargetSampleRate) {
+ mTargetSampleRate = hz;
+ if (mSensorHandler != null) {
+ mSensorHandler.setUpdateTargetMs(hz <= 0 ? 0 : (int)(1000.0f / hz));
+ }
+ }
+ } catch (Exception ignore) {}
+ }
}
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 4326562..942b605 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
@@ -37,7 +37,13 @@ public class SensorsHandler extends BaseHandler {
private static String TAG = SensorsHandler.class.getSimpleName();
@SuppressWarnings("hiding")
private static boolean DEBUG = true;
- private static boolean VERBOSE_TIMING = false;
+ /**
+ * The minimum update time per sensor. Ignored if 0 or negative.
+ * Sensor updates that arrive faster than this delay are ignored.
+ */
+ private long mUpdateTargetMs = 1000/50; // 50 fps in milliseconds
+ private long mGlobalAvgUpdateMs = 0;
+
/**
* Sensor "enabled by emulator" state has changed.
@@ -68,6 +74,28 @@ public class SensorsHandler extends BaseHandler {
return mSensors;
}
+ /**
+ * Set the target update delay throttling per-sensor, in milliseconds.
+ * <p/>
+ * For example setting it to 1000/50 means that updates for a <em>given</em> sensor
+ * faster than 50 fps is discarded.
+ *
+ * @param updateTargetMs 0 to disable throttling, otherwise a > 0 millisecond minimum
+ * between sensor updates.
+ */
+ public void setUpdateTargetMs(long updateTargetMs) {
+ mUpdateTargetMs = updateTargetMs;
+ }
+
+ /**
+ * Returns the actual average time in milliseconds between same-sensor updates.
+ *
+ * @return The actual average time in milliseconds between same-sensor updates or 0.
+ */
+ public long getActualUpdateMs() {
+ return mGlobalAvgUpdateMs;
+ }
+
@Override
public void onStart(EmulatorConnection connection, Context context) {
super.onStart(connection, context);
@@ -503,19 +531,19 @@ public class SensorsHandler extends BaseHandler {
}
/**
- * Starts monitoring the sensor. NOTE: This method is called from
- * outside of the UI thread.
+ * Starts monitoring the sensor.
+ * NOTE: This method is called from outside of the UI thread.
*/
private void startListening() {
if (mEnabledByEmulator && mEnabledByUser) {
if (DEBUG) Log.d(TAG, "+++ Sensor " + getEmulatorFriendlyName() + " is started.");
- mSenMan.registerListener(mListener, mSensor, SensorManager.SENSOR_DELAY_NORMAL);
+ mSenMan.registerListener(mListener, mSensor, SensorManager.SENSOR_DELAY_FASTEST);
}
}
/**
- * Stops monitoring the sensor. NOTE: This method is called from outside
- * of the UI thread.
+ * Stops monitoring the sensor.
+ * NOTE: This method is called from outside of the UI thread.
*/
private void stopListening() {
if (DEBUG) Log.d(TAG, "--- Sensor " + getEmulatorFriendlyName() + " is stopped.");
@@ -523,8 +551,8 @@ public class SensorsHandler extends BaseHandler {
}
/**
- * Enables sensor events. NOTE: This method is called from outside of
- * the UI thread.
+ * Enables sensor events.
+ * NOTE: This method is called from outside of the UI thread.
*/
private void enableSensor() {
if (DEBUG) Log.d(TAG, ">>> Sensor " + getEmulatorFriendlyName() + " is enabled.");
@@ -539,8 +567,8 @@ public class SensorsHandler extends BaseHandler {
}
/**
- * Disables sensor events. NOTE: This method is called from outside of
- * the UI thread.
+ * Disables sensor events.
+ * NOTE: This method is called from outside of the UI thread.
*/
private void disableSensor() {
if (DEBUG) Log.w(TAG, "<<< Sensor " + getEmulatorFriendlyName() + " is disabled.");
@@ -554,17 +582,30 @@ public class SensorsHandler extends BaseHandler {
}
private class OurSensorEventListener implements SensorEventListener {
+ /** Last update's time-stamp in local thread millisecond time. */
+ private long mLastUpdateTS;
+ /** Last display update time-stamp. */
+ private long mLastDisplayTS;
+
/**
- * Handles "sensor changed" event. This is an implementation of the
- * SensorEventListener interface.
+ * Handles "sensor changed" event.
+ * This is an implementation of the SensorEventListener interface.
*/
@Override
public void onSensorChanged(SensorEvent event) {
- mSensorCount++;
long now = SystemClock.currentThreadTimeMillis(); //.elapsedRealtime();
- // Display current sensor value, and format message that will be
- // sent to the emulator.
+ long nowDiff = 0;
+ if (mLastUpdateTS != 0) {
+ nowDiff = now - mLastUpdateTS;
+ Log.d(TAG, String.format("%d < %d < %d-- %s", mUpdateTargetMs, nowDiff, mGlobalAvgUpdateMs, mSensor.getName() ));
+ if (mUpdateTargetMs > 0 && nowDiff < mUpdateTargetMs) {
+ // New sample is arriving too fast. Discard it.
+ return;
+ }
+ }
+
+ // Format message that will be sent to the emulator.
float[] values = event.values;
final int len = values.length;
String str;
@@ -581,10 +622,27 @@ public class SensorsHandler extends BaseHandler {
}
sendEventToEmulator(str);
- long now1 = SystemClock.currentThreadTimeMillis();
+ // Computes average update time for this sensor and average globally.
+ if (mLastUpdateTS != 0) {
+ if (mGlobalAvgUpdateMs != 0) {
+ mGlobalAvgUpdateMs = (mGlobalAvgUpdateMs + nowDiff) / 2;
+ } else {
+ mGlobalAvgUpdateMs = nowDiff;
+ }
+ }
+ mLastUpdateTS = now;
+ // Update the UI for the sensor, with a static throttling of 10 fps max.
if (hasUiHandler()) {
- // TODO reduce the UI update rate. 2~4 fps would be just good enough.
+ if (mLastDisplayTS != 0) {
+ nowDiff = now - mLastDisplayTS;
+ if (nowDiff < 100 /*ms, 10fps*/) {
+ // Skip this UI update
+ return;
+ }
+ }
+ mLastDisplayTS = now;
+
mNbValues = len;
mValues[0] = values[0];
if (len > 1) {
@@ -600,53 +658,6 @@ public class SensorsHandler extends BaseHandler {
msg.obj = MonitoredSensor.this;
notifyUiHandlers(msg);
}
-
- if (VERBOSE_TIMING) {
- // Computes average update time for this sensor or globally.
- // Also computes the average time spend formatting sensor values.
- // average call times between "now"
- if (mGlobalLastNowTS != 0) {
- long nowDiff = now - mGlobalLastNowTS;
- mGlobalLastNowTS = now;
- if (mGlobalAvgNowMs != 0) {
- mGlobalAvgNowMs = (mGlobalAvgNowMs + nowDiff) / 2;
- } else {
- mGlobalAvgNowMs = nowDiff;
- }
- } else {
- mGlobalLastNowTS = now;
- }
-
- if (mLastNowTS != 0) {
- long nowDiff = now - mLastNowTS;
- mLastNowTS = now;
- if (mAvgNowMs != 0) {
- mAvgNowMs = (mAvgNowMs + nowDiff) / 2;
- } else {
- mAvgNowMs = nowDiff;
- }
-
- // average now to now1 time (time to format string)
- nowDiff = now1 - now;
- if (mAvgNow1Ms != 0) {
- mAvgNow1Ms = (mAvgNow1Ms + nowDiff) / 2;
- } else {
- mAvgNow1Ms = nowDiff;
- }
-
- // Display timing stats
- String d = String.format("G:%3d [%d L:%3d ms F:%3d +E:%3d ms] %s",
- mGlobalAvgNowMs, // average millis between global sensor updates
- mSensorCount, // update count for this sensor
- mAvgNowMs, // average milis between updates for this sensor
- mAvgNow1Ms, // average millis for string.format + emu send
- mSensor.getName());
- Log.d(TAG, d);
-
- } else {
- mLastNowTS = now;
- }
- } // VERBOSE_TIMING
}
/**
@@ -656,18 +667,7 @@ public class SensorsHandler extends BaseHandler {
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
-
- // Debug: Per-sensor variables used for verbose timing. see VERBOSE_TIMING
- private int mSensorCount;
- private long mLastNowTS;
- private long mAvgNowMs;
- private long mAvgNow1Ms;
-
}
} // MonitoredSensor
- // Debug: Global variables used for verbose timing. see VERBOSE_TIMING
- private long mGlobalLastNowTS;
- private long mGlobalAvgNowMs;
-
}