aboutsummaryrefslogtreecommitdiff
path: root/sensors
diff options
context:
space:
mode:
authorJan-Felix Schmakeit <jfschmakeit@google.com>2014-01-02 11:41:04 +1100
committerAlexander Lucas <alexlucas@google.com>2014-02-06 17:23:07 +0000
commit56216a861a0910fb7d4317be4a6c1b43697ebe09 (patch)
tree2ee6139c3ea29732421956546f4e3f316dabd7fe /sensors
parent2fa6e8d98412b6a91420ca217ef99d527d720417 (diff)
downloadandroid-56216a861a0910fb7d4317be4a6c1b43697ebe09.tar.gz
Add a sample showing the use of the step sensors
(STEP_DETECTOR and STEP_COUNTER) and sensor event batching. Change-Id: Ied3a2601b09b12a53ddbe709b959776ca9e87c3c (cherry picked from commit 501ae9a1d88ba4b5c877f4218b75630271c71e3c)
Diffstat (limited to 'sensors')
-rw-r--r--sensors/BatchStepSensor/BatchStepSensorSample/README-CardStream.txt82
-rw-r--r--sensors/BatchStepSensor/BatchStepSensorSample/src/main/AndroidManifest.xml51
-rw-r--r--sensors/BatchStepSensor/BatchStepSensorSample/src/main/java/com/example/android/batchstepsensor/BatchStepSensorFragment.java588
-rw-r--r--sensors/BatchStepSensor/BatchStepSensorSample/src/main/res/drawable-hdpi/ic_launcher.pngbin0 -> 4402 bytes
-rw-r--r--sensors/BatchStepSensor/BatchStepSensorSample/src/main/res/drawable-mdpi/ic_launcher.pngbin0 -> 2641 bytes
-rw-r--r--sensors/BatchStepSensor/BatchStepSensorSample/src/main/res/drawable-xhdpi/ic_launcher.pngbin0 -> 6076 bytes
-rw-r--r--sensors/BatchStepSensor/BatchStepSensorSample/src/main/res/drawable-xxhdpi/ic_launcher.pngbin0 -> 11109 bytes
-rw-r--r--sensors/BatchStepSensor/BatchStepSensorSample/src/main/res/values/strings.xml75
-rw-r--r--sensors/BatchStepSensor/build.gradle14
-rw-r--r--sensors/BatchStepSensor/buildSrc/build.gradle18
-rw-r--r--sensors/BatchStepSensor/gradle/wrapper/gradle-wrapper.jarbin0 -> 49896 bytes
-rw-r--r--sensors/BatchStepSensor/gradle/wrapper/gradle-wrapper.properties6
-rwxr-xr-xsensors/BatchStepSensor/gradlew164
-rw-r--r--sensors/BatchStepSensor/gradlew.bat90
-rw-r--r--sensors/BatchStepSensor/settings.gradle4
-rw-r--r--sensors/BatchStepSensor/template-params.xml53
16 files changed, 1145 insertions, 0 deletions
diff --git a/sensors/BatchStepSensor/BatchStepSensorSample/README-CardStream.txt b/sensors/BatchStepSensor/BatchStepSensorSample/README-CardStream.txt
new file mode 100644
index 00000000..957ccd65
--- /dev/null
+++ b/sensors/BatchStepSensor/BatchStepSensorSample/README-CardStream.txt
@@ -0,0 +1,82 @@
+<#--
+ Copyright 2013 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.
+-->
+
+Steps to implement CardStream template:
+-in template-params.xml.ftl:
+ -add the following templates
+ <template src="base"/>
+ <template src="CardStream"/>
+ -add the following line to common imports
+ <common src="activities"/>
+ <common src="logger"/>
+
+-Add a Fragment to handle behavior. In your MainActivity.java class, it will reference a Fragment
+ called (yourProjectName)Fragment.java. Create that file in your project, using the "main" source
+ folder instead of "common" or "templates".
+ For instance, if your package name is com.example.foo, create the file
+ src/main/java/com/example/foo/FooFragment.java
+
+-Now it's time to deal with cards. Implement a method like this in your Fragment to access the CardStream:
+private CardStreamFragment getCardStream() {
+ if (mCards == null) {
+ mCards = ((CardStream) getActivity()).getCardStream();
+ }
+ return mCards;
+}
+
+
+-Create a instance of Card.Builder with a tag String that *must* be unique among all cards.
+
+ Card.Builder builder = new Card.Builder(UNIQUE_TAG_STRING);
+
+-Set the properties for your card in the builder. Some properties (title, description, progress type) can also
+be changed later.
+
+ builder.setTitle(String title)
+
+-Cards can also have more than one action that is shown as a button at the bottom of the card.
+All actions *must* be defined through the builder. They can be hidden or shown later again, but they must be defined
+in the builder before .build() is called.
+
+-To implement an action, use Builder.addAction with a label, id, type (Neutral/Positive/Negative) and
+ a CardActionCallback.
+ Actions can be distinguished by their id to avoid the use of a large number of unnamed callback instances.
+ For convenience, the tag of the card the action belongs to is also returned in the callback.
+
+ builder.addAction(actionLabel1, 0, Card.ACTION_NEUTRAL, new Card.CardActionCallback() {
+ @Override
+ public void onClick(int cardActionId, String tag) {
+ ...
+ }
+ });
+
+
+-After finishing setup process, call Buidler.build() to return a new instance of a Card.
+
+ final Card card = builder.build(activity);
+
+-Inside your MainActivity.java class, call getCardStream() to get the instance of the CardStreamFragment through
+which cards are shown on screen.
+A card needs to be added to the CardStreamFragment first before it can be shown.
+Cards are identified by their unique tag.
+
+ Card myCard = ...
+ getCardStreamFragment().addCard(myCard);
+ getCardStreamFragment().show(myCard.getTag());
+ getCardStreamFragment().hide("MyCardTag");
+ getCardStreamFragment().show("MyCardTag",false); // can't be dismissed by user
+
+
diff --git a/sensors/BatchStepSensor/BatchStepSensorSample/src/main/AndroidManifest.xml b/sensors/BatchStepSensor/BatchStepSensorSample/src/main/AndroidManifest.xml
new file mode 100644
index 00000000..2c4e4f29
--- /dev/null
+++ b/sensors/BatchStepSensor/BatchStepSensorSample/src/main/AndroidManifest.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2014 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.
+-->
+
+
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.example.android.batchstepsensor"
+ android:versionCode="1"
+ android:versionName="1.0">
+
+ <!-- This sample requires at least Android KitKat for sensor batching support -->
+ <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="19" />
+
+ <!-- Require the step counter and step detector sensors.
+ See the method BatchStepSensorFragment#isKitkatWithStepSensor() for a programmatic check if
+ support is optional and the application supports a case where these sensors are not available.
+ -->
+ <uses-feature android:name="android.hardware.sensor.stepcounter" />
+ <uses-feature android:name="android.hardware.sensor.stepdetector" />
+
+
+ <application android:allowBackup="true"
+ android:label="@string/app_name"
+ android:icon="@drawable/ic_launcher"
+ android:theme="@style/AppTheme">
+
+ <activity android:name=".MainActivity"
+ android:label="@string/app_name">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+
+
+</manifest>
diff --git a/sensors/BatchStepSensor/BatchStepSensorSample/src/main/java/com/example/android/batchstepsensor/BatchStepSensorFragment.java b/sensors/BatchStepSensor/BatchStepSensorSample/src/main/java/com/example/android/batchstepsensor/BatchStepSensorFragment.java
new file mode 100644
index 00000000..aab0fc38
--- /dev/null
+++ b/sensors/BatchStepSensor/BatchStepSensorSample/src/main/java/com/example/android/batchstepsensor/BatchStepSensorFragment.java
@@ -0,0 +1,588 @@
+/*
+* Copyright 2014 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.example.android.batchstepsensor;
+
+import android.app.Activity;
+import android.content.pm.PackageManager;
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+
+import com.example.android.common.logger.Log;
+
+public class BatchStepSensorFragment extends Fragment implements OnCardClickListener {
+
+ public static final String TAG = "StepSensorSample";
+ // Cards
+ private CardStreamFragment mCards = null;
+
+ // Card tags
+ public static final String CARD_INTRO = "intro";
+ public static final String CARD_REGISTER_DETECTOR = "register_detector";
+ public static final String CARD_REGISTER_COUNTER = "register_counter";
+ public static final String CARD_BATCHING_DESCRIPTION = "register_batching_description";
+ public static final String CARD_COUNTING = "counting";
+ public static final String CARD_EXPLANATION = "explanation";
+ public static final String CARD_NOBATCHSUPPORT = "error";
+
+ // Actions from REGISTER cards
+ public static final int ACTION_REGISTER_DETECT_NOBATCHING = 10;
+ public static final int ACTION_REGISTER_DETECT_BATCHING_5s = 11;
+ public static final int ACTION_REGISTER_DETECT_BATCHING_10s = 12;
+ public static final int ACTION_REGISTER_COUNT_NOBATCHING = 21;
+ public static final int ACTION_REGISTER_COUNT_BATCHING_5s = 22;
+ public static final int ACTION_REGISTER_COUNT_BATCHING_10s = 23;
+ // Action from COUNTING card
+ public static final int ACTION_UNREGISTER = 1;
+ // Actions from description cards
+ private static final int ACTION_BATCHING_DESCRIPTION_DISMISS = 2;
+ private static final int ACTION_EXPLANATION_DISMISS = 3;
+
+ // State of application, used to register for sensors when app is restored
+ public static final int STATE_OTHER = 0;
+ public static final int STATE_COUNTER = 1;
+ public static final int STATE_DETECTOR = 2;
+
+ // Bundle tags used to store data when restoring application state
+ private static final String BUNDLE_STATE = "state";
+ private static final String BUNDLE_LATENCY = "latency";
+ private static final String BUNDLE_STEPS = "steps";
+
+ // max batch latency is specified in microseconds
+ private static final int BATCH_LATENCY_0 = 0; // no batching
+ private static final int BATCH_LATENCY_10s = 10000000;
+ private static final int BATCH_LATENCY_5s = 5000000;
+
+ /*
+ For illustration we keep track of the last few events and show their delay from when the
+ event occurred until it was received by the event listener.
+ These variables keep track of the list of timestamps and the number of events.
+ */
+ // Number of events to keep in queue and display on card
+ private static final int EVENT_QUEUE_LENGTH = 10;
+ // List of timestamps when sensor events occurred
+ private float[] mEventDelays = new float[EVENT_QUEUE_LENGTH];
+
+ // number of events in event list
+ private int mEventLength = 0;
+ // pointer to next entry in sensor event list
+ private int mEventData = 0;
+
+ // Steps counted in current session
+ private int mSteps = 0;
+ // Value of the step counter sensor when the listener was registered.
+ // (Total steps are calculated from this value.)
+ private int mCounterSteps = 0;
+ // Steps counted by the step counter previously. Used to keep counter consistent across rotation
+ // changes
+ private int mPreviousCounterSteps = 0;
+ // State of the app (STATE_OTHER, STATE_COUNTER or STATE_DETECTOR)
+ private int mState = STATE_OTHER;
+ // When a listener is registered, the batch sensor delay in microseconds
+ private int mMaxDelay = 0;
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ CardStreamFragment stream = getCardStream();
+ if (stream.getVisibleCardCount() < 1) {
+ // No cards are visible, started for the first time
+ // Prepare all cards and show the intro card.
+ initialiseCards();
+ showIntroCard();
+ // Show the registration card if the hardware is supported, show an error otherwise
+ if (isKitkatWithStepSensor()) {
+ showRegisterCard();
+ } else {
+ showErrorCard();
+ }
+ }
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ // BEGIN_INCLUDE(onpause)
+ // Unregister the listener when the application is paused
+ unregisterListeners();
+ // END_INCLUDE(onpause)
+ }
+
+ /**
+ * Returns true if this device is supported. It needs to be running Android KitKat (4.4) or
+ * higher and has a step counter and step detector sensor.
+ * This check is useful when an app provides an alternative implementation or different
+ * functionality if the step sensors are not available or this code runs on a platform version
+ * below Android KitKat. If this functionality is required, then the minSDK parameter should
+ * be specified appropriately in the AndroidManifest.
+ *
+ * @return True iff the device can run this sample
+ */
+ private boolean isKitkatWithStepSensor() {
+ // BEGIN_INCLUDE(iskitkatsensor)
+ // Require at least Android KitKat
+ int currentApiVersion = android.os.Build.VERSION.SDK_INT;
+ // Check that the device supports the step counter and detector sensors
+ PackageManager packageManager = getActivity().getPackageManager();
+ return currentApiVersion >= android.os.Build.VERSION_CODES.KITKAT
+ && packageManager.hasSystemFeature(PackageManager.FEATURE_SENSOR_STEP_COUNTER)
+ && packageManager.hasSystemFeature(PackageManager.FEATURE_SENSOR_STEP_DETECTOR);
+ // END_INCLUDE(iskitkatsensor)
+ }
+
+ /**
+ * Handles a click on a card action.
+ * Registers a SensorEventListener (see {@link #registerEventListener(int, int)}) with the
+ * selected delay, dismisses cards and unregisters the listener
+ * (see {@link #unregisterListeners()}).
+ * Actions are defined when a card is created.
+ *
+ * @param cardActionId
+ * @param cardTag
+ */
+ @Override
+ public void onCardClick(int cardActionId, String cardTag) {
+
+ switch (cardActionId) {
+ // BEGIN_INCLUDE(onclick)
+ // Register Step Counter card
+ case ACTION_REGISTER_COUNT_NOBATCHING:
+ registerEventListener(BATCH_LATENCY_0, Sensor.TYPE_STEP_COUNTER);
+ break;
+ case ACTION_REGISTER_COUNT_BATCHING_5s:
+ registerEventListener(BATCH_LATENCY_5s, Sensor.TYPE_STEP_COUNTER);
+ break;
+ case ACTION_REGISTER_COUNT_BATCHING_10s:
+ registerEventListener(BATCH_LATENCY_10s, Sensor.TYPE_STEP_COUNTER);
+ break;
+
+ // Register Step Detector card
+ case ACTION_REGISTER_DETECT_NOBATCHING:
+ registerEventListener(BATCH_LATENCY_0, Sensor.TYPE_STEP_DETECTOR);
+ break;
+ case ACTION_REGISTER_DETECT_BATCHING_5s:
+ registerEventListener(BATCH_LATENCY_5s, Sensor.TYPE_STEP_DETECTOR);
+ break;
+ case ACTION_REGISTER_DETECT_BATCHING_10s:
+ registerEventListener(BATCH_LATENCY_10s, Sensor.TYPE_STEP_DETECTOR);
+ break;
+
+ // Unregister card
+ case ACTION_UNREGISTER:
+ showRegisterCard();
+ unregisterListeners();
+ // reset the application state when explicitly unregistered
+ mState = STATE_OTHER;
+ break;
+ // END_INCLUDE(onclick)
+ // Explanation cards
+ case ACTION_BATCHING_DESCRIPTION_DISMISS:
+ // permanently remove the batch description card, it will not be shown again
+ getCardStream().removeCard(CARD_BATCHING_DESCRIPTION);
+ break;
+ case ACTION_EXPLANATION_DISMISS:
+ // permanently remove the explanation card, it will not be shown again
+ getCardStream().removeCard(CARD_EXPLANATION);
+ }
+
+ // For register cards, display the counting card
+ if (cardTag.equals(CARD_REGISTER_COUNTER) || cardTag.equals(CARD_REGISTER_DETECTOR)) {
+ showCountingCards();
+ }
+ }
+
+ /**
+ * Register a {@link android.hardware.SensorEventListener} for the sensor and max batch delay.
+ * The maximum batch delay specifies the maximum duration in microseconds for which subsequent
+ * sensor events can be temporarily stored by the sensor before they are delivered to the
+ * registered SensorEventListener. A larger delay allows the system to handle sensor events more
+ * efficiently, allowing the system to switch to a lower power state while the sensor is
+ * capturing events. Once the max delay is reached, all stored events are delivered to the
+ * registered listener. Note that this value only specifies the maximum delay, the listener may
+ * receive events quicker. A delay of 0 disables batch mode and registers the listener in
+ * continuous mode.
+ * The optimium batch delay depends on the application. For example, a delay of 5 seconds or
+ * higher may be appropriate for an application that does not update the UI in real time.
+ *
+ * @param maxdelay
+ * @param sensorType
+ */
+ private void registerEventListener(int maxdelay, int sensorType) {
+ // BEGIN_INCLUDE(register)
+
+ // Keep track of state so that the correct sensor type and batch delay can be set up when
+ // the app is restored (for example on screen rotation).
+ mMaxDelay = maxdelay;
+ if (sensorType == Sensor.TYPE_STEP_COUNTER) {
+ mState = STATE_COUNTER;
+ /*
+ Reset the initial step counter value, the first event received by the event listener is
+ stored in mCounterSteps and used to calculate the total number of steps taken.
+ */
+ mCounterSteps = 0;
+ Log.i(TAG, "Event listener for step counter sensor registered with a max delay of "
+ + mMaxDelay);
+ } else {
+ mState = STATE_DETECTOR;
+ Log.i(TAG, "Event listener for step detector sensor registered with a max delay of "
+ + mMaxDelay);
+ }
+
+ // Get the default sensor for the sensor type from the SenorManager
+ SensorManager sensorManager =
+ (SensorManager) getActivity().getSystemService(Activity.SENSOR_SERVICE);
+ // sensorType is either Sensor.TYPE_STEP_COUNTER or Sensor.TYPE_STEP_DETECTOR
+ Sensor sensor = sensorManager.getDefaultSensor(sensorType);
+
+ // Register the listener for this sensor in batch mode.
+ // If the max delay is 0, events will be delivered in continuous mode without batching.
+ final boolean batchMode = sensorManager.registerListener(
+ mListener, sensor, SensorManager.SENSOR_DELAY_NORMAL, maxdelay);
+
+ if (!batchMode) {
+ // Batch mode could not be enabled, show a warning message and switch to continuous mode
+ getCardStream().getCard(CARD_NOBATCHSUPPORT)
+ .setDescription(getString(R.string.warning_nobatching));
+ getCardStream().showCard(CARD_NOBATCHSUPPORT);
+ Log.w(TAG, "Could not register sensor listener in batch mode, " +
+ "falling back to continuous mode.");
+ }
+
+ if (maxdelay > 0 && batchMode) {
+ // Batch mode was enabled successfully, show a description card
+ getCardStream().showCard(CARD_BATCHING_DESCRIPTION);
+ }
+
+ // Show the explanation card
+ getCardStream().showCard(CARD_EXPLANATION);
+
+ // END_INCLUDE(register)
+
+ }
+
+ /**
+ * Unregisters the sensor listener if it is registered.
+ */
+ private void unregisterListeners() {
+ // BEGIN_INCLUDE(unregister)
+ SensorManager sensorManager =
+ (SensorManager) getActivity().getSystemService(Activity.SENSOR_SERVICE);
+ sensorManager.unregisterListener(mListener);
+ Log.i(TAG, "Sensor listener unregistered.");
+
+ // END_INCLUDE(unregister)
+ }
+
+ /**
+ * Resets the step counter by clearing all counting variables and lists.
+ */
+ private void resetCounter() {
+ // BEGIN_INCLUDE(reset)
+ mSteps = 0;
+ mCounterSteps = 0;
+ mEventLength = 0;
+ mEventDelays = new float[EVENT_QUEUE_LENGTH];
+ mPreviousCounterSteps = 0;
+ // END_INCLUDE(reset)
+ }
+
+
+ /**
+ * Listener that handles step sensor events for step detector and step counter sensors.
+ */
+ private final SensorEventListener mListener = new SensorEventListener() {
+ @Override
+ public void onSensorChanged(SensorEvent event) {
+ // BEGIN_INCLUDE(sensorevent)
+ // store the delay of this event
+ recordDelay(event);
+ final String delayString = getDelayString();
+
+ if (event.sensor.getType() == Sensor.TYPE_STEP_DETECTOR) {
+ // A step detector event is received for each step.
+ // This means we need to count steps ourselves
+
+ mSteps += event.values.length;
+
+ // Update the card with the latest step count
+ getCardStream().getCard(CARD_COUNTING)
+ .setTitle(getString(R.string.counting_title, mSteps))
+ .setDescription(getString(R.string.counting_description,
+ getString(R.string.sensor_detector), mMaxDelay, delayString));
+
+ Log.i(TAG,
+ "New step detected by STEP_DETECTOR sensor. Total step count: " + mSteps);
+
+ } else if (event.sensor.getType() == Sensor.TYPE_STEP_COUNTER) {
+
+ /*
+ A step counter event contains the total number of steps since the listener
+ was first registered. We need to keep track of this initial value to calculate the
+ number of steps taken, as the first value a listener receives is undefined.
+ */
+ if (mCounterSteps < 1) {
+ // initial value
+ mCounterSteps = (int) event.values[0];
+ }
+
+ // Calculate steps taken based on first counter value received.
+ mSteps = (int) event.values[0] - mCounterSteps;
+
+ // Add the number of steps previously taken, otherwise the counter would start at 0.
+ // This is needed to keep the counter consistent across rotation changes.
+ mSteps = mSteps + mPreviousCounterSteps;
+
+ // Update the card with the latest step count
+ getCardStream().getCard(CARD_COUNTING)
+ .setTitle(getString(R.string.counting_title, mSteps))
+ .setDescription(getString(R.string.counting_description,
+ getString(R.string.sensor_counter), mMaxDelay, delayString));
+ Log.i(TAG, "New step detected by STEP_COUNTER sensor. Total step count: " + mSteps);
+ // END_INCLUDE(sensorevent)
+ }
+ }
+
+ @Override
+ public void onAccuracyChanged(Sensor sensor, int accuracy) {
+
+ }
+ };
+
+ /**
+ * Records the delay for the event.
+ *
+ * @param event
+ */
+ private void recordDelay(SensorEvent event) {
+ // Calculate the delay from when event was recorded until it was received here in ms
+ // Event timestamp is recorded in us accuracy, but ms accuracy is sufficient here
+ mEventDelays[mEventData] = System.currentTimeMillis() - (event.timestamp / 1000000L);
+
+ // Increment length counter
+ mEventLength = Math.min(EVENT_QUEUE_LENGTH, mEventLength + 1);
+ // Move pointer to the next (oldest) location
+ mEventData = (mEventData + 1) % EVENT_QUEUE_LENGTH;
+ }
+
+ private final StringBuffer mDelayStringBuffer = new StringBuffer();
+
+ /**
+ * Returns a string describing the sensor delays recorded in
+ * {@link #recordDelay(android.hardware.SensorEvent)}.
+ *
+ * @return
+ */
+ private String getDelayString() {
+ // Empty the StringBuffer
+ mDelayStringBuffer.setLength(0);
+
+ // Loop over all recorded delays and append them to the buffer as a decimal
+ for (int i = 0; i < mEventLength; i++) {
+ if (i > 0) {
+ mDelayStringBuffer.append(", ");
+ }
+ final int index = (mEventData + i) % EVENT_QUEUE_LENGTH;
+ final float delay = mEventDelays[index] / 1000f; // convert delay from ms into s
+ mDelayStringBuffer.append(String.format("%1.1f", delay));
+ }
+
+ return mDelayStringBuffer.toString();
+ }
+
+ /**
+ * Records the state of the application into the {@link android.os.Bundle}.
+ *
+ * @param outState
+ */
+ @Override
+ public void onSaveInstanceState(Bundle outState) {
+ // BEGIN_INCLUDE(saveinstance)
+ super.onSaveInstanceState(outState);
+ // Store all variables required to restore the state of the application
+ outState.putInt(BUNDLE_LATENCY, mMaxDelay);
+ outState.putInt(BUNDLE_STATE, mState);
+ outState.putInt(BUNDLE_STEPS, mSteps);
+ // END_INCLUDE(saveinstance)
+ }
+
+ @Override
+ public void onActivityCreated(Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+ // BEGIN_INCLUDE(restore)
+ // Fragment is being restored, reinitialise its state with data from the bundle
+ if (savedInstanceState != null) {
+ resetCounter();
+ mSteps = savedInstanceState.getInt(BUNDLE_STEPS);
+ mState = savedInstanceState.getInt(BUNDLE_STATE);
+ mMaxDelay = savedInstanceState.getInt(BUNDLE_LATENCY);
+
+ // Register listeners again if in detector or counter states with restored delay
+ if (mState == STATE_DETECTOR) {
+ registerEventListener(mMaxDelay, Sensor.TYPE_STEP_DETECTOR);
+ } else if (mState == STATE_COUNTER) {
+ // store the previous number of steps to keep step counter count consistent
+ mPreviousCounterSteps = mSteps;
+ registerEventListener(mMaxDelay, Sensor.TYPE_STEP_COUNTER);
+ }
+ }
+ // END_INCLUDE(restore)
+ }
+
+ /**
+ * Hides the registration cards, reset the counter and show the step counting card.
+ */
+ private void showCountingCards() {
+ // Hide the registration cards
+ getCardStream().hideCard(CARD_REGISTER_DETECTOR);
+ getCardStream().hideCard(CARD_REGISTER_COUNTER);
+
+ // Show the explanation card if it has not been dismissed
+ getCardStream().showCard(CARD_EXPLANATION);
+
+ // Reset the step counter, then show the step counting card
+ resetCounter();
+
+ // Set the inital text for the step counting card before a step is recorded
+ String sensor = "-";
+ if (mState == STATE_COUNTER) {
+ sensor = getString(R.string.sensor_counter);
+ } else if (mState == STATE_DETECTOR) {
+ sensor = getString(R.string.sensor_detector);
+ }
+ // Set initial text
+ getCardStream().getCard(CARD_COUNTING)
+ .setTitle(getString(R.string.counting_title, 0))
+ .setDescription(getString(R.string.counting_description, sensor, mMaxDelay, "-"));
+
+ // Show the counting card and make it undismissable
+ getCardStream().showCard(CARD_COUNTING, false);
+
+ }
+
+ /**
+ * Show the introduction card
+ */
+ private void showIntroCard() {
+ Card c = new Card.Builder(this, CARD_INTRO)
+ .setTitle(getString(R.string.intro_title))
+ .setDescription(getString(R.string.intro_message))
+ .build(getActivity());
+ getCardStream().addCard(c, true);
+ }
+
+ /**
+ * Show two registration cards, one for the step detector and counter sensors.
+ */
+ private void showRegisterCard() {
+ // Hide the counting and explanation cards
+ getCardStream().hideCard(CARD_BATCHING_DESCRIPTION);
+ getCardStream().hideCard(CARD_EXPLANATION);
+ getCardStream().hideCard(CARD_COUNTING);
+
+ // Show two undismissable registration cards, one for each step sensor
+ getCardStream().showCard(CARD_REGISTER_DETECTOR, false);
+ getCardStream().showCard(CARD_REGISTER_COUNTER, false);
+ }
+
+ /**
+ * Show the error card.
+ */
+ private void showErrorCard() {
+ getCardStream().showCard(CARD_NOBATCHSUPPORT, false);
+ }
+
+ /**
+ * Initialise Cards.
+ */
+ private void initialiseCards() {
+ // Step counting
+ Card c = new Card.Builder(this, CARD_COUNTING)
+ .setTitle("Steps")
+ .setDescription("")
+ .addAction("Unregister Listener", ACTION_UNREGISTER, Card.ACTION_NEGATIVE)
+ .build(getActivity());
+ getCardStream().addCard(c);
+
+ // Register step detector listener
+ c = new Card.Builder(this, CARD_REGISTER_DETECTOR)
+ .setTitle(getString(R.string.register_detector_title))
+ .setDescription(getString(R.string.register_detector_description))
+ .addAction(getString(R.string.register_0),
+ ACTION_REGISTER_DETECT_NOBATCHING, Card.ACTION_NEUTRAL)
+ .addAction(getString(R.string.register_5),
+ ACTION_REGISTER_DETECT_BATCHING_5s, Card.ACTION_NEUTRAL)
+ .addAction(getString(R.string.register_10),
+ ACTION_REGISTER_DETECT_BATCHING_10s, Card.ACTION_NEUTRAL)
+ .build(getActivity());
+ getCardStream().addCard(c);
+
+ // Register step counter listener
+ c = new Card.Builder(this, CARD_REGISTER_COUNTER)
+ .setTitle(getString(R.string.register_counter_title))
+ .setDescription(getString(R.string.register_counter_description))
+ .addAction(getString(R.string.register_0),
+ ACTION_REGISTER_COUNT_NOBATCHING, Card.ACTION_NEUTRAL)
+ .addAction(getString(R.string.register_5),
+ ACTION_REGISTER_COUNT_BATCHING_5s, Card.ACTION_NEUTRAL)
+ .addAction(getString(R.string.register_10),
+ ACTION_REGISTER_COUNT_BATCHING_10s, Card.ACTION_NEUTRAL)
+ .build(getActivity());
+ getCardStream().addCard(c);
+
+
+ // Batching description
+ c = new Card.Builder(this, CARD_BATCHING_DESCRIPTION)
+ .setTitle(getString(R.string.batching_queue_title))
+ .setDescription(getString(R.string.batching_queue_description))
+ .addAction(getString(R.string.action_notagain),
+ ACTION_BATCHING_DESCRIPTION_DISMISS, Card.ACTION_POSITIVE)
+ .build(getActivity());
+ getCardStream().addCard(c);
+
+ // Explanation
+ c = new Card.Builder(this, CARD_EXPLANATION)
+ .setDescription(getString(R.string.explanation_description))
+ .addAction(getString(R.string.action_notagain),
+ ACTION_EXPLANATION_DISMISS, Card.ACTION_POSITIVE)
+ .build(getActivity());
+ getCardStream().addCard(c);
+
+ // Error
+ c = new Card.Builder(this, CARD_NOBATCHSUPPORT)
+ .setTitle(getString(R.string.error_title))
+ .setDescription(getString(R.string.error_nosensor))
+ .build(getActivity());
+ getCardStream().addCard(c);
+ }
+
+ /**
+ * Returns the cached CardStreamFragment used to show cards.
+ *
+ * @return
+ */
+ private CardStreamFragment getCardStream() {
+ if (mCards == null) {
+ mCards = ((CardStream) getActivity()).getCardStream();
+ }
+ return mCards;
+ }
+
+}
diff --git a/sensors/BatchStepSensor/BatchStepSensorSample/src/main/res/drawable-hdpi/ic_launcher.png b/sensors/BatchStepSensor/BatchStepSensorSample/src/main/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 00000000..564742cc
--- /dev/null
+++ b/sensors/BatchStepSensor/BatchStepSensorSample/src/main/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/sensors/BatchStepSensor/BatchStepSensorSample/src/main/res/drawable-mdpi/ic_launcher.png b/sensors/BatchStepSensor/BatchStepSensorSample/src/main/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 00000000..08abe575
--- /dev/null
+++ b/sensors/BatchStepSensor/BatchStepSensorSample/src/main/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/sensors/BatchStepSensor/BatchStepSensorSample/src/main/res/drawable-xhdpi/ic_launcher.png b/sensors/BatchStepSensor/BatchStepSensorSample/src/main/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 00000000..15bafae9
--- /dev/null
+++ b/sensors/BatchStepSensor/BatchStepSensorSample/src/main/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/sensors/BatchStepSensor/BatchStepSensorSample/src/main/res/drawable-xxhdpi/ic_launcher.png b/sensors/BatchStepSensor/BatchStepSensorSample/src/main/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 00000000..40bdd35d
--- /dev/null
+++ b/sensors/BatchStepSensor/BatchStepSensorSample/src/main/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/sensors/BatchStepSensor/BatchStepSensorSample/src/main/res/values/strings.xml b/sensors/BatchStepSensor/BatchStepSensorSample/src/main/res/values/strings.xml
new file mode 100644
index 00000000..9c0a8add
--- /dev/null
+++ b/sensors/BatchStepSensor/BatchStepSensorSample/src/main/res/values/strings.xml
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2014 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.
+-->
+
+<resources>
+ <string name="intro_title">Introduction</string>
+
+ <string name="batching_queue_title">Background sensor batching</string>
+ <string name="batching_queue_description">Batching allows the sensor to report sensor events at
+ a specified frequency.\n\nThe system delays calls to the SensorEventListener and deliver
+ them in intervals, based on the maximum report latency specified when the listener is
+ registered. Note that this only means that the call to onSensorChanged() is delayed, the
+ total number of calls is identical as if no batching was used. Sensors only deliver events
+ while the CPU is awake. If the CPU is asleep and a batched sensor event listener is still
+ registered, the sensor will continue to collect events until it runs out of memory and
+ overwrites old values. This use case is not covered by this sample. (The sensor event queue
+ should be flushed using a scheduled background thread.) \n\nIn this sample app data is only
+ collected while the app is running and the CPU is awake. In this case the sensor will
+ deliver events before the queue fills up.
+ </string>
+
+ <string name="explanation_description">The age of a sensor event describes the delay between
+ when it was recorded by the sensor until it was delivered to the SensorEventListener.
+ </string>
+
+ <string name="register_detector_title">Register step detector sensor</string>
+ <string name="register_detector_description">Register a listener for the STEP DETECTOR
+ sensor.\n\nThis sensor delivers an event when the user takes a step. One event is received
+ per step.
+ </string>
+
+ <string name="register_counter_title">Register step counter sensor</string>
+ <string name="register_counter_description">Register a listener for the STEP COUNTER
+ sensor.\n\nThis sensor triggers events when a step is detected, but applies algorithms to
+ filter out false positives. Events from this sensor have higher latency than the step
+ detector and contain the total number of steps taken since the sensor was first registered.
+ </string>
+
+ <string name="register_0">No batching (delay=0)</string>
+ <string name="register_5">5s batching (delay=5000ms)</string>
+ <string name="register_10">10s batching (delay=10000ms)</string>
+
+ <string name="counting_title">Total Steps: %1$d</string>
+ <string name="sensor_counter">Step Counter</string>
+ <string name="sensor_detector">Step Detector</string>
+ <string name="counting_description">Sensor: %1$s\nMax sensor event delay: %2$,d \u00B5s\nAge of
+ events in s:\n%3$s
+ </string>
+
+ <string name="error_title">Error</string>
+ <string name="error_nosensor">This sample requires at least Android KitKat (4.4) and a device
+ with the step sensor.\n\nThis device does not appear to meet these requirements, as an
+ alternative you may want to consider using the gyro sensor and implement your own step
+ recognition as a fallback.
+ </string>
+ <string name="warning_nobatching">The listener has been registered, but batch mode could not be
+ enabled.\n\nIt is likely that it is not supported by this device.\n\nSensor events will be
+ delivered in continuous mode.
+ </string>
+
+ <string name="action_notagain">Do not show again</string>
+</resources> \ No newline at end of file
diff --git a/sensors/BatchStepSensor/build.gradle b/sensors/BatchStepSensor/build.gradle
new file mode 100644
index 00000000..f9f6f652
--- /dev/null
+++ b/sensors/BatchStepSensor/build.gradle
@@ -0,0 +1,14 @@
+
+
+
+
+// BEGIN_EXCLUDE
+import com.example.android.samples.build.SampleGenPlugin
+apply plugin: SampleGenPlugin
+
+samplegen {
+ pathToBuild "../../../../build"
+ pathToSamplesCommon "../../common"
+}
+apply from: "../../../../build/build.gradle"
+// END_EXCLUDE
diff --git a/sensors/BatchStepSensor/buildSrc/build.gradle b/sensors/BatchStepSensor/buildSrc/build.gradle
new file mode 100644
index 00000000..29282af4
--- /dev/null
+++ b/sensors/BatchStepSensor/buildSrc/build.gradle
@@ -0,0 +1,18 @@
+
+
+
+repositories {
+ mavenCentral()
+}
+dependencies {
+ compile 'org.freemarker:freemarker:2.3.20'
+}
+
+sourceSets {
+ main {
+ groovy {
+ srcDir new File(rootDir, "../../../../../build/buildSrc/src/main/groovy")
+ }
+ }
+}
+
diff --git a/sensors/BatchStepSensor/gradle/wrapper/gradle-wrapper.jar b/sensors/BatchStepSensor/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 00000000..8c0fb64a
--- /dev/null
+++ b/sensors/BatchStepSensor/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/sensors/BatchStepSensor/gradle/wrapper/gradle-wrapper.properties b/sensors/BatchStepSensor/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 00000000..56f685a4
--- /dev/null
+++ b/sensors/BatchStepSensor/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Wed Apr 10 15:27:10 PDT 2013
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=http\://services.gradle.org/distributions/gradle-1.10-bin.zip
diff --git a/sensors/BatchStepSensor/gradlew b/sensors/BatchStepSensor/gradlew
new file mode 100755
index 00000000..91a7e269
--- /dev/null
+++ b/sensors/BatchStepSensor/gradlew
@@ -0,0 +1,164 @@
+#!/usr/bin/env bash
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+ echo "$*"
+}
+
+die ( ) {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+esac
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched.
+if $cygwin ; then
+ [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
+fi
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >&-
+APP_HOME="`pwd -P`"
+cd "$SAVED" >&-
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
+function splitJvmOpts() {
+ JVM_OPTS=("$@")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
diff --git a/sensors/BatchStepSensor/gradlew.bat b/sensors/BatchStepSensor/gradlew.bat
new file mode 100644
index 00000000..aec99730
--- /dev/null
+++ b/sensors/BatchStepSensor/gradlew.bat
@@ -0,0 +1,90 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windowz variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+if "%@eval[2+2]" == "4" goto 4NT_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+goto execute
+
+:4NT_args
+@rem Get arguments from the 4NT Shell from JP Software
+set CMD_LINE_ARGS=%$
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/sensors/BatchStepSensor/settings.gradle b/sensors/BatchStepSensor/settings.gradle
new file mode 100644
index 00000000..18ebefc5
--- /dev/null
+++ b/sensors/BatchStepSensor/settings.gradle
@@ -0,0 +1,4 @@
+
+
+
+include 'BatchStepSensorSample'
diff --git a/sensors/BatchStepSensor/template-params.xml b/sensors/BatchStepSensor/template-params.xml
new file mode 100644
index 00000000..a07579de
--- /dev/null
+++ b/sensors/BatchStepSensor/template-params.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 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.
+-->
+
+
+
+<sample>
+ <name>BatchStepSensor</name>
+ <group>Sensors</group>
+ <package>com.example.android.batchstepsensor</package>
+
+
+
+ <!-- change minSdk if needed-->
+ <minSdk>19</minSdk>
+
+
+ <strings>
+ <intro>
+ <![CDATA[
+ This sample demonstrates the use of the two step sensors (step detector and counter) and
+ sensor batching.\n\n It shows how to register a SensorEventListener with and without
+ batching and shows how these events are received.\n\nThe Step Detector sensor fires an
+ event when a step is detected, while the step counter returns the total number of
+ steps since a listener was first registered for this sensor.
+ Both sensors only count steps while a listener is registered. This sample only covers the
+ basic case, where a listener is only registered while the app is running. Likewise,
+ batched sensors can be used in the background (when the CPU is suspended), which
+ requires manually flushing the sensor event queue before it overflows, which is not
+ covered in this sample.
+ ]]>
+ </intro>
+ </strings>
+
+ <template src="base"/>
+ <template src="CardStream"/>
+ <common src="logger"/>
+ <common src="activities"/>
+
+</sample>