You are on page 1of 112

PROJECT FORMAT

1. ABSTRACT
2. INTRODUCTION
3. FEASIBILITY STUDY
4. SYSTEM ANALYSIS
i.

Existing system

ii.

Proposed system

5. SYSTEM REQUIREMENTS
i.

Software requirements

ii.

Hardware requirements

6. DATA FLOW DIAGRAMS


7. ABOUT THE LANGUAGE (FRONT-END AND BACK-END)
8. SOURCE CODE (its in Microsoft word for documentation)
9. SCREEN SHOTS (same as above)
10.TESTING
11.MAINTENANCE
12.CONCLUSION
13.FUTURE ENHANCEMENTS
14.BIBLIOGRAPHY (related reference books and related project web sites).

ABSTRACT

Abstract:
In this project we intended to create an apps in android which will help us to track the
location and change of location while a person carrying a smart phone commute from one place
to another within a closed environment. This is intended to develop using the internal sensors
embedded in the smart phones. This project will use geometric field sensors API, position
sensors API, proximity sensors, motion sensors and accelerometer which are all coming with
android to enable as GPS (Global Positioning System) navigation systems will be smartly
utilized to detect the current position and in case of changing position into an vector and
calculating the speed of monitor using the distance, displace and time taken for that
displacement.
This will be base for several projects which can be derived from this base application
such as unambiguous pedestrian tracking and blind people in house guidance application etc
This navel method of existing APIs and unambiguous algorithm will pave the way for
developed and innovation of many project in future.

INTRODUCTION
This project is developed to create new apps that always run in the background, counting
our steps, tracking our location, or listening to us as we sleep. These tasks require that a process
remains in an active state, and whenever there's any activity going on within a smartphone,
battery life takes a hit. Android 4.4 reduces the impact of these processes with new support for
hardware sensor batching.
This optimization allows Android to collect and deliver sensor events in clumps, rather
than keep track of them individually. Think of this as the difference between ordering one T-shirt
and ordering a thousand. Just as producing a product in bulk is easier on the manufacturer,
sending bite-sized tracking data in batches puts less of a strain on your phone, as it reduces how
often it has to wake up from an idle state.
New Version of KitKat also adds platform support for two new sensors, step
detector and step counter. The former can recognize when a user takes a step and trigger an event
as a result, while the latter tracks the total number of steps taken since the last device reboot.
Since these functions are now implemented into the platform and underlying hardware, we are
using this functionality of Kitkat to develop the project to identify the motion detection and
location identification using the process called batch step sensor.
Android sensors give applications access to a mobile device's underlying base sensor(s):
accelerometer, gyroscope, and magnetometer. Manufacturers develop the drivers that define
additional composite sensor types from those base sensors. For instance, Android offers both
calibrated and uncalibrated gyroscopes, a geomagnetic rotation vector and a game rotation
vector. This variety gives developers some flexibility in tuning applications for battery life
optimization and accuracy. We effectively use these facility of android and ensuring the
deduction of steps and speed in this project which can be the base for future innovative
applications based on the sensors.

FEASIBILITY STUDY
As we have discussed in the introduction this project is developed based on the
functionalities of Android OS and Hardware of smart phones, this is theoretically feasibility is
observed and we intended to introspect whether our postulates and hypothesis about the
construction of the project. On throw study on this the following finding were evolved.

Technical Feasibility
This Application needs an android phone with sensors and which can work on Android
4.4 Kitkat OS. This project can be developed and built as an application using the ADT Studio
which supports Kitkat OS. Even though the ADT is available the simulators can be used to
certain extend only due to lack of sensor hardware and simulation of motion in the simulator. So
we have decided to develop sensor simulator in java to test the functionality of sensor in the OS.
Once it is successful it is understood that we can implement this process of Motion deduction
using batch step process. So it is decided that there is a technical feasibility for this project with
its own limitation.
The limitations are only during the development and testing because of the absence of
hardware sensors in the emulators and the another limitation that this can be developed only in
Android Kitkat OS.

SYSTEM ANALYSIS

Existing System
The Existing Sensor based projects are based on real-time running of application directly
interact with the hardware and having processor intensive , memory intensive, as well as
consumption of battery to the grater extend. Which is very critical for the smart phone? All the
application which will be running in foreground and keep on detecting the activities whether the
activity is happening or not. Also the hardware need to be controlled or monitored and signal
capturing all need to be controlled using hardcore programming due to lack of APIs. In nonbatch mode, all sensor events must be reported as soon as they are detected. For example, an
accelerometer activated at 50Hz will trigger interrupts 50 times per second. This makes the
application processor time intensive and efficiency may drop down drastically. To over come
this limitation The batch mode tracking of sensors is utilized.

Proposed System
While in batch mode, sensor events do not need to be reported as soon as they are
detected. They can be temporarily stored and reported in batches, as long as no event is delayed
by more than maxReportingLatency nanoseconds. That is, all events since the previous
batch are recorded and returned at once. This reduces the amount of interrupts sent to the SoC
and allows the SoC to switch to a lower power mode (idle) while the sensor is capturing and
batching data.
nabling batch mode for a given sensor sets the delay between events. max_report_latency
sets the maximum time by which events can be delayed and batched together before being
reported to the applications. A value of zero disables batch mode for the given sensor. The
period_ns parameter is equivalent to calling setDelay() -- this function both enables or disables
the batch mode AND sets the event's period in nanoseconds. See setDelay() for a detailed
explanation of the period_ns parameter.
These are the power modes of the application processor: on, idle, and suspend. The
sensors behave differently in each of these modes. As you would imagine, on mode is when the

application processor is running. Idle mode is a medium power mode where the application
processor is powered but doesn't perform any tasks. Suspend is a low-power mode where the
application processor is not powered. The power consumption of the device in this mode is
usually 100 times less than in the On mode.

SYSTEM REQUIREMENTS
HARDWRE REQUIRMENTS
For Development :
PC with Intel Duel Core Processor
Minimum of 4 GB RAM
500 GB HDD
VGA Card With Built in Video RAM
For Testing
Tablet PC or Smart phone with Sensors which adhering to th standards of Nexus 5
or above
Software Requirements
Either Windows 7 or Ubuntu 13
Software Development

Android ADK Studio


Android Development Kit Bundle 4.4 or later
Android OS 4.41 KIT KAT

State machine for the accelerometer x-axis data when the device is placed on a
flat surface.

Accelerometer data coordinate system in android

Control Flow Diagram

BATCH Step Sensor


Process

Acceleration
Sensor
Acceleration
Sensor

Process

Other Sensors

Walk/Run

Move or
rotate the
phone
No Action

Use Case Diagram for Batch Step process

About the Software


As this project used device level programming there is no concept of back end database
used in this Application We have used android OS and and Developed the application using
JAVA.
Android is an operating system based on the Linux kernel. The project responsible for
developing the Android system is called the Android Open Source Project (AOSP) and is
primarily lead by Google. The Android system supports background processing, provides a rich
user interface library, supports 2-D and 3-D graphics using the OpenGL-ES (short OpenGL)
standard and grants access to the file system as well as an embedded SQLite database An
Android application typically consists of different visual and non visual components and can
reuse components of other applications.
The Android system is a full software stack, which is typically divided into the four areas
as depicted in the following graphic.

The levels can be described as:

Applications - The Android Open Source Project contains several default


application, like the Browser, Camera, Gallery, Music, Phone and more.
Application framework - An API which allows high-level interactions with the
Android system from Android applications.
Libraries and runtime - The libraries for many common functions (e.g.:
graphic rendering, data storage, web browsing, etc.) of the Application
Framework and the Dalvik runtime, as well as the core Java libraries for
running Android applications.
Linux kernel - Communication layer for the underlying hardware.
The Linux kernel, the libraries and the runtime are encapsulated by the application
framework. The Android application developer typically works with the two layers on
top to create new Android applications.

Android Development Tools


Android SDK
The Android Software Development Kit (Android SDK) contains the necessary tools
to create, compile and package Android applications. Most of these tools are
command line based. The primary way to develop Android applications is based on
the Java programming language.

Android debug bridge (adb)


The Android SDK contains the Android debug bridge (adb), which is a tool that
allows you to connect to a virtual or real Android device, for the purpose of
managing the device or debugging your application.

Android Developer Tools and Android Studio


Google provides two integrated development environments (IDEs) to develop new
applications.
The Android Developer Tools (ADT) are based on the Eclipse IDE. ADT is a set of
components (plug-ins), which extend the Eclipse IDE with Android development
capabilities.
Google also supports an IDE called Android Studio for creating Android applications.
This IDE is based on the IntelliJ IDE.
Both IDEs contain all required functionality to create, compile, debug and deploy
Android applications. They also allow the developer to create and start virtual
Android devices for testing.

Both tools provide specialized editors for Android specific files. Most of Android's
configuration files are based on XML. In this case these editors allow you to switch
between the XML representation of the file and a structured user interface for
entering the data.

Dalvik Virtual Machine


The Android system uses a special virtual machine, i.e., the Dalvik Virtual Machine
(Dalvik) to run Java based applications. Dalvik uses a custom bytecode format which
is different from Java bytecode.
Therefore you cannot run Java class files on Android directly; they need to be
converted into the Dalvik bytecode format.

Just in time compiler on Dalvik


Similar to the JVM, Dalvik optimizes the application at runtime. This is known as Just
In Time (JIT) compilation. If a part of the application is called frequently, Dalvik will
optimize this part of the code and compile it into machine code which executes
much faster.

Android RunTime (ART)


With Android 4.4, Google introduced the Android RunTime (ART) as optional runtime
for Android 4.4. It is expected that versions after 4.4 will use ART as default runtime.
ART uses Ahead Of Time compilation. During the deployment process of an
application on an Android device, the application code is translated into machine
code. This results in approx. 30% larger compile code, but allows faster execution
from the beginning of the application.

How to develop Android applications


Android applications are primarily written in the Java programming language.
During development the developer creates the Android specific configuration files
and writes the application logic in the Java programming language.
The ADT or the Android Studio tools convert these application files, transparently to
the user, into an Android application. When developers trigger the deployment in
their IDE, the whole Android application is compiled, packaged, deployed and
started.

Conversion process from source code to Android application


The Java source files are converted to Java class files by the Java compiler.
The Android SDK contains a tool called dx which converts Java class files into a .dex
(Dalvik Executable) file. All class files of the application are placed in this .dex file.

During this conversion process redundant information in the class files are
optimized in the .dex file.
For example, if the same String is found in different class files, the .dex file
contains only one reference of this String.
These .dex files are therefore much smaller in size than the corresponding class
files.
The .dex file and the resources of an Android project, e.g., the images and XML
files, are packed into an .apk (Android Package) file. The program aapt (Android
Asset Packaging Tool) performs this step.
The resulting .apk file contains all necessary data to run the Android application
and can be deployed to an Android device via the adb tool.

5. Android device emulator and Android Virtual Devices

Android emulator and Android Virtual Device


The Android SDK contains an Android device emulator. This emulator can be used to
run an Android Virtual Device (AVD), which emulates a real Android phone. Such an
emulator is displayed in the following screenshot.

AVDs allow you to test your Android applications on different Android versions and
configurations without access to the real hardware.
During the creation of your AVD you define the configuration for the virtual device.
This includes, for example, the resolution, the Android API version and the density of
your display.
You can define multiple AVDs with different configurations and start them in parallel.
This allows you to test different device configurations at once.

Project Outline

BatchStepSensor
BatchStepSensor
AndroidManifest.xml
res
drawable
card_action_bg.xml
card_action_bg_negative.xml
card_action_bg_positive.xml
card_action_icon_negative.xml
card_action_icon_neutral.xml
card_action_icon_positive.xml
card_action_text.xml
card_action_text_negative.xml
card_action_text_positive.xml
card_overlay_focused.xml

card_separator.xml
drawable-hdpi
ic_action_cancel.png
ic_launcher.png
tile.9.png
drawable-mdpi
ic_action_cancel.png
ic_launcher.png
drawable-xhdpi
card_bg.9.png
ic_cardaction_negative.png
ic_cardaction_negative_pressed.png
ic_cardaction_neutral.png
ic_cardaction_neutral_pressed.png
ic_cardaction_positive.png
ic_cardaction_positive_pressed.png
ic_launcher.png
drawable-xxhdpi
ic_action_cancel.png

ic_launcher.png
layout
activity_main.xml
card.xml
card_button_negative.xml
card_button_neutral.xml
card_button_positive.xml
card_button_seperator.xml
card_progress.xml
cardstream.xml
values
attrs.xml
base-strings.xml
color.xml
dimens.xml
ids.xml
strings.xml
styles.xml

template-dimens.xml
template-styles.xml
values-sw600dp
template-dimens.xml
template-styles.xml
values-sw720dp-land
dimens.xml
values-v11
styles.xml
values-v14
styles.xml
values-v16
styles.xml
src
com.example.android.batchstepsensor
BatchStepSensorFragment.java
Card.java
CardActionButton.java
CardLayout.java

CardStream.java
CardStreamAnimator.java
CardStreamFragment.java
CardStreamLinearLayout.java
CardStreamState.java
DefaultCardStreamAnimator.java
MainActivity.java
OnCardClickListener.java
StreamRetentionFragment.java
com.example.android.common
activities
SampleActivityBase.java
logger
Log.java
LogFragment.java
LogNode.java
LogView.java
LogWrapper.java

MessageOnlyLogFilter.java

Source Code:
MainActivity.java
package com.example.android.batchstepsensor;
import android.os.Bundle;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.view.Menu;
import com.example.android.common.activities.SampleActivityBase;
import com.example.android.common.logger.Log;
public class MainActivity extends SampleActivityBase implements CardStream {
public static final String TAG = "MainActivity";
public static final String FRAGTAG = "BatchStepSensorFragment";
private CardStreamFragment mCardStreamFragment;
private StreamRetentionFragment mRetentionFragment;
private static final String RETENTION_TAG = "retention";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);
FragmentManager fm = getSupportFragmentManager();
BatchStepSensorFragment fragment =
(BatchStepSensorFragment) fm.findFragmentByTag(FRAGTAG);
if (fragment == null) {
FragmentTransaction transaction = fm.beginTransaction();
fragment = new BatchStepSensorFragment();
transaction.add(fragment, FRAGTAG);
transaction.commit();
}
// Use fragment as click listener for cards, but must implement correct interface
if(!(fragment instanceof OnCardClickListener)){
throw new ClassCastException("BatchStepSensorFragment must " +
"implement OnCardClickListener interface.");
}
OnCardClickListener clickListener = (OnCardClickListener)
fm.findFragmentByTag(FRAGTAG);

mRetentionFragment = (StreamRetentionFragment)
fm.findFragmentByTag(RETENTION_TAG);
if (mRetentionFragment == null) {
mRetentionFragment = new StreamRetentionFragment();
fm.beginTransaction().add(mRetentionFragment, RETENTION_TAG).commit();
} else {
// If the retention fragment already existed, we need to pull some state.
// pull state out
CardStreamState state = mRetentionFragment.getCardStream();
// dump it in CardStreamFragment.
mCardStreamFragment =
(CardStreamFragment) fm.findFragmentById(R.id.fragment_cardstream);
mCardStreamFragment.restoreState(state, clickListener);
}
}

public CardStreamFragment getCardStream() {


if (mCardStreamFragment == null) {
mCardStreamFragment = (CardStreamFragment)

getSupportFragmentManager().findFragmentById(R.id.fragment_cardstream);
}
return mCardStreamFragment;
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
CardStreamState state = getCardStream().dumpState();
mRetentionFragment.storeCardStream(state);
}
}

BatchStepSensorFragment.java
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_COU
NTER)
&&
packageManager.hasSystemFeature(PackageManager.FEATURE_SENSOR_STEP_DET
ECTOR);
// 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;
}

}
Card.java
package com.example.android.batchstepsensor;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.app.Activity;
import android.graphics.Color;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ProgressBar;

import android.widget.TextView;

import java.util.ArrayList;

/**
* A Card contains a description and has a visual state. Optionally a card also contains a
title,
* progress indicator and zero or more actions. It is constructed through the {@link
Builder}.
*/
public class Card {

public static final int ACTION_POSITIVE = 1;


public static final int ACTION_NEGATIVE = 2;
public static final int ACTION_NEUTRAL = 3;

public static final int PROGRESS_TYPE_NO_PROGRESS = 0;


public static final int PROGRESS_TYPE_NORMAL = 1;
public static final int PROGRESS_TYPE_INDETERMINATE = 2;

public static final int PROGRESS_TYPE_LABEL = 3;

private OnCardClickListener mClickListener;

// The card model contains a reference to its desired layout (for extensibility), title,
// description, zero to many action buttons, and zero or 1 progress indicators.
private int mLayoutId = R.layout.card;

/**
* Tag that uniquely identifies this card.
*/
private String mTag = null;

private String mTitle = null;


private String mDescription = null;

private View mCardView = null;


private View mOverlayView = null;

private TextView mTitleView = null;


private TextView mDescView = null;
private View mActionAreaView = null;

private Animator mOngoingAnimator = null;

/**
* Visual state, either {@link #CARD_STATE_NORMAL}, {@link
#CARD_STATE_FOCUSED} or
* {@link #CARD_STATE_INACTIVE}.
*/
private int mCardState = CARD_STATE_NORMAL;
public static final int CARD_STATE_NORMAL = 1;
public static final int CARD_STATE_FOCUSED = 2;
public static final int CARD_STATE_INACTIVE = 3;

/**
* Represent actions that can be taken from the card. Stylistically the developer can
* designate the action as positive, negative (ok/cancel, for instance), or neutral.

* This "type" can be used as a UI hint.


* @see com.example.android.sensors.batchstepsensor.Card.CardAction
*/
private ArrayList<CardAction> mCardActions = new ArrayList<CardAction>();

/**
* Some cards will have a sense of "progress" which should be associated with, but
separated
* from its "parent" card. To push for simplicity in samples, Cards are designed to
have
* a maximum of one progress indicator per Card.
*/
private CardProgress mCardProgress = null;

public Card() {
}

public String getTag() {


return mTag;

public View getView() {


return mCardView;
}

public Card setDescription(String desc) {


if (mDescView != null) {
mDescription = desc;
mDescView.setText(desc);
}
return this;
}

public Card setTitle(String title) {


if (mTitleView != null) {
mTitle = title;
mTitleView.setText(title);

}
return this;
}

/**
* Return the UI state, either {@link #CARD_STATE_NORMAL}, {@link
#CARD_STATE_FOCUSED}
* or {@link #CARD_STATE_INACTIVE}.
*/
public int getState() {
return mCardState;
}

/**
* Set the UI state. The parameter describes the state and must be either
* {@link #CARD_STATE_NORMAL}, {@link #CARD_STATE_FOCUSED} or
{@link #CARD_STATE_INACTIVE}.
* Note: This method must be called from the UI Thread.

* @param state
* @return The card itself, allows for chaining of calls
*/
public Card setState(int state) {
mCardState = state;
if (null != mOverlayView) {
if (null != mOngoingAnimator) {
mOngoingAnimator.end();
mOngoingAnimator = null;
}
switch (state) {
case CARD_STATE_NORMAL: {
mOverlayView.setVisibility(View.GONE);
mOverlayView.setAlpha(1.f);
break;
}
case CARD_STATE_FOCUSED: {
mOverlayView.setVisibility(View.VISIBLE);
mOverlayView.setBackgroundResource(R.drawable.card_overlay_focused);

ObjectAnimator animator = ObjectAnimator.ofFloat(mOverlayView,


"alpha", 0.f);
animator.setRepeatMode(ObjectAnimator.REVERSE);
animator.setRepeatCount(ObjectAnimator.INFINITE);
animator.setDuration(1000);
animator.start();
mOngoingAnimator = animator;
break;
}
case CARD_STATE_INACTIVE: {
mOverlayView.setVisibility(View.VISIBLE);
mOverlayView.setAlpha(1.f);
mOverlayView.setBackgroundColor(Color.argb(0xaa, 0xcc, 0xcc, 0xcc));
break;
}
}
}
return this;
}

/**
* Set the type of progress indicator.
* The progress type can only be changed if the Card was initially build with a progress
* indicator.
* See {@link Builder#setProgressType(int)}.
* Must be a value of either {@link #PROGRESS_TYPE_NORMAL},
* {@link #PROGRESS_TYPE_INDETERMINATE}, {@link
#PROGRESS_TYPE_LABEL} or
* {@link #PROGRESS_TYPE_NO_PROGRESS}.
* @param progressType
* @return The card itself, allows for chaining of calls
*/
public Card setProgressType(int progressType) {
if (mCardProgress == null) {
mCardProgress = new CardProgress();
}
mCardProgress.setProgressType(progressType);
return this;

/**
* Return the progress indicator type. A value of either {@link
#PROGRESS_TYPE_NORMAL},
* {@link #PROGRESS_TYPE_INDETERMINATE}, {@link
#PROGRESS_TYPE_LABEL}. Otherwise if no progress
* indicator is enabled, {@link #PROGRESS_TYPE_NO_PROGRESS} is returned.
* @return
*/
public int getProgressType() {
if (mCardProgress == null) {
return PROGRESS_TYPE_NO_PROGRESS;
}
return mCardProgress.progressType;
}

/**
* Set the progress to the specified value. Only applicable if the card has a

* {@link #PROGRESS_TYPE_NORMAL} progress type.


* @param progress
* @return
* @see #setMaxProgress(int)
*/
public Card setProgress(int progress) {
if (mCardProgress != null) {
mCardProgress.setProgress(progress);
}
return this;
}

/**
* Set the range of the progress to 0...max. Only applicable if the card has a
* {@link #PROGRESS_TYPE_NORMAL} progress type.
* @return
*/
public Card setMaxProgress(int max){
if (mCardProgress != null) {

mCardProgress.setMax(max);
}
return this;
}

/**
* Set the label text for the progress if the card has a progress type of
* {@link #PROGRESS_TYPE_NORMAL}, {@link
#PROGRESS_TYPE_INDETERMINATE} or
* {@link #PROGRESS_TYPE_LABEL}
* @param text
* @return
*/
public Card setProgressLabel(String text) {
if (mCardProgress != null) {
mCardProgress.setProgressLabel(text);
}
return this;
}

/**
* Toggle the visibility of the progress section of the card. Only applicable if
* the card has a progress type of
* {@link #PROGRESS_TYPE_NORMAL}, {@link
#PROGRESS_TYPE_INDETERMINATE} or
* {@link #PROGRESS_TYPE_LABEL}.
* @param isVisible
* @return
*/
public Card setProgressVisibility(boolean isVisible) {
if (mCardProgress.progressView == null) {
return this; // Card does not have progress
}
mCardProgress.progressView.setVisibility(isVisible ? View.VISIBLE :
View.GONE);

return this;
}

/**
* Adds an action to this card during build time.
*
* @param label
* @param id
* @param type
*/
private void addAction(String label, int id, int type) {
CardAction cardAction = new CardAction();
cardAction.label = label;
cardAction.id = id;
cardAction.type = type;
mCardActions.add(cardAction);
}

/**
* Toggles the visibility of a card action.
* @param actionId

* @param isVisible
* @return
*/
public Card setActionVisibility(int actionId, boolean isVisible) {
int visibilityFlag = isVisible ? View.VISIBLE : View.GONE;
for (CardAction action : mCardActions) {
if (action.id == actionId && action.actionView != null) {
action.actionView.setVisibility(visibilityFlag);
}
}
return this;
}

/**
* Toggles visibility of the action area of this Card through an animation.
* @param isVisible
* @return
*/

public Card setActionAreaVisibility(boolean isVisible) {


if (mActionAreaView == null) {
return this; // Card does not have an action area
}

if (isVisible) {
// Show the action area
mActionAreaView.setVisibility(View.VISIBLE);
mActionAreaView.setPivotY(0.f);
mActionAreaView.setPivotX(mCardView.getWidth() / 2.f);
mActionAreaView.setAlpha(0.5f);
mActionAreaView.setRotationX(-90.f);
mActionAreaView.animate().rotationX(0.f).alpha(1.f).setDuration(400);
} else {
// Hide the action area
mActionAreaView.setPivotY(0.f);
mActionAreaView.setPivotX(mCardView.getWidth() / 2.f);
mActionAreaView.animate().rotationX(90.f).alpha(0.f).setDuration(400).setListener(

new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
mActionAreaView.setVisibility(View.GONE);
}
});
}
return this;
}

/**
* Creates a shallow clone of the card. Shallow means all values are present, but no
views.
* This is useful for saving/restoring in the case of configuration changes, like screen
* rotation.
*
* @return A shallow clone of the card instance
*/

public Card createShallowClone() {


Card cloneCard = new Card();

// Outer card values


cloneCard.mTitle = mTitle;
cloneCard.mDescription = mDescription;
cloneCard.mTag = mTag;
cloneCard.mLayoutId = mLayoutId;
cloneCard.mCardState = mCardState;

// Progress
if (mCardProgress != null) {
cloneCard.mCardProgress = mCardProgress.createShallowClone();
}

// Actions
for (CardAction action : mCardActions) {
cloneCard.mCardActions.add(action.createShallowClone());
}

return cloneCard;
}

/**
* Prepare the card to be stored for configuration change.
*/
public void prepareForConfigurationChange() {
// Null out views.
mCardView = null;
for (CardAction action : mCardActions) {
action.actionView = null;
}
mCardProgress.progressView = null;
}

/**

* Creates a new {@link #Card}.


*/
public static class Builder {
private Card mCard;

/**
* Instantiate the builder with data from a shallow clone.
* @param listener
* @param card
* @see Card#createShallowClone()
*/
protected Builder(OnCardClickListener listener, Card card) {
mCard = card;
mCard.mClickListener = listener;
}

/**
* Instantiate the builder with the tag of the card.
* @param listener

* @param tag
*/
public Builder(OnCardClickListener listener, String tag) {
mCard = new Card();
mCard.mTag = tag;
mCard.mClickListener = listener;
}

public Builder setTitle(String title) {


mCard.mTitle = title;
return this;
}

public Builder setDescription(String desc) {


mCard.mDescription = desc;
return this;
}

/**
* Add an action.
* The type describes how this action will be displayed. Accepted values are
* {@link #ACTION_NEUTRAL}, {@link #ACTION_POSITIVE} or {@link
#ACTION_NEGATIVE}.
*
* @param label The text to display for this action
* @param id Identifier for this action, supplied in the click listener
* @param type UI style of action
* @return
*/
public Builder addAction(String label, int id, int type) {
mCard.addAction(label, id, type);
return this;
}

/**
* Override the default layout.
* The referenced layout file has to contain the same identifiers as defined in the
default

* layout configuration.
* @param layout
* @return
* @see R.layout.card
*/
public Builder setLayout(int layout) {
mCard.mLayoutId = layout;
return this;
}

/**
* Set the type of progress bar to display.
* Accepted values are:
* <ul>
* <li>{@link #PROGRESS_TYPE_NO_PROGRESS} disables the progress
indicator</li>
*

<li>{@link #PROGRESS_TYPE_NORMAL}

displays a standard, linear progress indicator.</li>

* <li>{@link #PROGRESS_TYPE_INDETERMINATE} displays an


indeterminate (infite) progress
*

indicator.</li>

* <li>{@link #PROGRESS_TYPE_LABEL} only displays a label text in the


progress area
*

of the card.</li>

* </ul>
*
* @param progressType
* @return
*/
public Builder setProgressType(int progressType) {
mCard.setProgressType(progressType);
return this;
}

public Builder setProgressLabel(String label) {


// ensure the progress layout has been initialized, use 'no progress' by default
if (mCard.mCardProgress == null) {
mCard.setProgressType(PROGRESS_TYPE_NO_PROGRESS);

}
mCard.mCardProgress.label = label;
return this;
}

public Builder setProgressMaxValue(int maxValue) {


// ensure the progress layout has been initialized, use 'no progress' by default
if (mCard.mCardProgress == null) {
mCard.setProgressType(PROGRESS_TYPE_NO_PROGRESS);
}
mCard.mCardProgress.maxValue = maxValue;
return this;
}

public Builder setStatus(int status) {


mCard.setState(status);
return this;
}

public Card build(Activity activity) {


LayoutInflater inflater = activity.getLayoutInflater();
// Inflating the card.
ViewGroup cardView = (ViewGroup) inflater.inflate(mCard.mLayoutId,
(ViewGroup) activity.findViewById(R.id.card_stream), false);

// Check that the layout contains a TextView with the card_title id


View viewTitle = cardView.findViewById(R.id.card_title);
if (mCard.mTitle != null && viewTitle != null) {
mCard.mTitleView = (TextView) viewTitle;
mCard.mTitleView.setText(mCard.mTitle);
} else if (viewTitle != null) {
viewTitle.setVisibility(View.GONE);
}

// Check that the layout contains a TextView with the card_content id


View viewDesc = cardView.findViewById(R.id.card_content);
if (mCard.mDescription != null && viewDesc != null) {

mCard.mDescView = (TextView) viewDesc;


mCard.mDescView.setText(mCard.mDescription);
} else if (viewDesc != null) {
cardView.findViewById(R.id.card_content).setVisibility(View.GONE);
}

ViewGroup actionArea = (ViewGroup)


cardView.findViewById(R.id.card_actionarea);

// Inflate Progress
initializeProgressView(inflater, actionArea);

// Inflate all action views.


initializeActionViews(inflater, cardView, actionArea);

mCard.mCardView = cardView;
mCard.mOverlayView = cardView.findViewById(R.id.card_overlay);

return mCard;
}

/**
* Initialize data from the given card.
* @param card
* @return
* @see Card#createShallowClone()
*/
public Builder cloneFromCard(Card card) {
mCard = card.createShallowClone();
return this;
}

/**
* Build the action views by inflating the appropriate layouts and setting the text and
* values.
* @param inflater

* @param cardView
* @param actionArea
*/
private void initializeActionViews(LayoutInflater inflater, ViewGroup cardView,
ViewGroup actionArea) {
if (!mCard.mCardActions.isEmpty()) {
// Set action area to visible only when actions are visible
actionArea.setVisibility(View.VISIBLE);
mCard.mActionAreaView = actionArea;
}

// Inflate all card actions


for (final CardAction action : mCard.mCardActions) {

int useActionLayout = 0;
switch (action.type) {
case Card.ACTION_POSITIVE:
useActionLayout = R.layout.card_button_positive;
break;

case Card.ACTION_NEGATIVE:
useActionLayout = R.layout.card_button_negative;
break;
case Card.ACTION_NEUTRAL:
default:
useActionLayout = R.layout.card_button_neutral;
break;
}

action.actionView = inflater.inflate(useActionLayout, actionArea, false);


Button actionButton = (Button)
action.actionView.findViewById(R.id.card_button);

actionButton.setText(action.label);
actionButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mCard.mClickListener.onCardClick(action.id, mCard.mTag);
}

});
actionArea.addView(action.actionView);
}
}

/**
* Build the progress view into the given ViewGroup.
*
* @param inflater
* @param actionArea
*/
private void initializeProgressView(LayoutInflater inflater, ViewGroup actionArea)
{

// Only inflate progress layout if a progress type other than NO_PROGRESS was
set.
if (mCard.mCardProgress != null) {
//Setup progress card.
View progressView = inflater.inflate(R.layout.card_progress, actionArea,
false);

ProgressBar progressBar =
(ProgressBar) progressView.findViewById(R.id.card_progress);
((TextView) progressView.findViewById(R.id.card_progress_text))
.setText(mCard.mCardProgress.label);
progressBar.setMax(mCard.mCardProgress.maxValue);
progressBar.setProgress(0);
mCard.mCardProgress.progressView = progressView;
mCard.mCardProgress.setProgressType(mCard.getProgressType());
actionArea.addView(progressView);
}
}
}

/**
* Represents a clickable action, accessible from the bottom of the card.
* Fields include the label, an ID to specify the action that was performed in the
callback,
* an action type (positive, negative, neutral), and the callback.
*/

public class CardAction {

public String label;


public int id;
public int type;
public View actionView;

public CardAction createShallowClone() {


CardAction actionClone = new CardAction();
actionClone.label = label;
actionClone.id = id;
actionClone.type = type;
return actionClone;
// Not the view. Never the view (don't want to hold view references for
// onConfigurationChange.
}

/**
* Describes the progress of a {@link Card}.
* Three types of progress are supported:
* <ul><li>{@link Card#PROGRESS_TYPE_NORMAL: Standard progress bar with
label text</li>
* <li>{@link Card#PROGRESS_TYPE_INDETERMINATE}: Indeterminate
progress bar with label txt</li>
* <li>{@link Card#PROGRESS_TYPE_LABEL}: Label only, no progresss bar</li>
* </ul>
*/
public class CardProgress {
private int progressType = Card.PROGRESS_TYPE_NO_PROGRESS;
private String label = "";
private int currProgress = 0;
private int maxValue = 100;

public View progressView = null;


private ProgressBar progressBar = null;
private TextView progressLabel = null;

public CardProgress createShallowClone() {


CardProgress progressClone = new CardProgress();
progressClone.label = label;
progressClone.currProgress = currProgress;
progressClone.maxValue = maxValue;
progressClone.progressType = progressType;
return progressClone;
}

/**
* Set the progress. Only useful for the type {@link
#PROGRESS_TYPE_NORMAL}.
* @param progress
* @see android.widget.ProgressBar#setProgress(int)
*/
public void setProgress(int progress) {
currProgress = progress;
final ProgressBar bar = getProgressBar();

if (bar != null) {
bar.setProgress(currProgress);
bar.invalidate();
}
}

/**
* Set the range of the progress to 0...max.
* Only useful for the type {@link #PROGRESS_TYPE_NORMAL}.
* @param max
* @see android.widget.ProgressBar#setMax(int)
*/
public void setMax(int max) {
maxValue = max;
final ProgressBar bar = getProgressBar();
if (bar != null) {
bar.setMax(maxValue);
}

/**
* Set the label text that appears near the progress indicator.
* @param text
*/
public void setProgressLabel(String text) {
label = text;
final TextView labelView = getProgressLabel();
if (labelView != null) {
labelView.setText(text);
}
}

/**
* Set how progress is displayed. The parameter must be one of three supported
types:
* <ul><li>{@link Card#PROGRESS_TYPE_NORMAL: Standard progress bar
with label text</li>
* <li>{@link Card#PROGRESS_TYPE_INDETERMINATE}:

* Indeterminate progress bar with label txt</li>


* <li>{@link Card#PROGRESS_TYPE_LABEL}: Label only, no progresss
bar</li>
* @param type
*/
public void setProgressType(int type) {
progressType = type;
if (progressView != null) {
switch (type) {
case PROGRESS_TYPE_NO_PROGRESS: {
progressView.setVisibility(View.GONE);
break;
}
case PROGRESS_TYPE_NORMAL: {
progressView.setVisibility(View.VISIBLE);
getProgressBar().setIndeterminate(false);
break;
}
case PROGRESS_TYPE_INDETERMINATE: {

progressView.setVisibility(View.VISIBLE);
getProgressBar().setIndeterminate(true);
break;
}
}
}
}

private TextView getProgressLabel() {


if (progressLabel != null) {
return progressLabel;
} else if (progressView != null) {
progressLabel = (TextView)
progressView.findViewById(R.id.card_progress_text);
return progressLabel;
} else {
return null;
}
}

private ProgressBar getProgressBar() {


if (progressBar != null) {
return progressBar;
} else if (progressView != null) {
progressBar = (ProgressBar) progressView.findViewById(R.id.card_progress);
return progressBar;
} else {
return null;
}
}

}
}

CardLayout.java

package com.example.android.batchstepsensor;

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
import android.widget.RelativeLayout;

/**
* Custom Button with a special 'pressed' effect for touch events.
*/
public class CardLayout extends RelativeLayout {

private boolean mSwiping = false;


private float mDownX = 0.f;
private float mDownY = 0.f;

private float mTouchSlop = 0.f;

public CardLayout(Context context) {


super(context);
init();
}

public CardLayout(Context context, AttributeSet attrs) {


super(context, attrs);
init();
}

public CardLayout(Context context, AttributeSet attrs, int defStyle) {


super(context, attrs, defStyle);
init();
}

private void init(){


setFocusable(true);

setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);
setWillNotDraw(false);
setClickable(true);

mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop() * 2.f;


}

@Override
public boolean onTouchEvent(MotionEvent event) {
switch(event.getAction()){
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
mSwiping = false;
break;
}
return super.onTouchEvent(event);
}

@Override
public boolean onInterceptTouchEvent(MotionEvent event) {

switch(event.getAction()){
case MotionEvent.ACTION_MOVE:
if( !mSwiping ){
mSwiping = Math.abs(mDownX - event.getX()) > mTouchSlop;
}
break;
case MotionEvent.ACTION_DOWN:
mDownX = event.getX();
mDownY = event.getY();
mSwiping = false;
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
mSwiping = false;
break;
}

return mSwiping;
}
}

Screen Shots

Testing
Create a Test Case
Activity tests are written in a structured way. Make sure to put your tests in a
separate package, distinct from the code under test.
By convention, your test package name should follow the same name as the
application package, suffixed with ".tests". In the test package you created, add
the Java class for your test case. By convention, your test case name should also
follow the same name as the Java or Android class that you want to test, but
suffixed with Test.
To create a new test case in Eclipse:
a. In the Package Explorer, right-click on the /src directory for test project and
select New > Package.
b. Set the Name field to <your_app_package_name>.tests (for example,
com.example.android.testingfun.tests) and click Finish.
c. Right-click on the test package you created, and select New > Class.
d. Set the Name field to <your_app_activity_name>Test (for example,
MyFirstTestActivityTest) and click Finish.

Set Up Your Test Fixture


A test fixture consists of objects that must be initialized for running one or more
tests. To set up the test fixture, you can override the setUp() and tearDown()
methods in this test. The test runner automatically runs setUp() before running any
other test methods, and tearDown() at the end of each test method execution. It
can use these methods to keep the code for test initialization and clean up separate
from the tests methods.
As a sanity check, it is good practice to verify that the test fixture has been set up
correctly, and the objects that you want to test have been correctly instantiated or
initialized. That way, wont have to see tests failing because something was wrong
with the setup of your test fixture. By convention, the method for verifying test
fixture is called testPreconditions().

The assertion methods are from the JUnit Assert class. Generally, you can use
assertions to verify if a specific condition that you want to test is true.
If the condition is false, the assertion method throws an
AssertionFailedError exception, which is then typically reported by the
test runner. You can provide a string in the first argument of your assertion
method to give some contextual details if the assertion fails.
If the condition is true, the test passes.

Build and Run Your Test


build and run project test easily from the Package Explorer in Eclipse.
To build and run your test:
1. Connect an Android device to your machine. On the device or emulator, open
the Settings menu, select Developer options and make sure that USB
debugging is enabled.
2. In the Project Explorer, right-click on the test class that created earlier and
select Run As > Android Junit Test.
3. In the Android Device Chooser dialog, select the device that just connected,
then click OK.
4. In the JUnit view, verify that the test passes with no errors or failures.

In both cases, the test runner proceeds to run the other test methods in the test
case.

Creating Unit Tests


An Activity unit test is an excellent way to quickly verify the state of an Activity
and its interactions with other components in isolation (that is, disconnected from
the rest of the system). A unit test generally tests the smallest possible unit of code
(which could be a method, class, or component), without dependencies on system
or network resources. For example, you can write a unit test to check that an
Activity has the correct layout or that it triggers an Intent object correctly.
Unit tests are generally not suitable for testing complex UI interaction events with
the system. Instead, you should use the ActivityInstrumentationTestCase2
class, as described in Testing UI Components.

MAINTENANCE
Maintenance of Android Application

- Install a good ROM and a good Kernel


Official ROMs are good but custom ROMs are usually faster and in many cases as stable as
official ROMs. This is because ROMs are released and thereafter rarely change, custom ROMs
are already made by developers who are constantly improving their job to get the most out of the
phone. It's very important to research before installing a new ROM, searching always for the one
that meets expectations and relates well with device since the same ROM can work very well
on my x10 but not as well on x10 my brothers for example.
The same goes for Kernels, but with Kernels take extra care to make sure that the Kernel is
compatible with desired ROM and phone.
- Keep clean caches
Caches are good to keep certain information and have access to these faster but with these files
and information some "garbage" is stored .
The solutions to this can be pretty basic or advanced, the most basic way is to enter Application
Manager (Settings> Applications> Manage Applications) and clear the cache for each
application. It is important to clear the cache only and not application data as these may be
important such as the files that resemble progress in a game. Already the most advanced solution
is to clear the Dalvik Cache and Cache Partition through recovery.
Both solutions dont need to be made with daily frequency, for example I usually clean my
caches every 45 days or when I feel that the phone is getting slow.
- Make a full, but clean, backup
Full backups (full system backup) like those made by recovery or nandroid are great to store
complete setups but when they are done with dirty files in the the phones memory restoring
these files may worsen rather than help the situation of device .
Ideally, do a full backup after completely configure phone (configure account, set homescreens,
install the required applications, etc.) but before using it for real.

That way if phone starts getting slow and nothing works to reverse the situation it can easily go
back to it's original settings without the hassle of customizing everything in its way again.
Expence scheduler- Do not touch the CPU / GPU the first day
Like people, phones also take a while to adapt to a new environment, or in our case new ROMs,
so during the first 24 hours of use is important to use the settings of CPU and GPU that came
with the ROM, no overclock, undervolt and things like that.
Another important step in the process of adaptation to the new ROM is really using and
exploring the device in this very first day so it "get used" to the change. Do not mind the battery
consumption, that should stabilize after a few days.
Its also iimportant to remember that some ROMs already comes with overclock, undervolt and
improvements in battery usage. In this case there is no problem in using these settings from the
first minute because if they are there since the installation of the ROM, it is because they are part
of the default settings already programmed and develop on this particular ROM and it will work
better this way.
- Use the maximum battery
Batteries seem to last less and less as time goes on, in part this is because battery is uncalibrated
and there are ways to fix it.
- Applications: less is more
Having millions of apps is the glory and the doom of smartphones, the glory because it can do
everything on device and doom because of the following reasons:
As a computer a phone also slows down theu as it becomes full and in most cases blame it on
the number of apps that havebeen installed on it. So try to leave installed only the applications
actually use and uninstall the ones that no longer use so can have more free memory and
consequently a faster device.
Some applications can not be uninstalled because they are system applications; in order to
remove those apps are going to need uninstallers that have root access (ex: RootUninstaller)
which are capable of removing these applications but before taking such a measure is necessary
to look for a safelist (a list of applications that can be removed without causing system
problems).

Keeping a low number of applications but doing so by installing and uninstalling new apps every
day also usually let the machine slower so if it find an application for a specific function that fits
needs one should stay with it instead of testing another 10 before returning to it.
PS: A good way to avoid testing several applications before finding the right one is reading
reviews and comments before making onece choice.
- Repair defective applications
Often the phone is working fine but a certain application or function is not, which can cause
slowdowns and FCs (force close); depending on the situation there is not much to do but some of
these solutions may take care of the problem:
The first thing to do is to uninstall and reinstall the apps via Play Store to make sure that the
problem was not caused by a corrupted file when downloaded the application, if the problem
persists there are some more advanced alternatives: in the advanced settings of recovery select
fix permissions, this function should make sure that every application has the necessary
permissions to work properly.
- Keep some free space
Full memory is often a problem on any device, especially in older phones like ours, after all the
more files the longer it takes read all these files if it is necessary, so the tip is this: the more free
space the better.
- Avoid keeping some applications running all the time
Its very common to close an application and assume that it stopped running on the system but
this is not always the case because it actually still cached in the memory of the device, Android
makes it to be faster on reopening it later and often the system itself definitively closes the
application automatically but thats not always the case.
Firstly it is important to prevent certain applications from even opening and to do this we use
apps known as Startup Managers, there are several options in the Play Store but I particularly
like Auto starts. Once inside the Start up Manager one can choose which applications will be
opened as the system is started or any action is taken (for example changing the state of your WiFi); the ideal is to minimize the number of self-starting applications, leaving only the truly
necessary ones without forgetting to be very careful to avoid stopping system applications

because if they are unable to open themselves it can cause instability. Another way to prevent
applications from opening or stay on cache all the time is to disable automatic updates of apps
such as email clients and social networks but this is a more personal matter that varies from user
to user,
It's easy to know when to quit an application completely but it is necessary to first understand a
basic concept about the system: applications and processes cached in memory are not always a
bad thing, in fact as stated at the beginning of the topic they are a good thing because the
application should open faster when launched again (hence the use of Task Killers usually
worsens more than help if not done properly) but if use an application to view the weather every
morning and will only use it again the next morning this application can be closed without
problems.

CONCLUSION
As it is intended the to create an apps in android which will help us to track the
location and change of location while a person carrying a smart phone commute
from one place to another within a closed environment was created successfully
using the internal sensors embedded in the smart phones like geometric field
sensors API, position sensors API, proximity sensors, motion sensors and
accelerometer which are all coming with android to enable as GPS (Global
Positioning System) navigation systems. It has been utilized to detect the current
position and in case of changing position into an vector and calculating the speed
of monitor using the distance, displace and time taken for that displacement.
This Project can be kept as the base for many of the future development for
navigation system and application which can be developed to assist differently
enabled persons.

Future Enhancements
As this is sensor based application which deduct the location and provide guidance
using the various parameters of motion of the device, the future enhancement can
be made in many ways like integrating the expert system and training that expert
system the an application which can guide physically challenged people in a
known environments. Also it can be used to determine various aspects of biokinetic and and Bio-mechanical factors of the user, it will give way to develop
Applications which provide guidance and monitoring on the above parameters.

BIBLIOGRAPHY

Google inc 2014, Android Quick Start Guide


Frank Zammetti -2013. Apress,Specifications of Pro IOS and Android
Apps for Business: With Jquery Mobile, Node.Js, and Mongodb

Ian F. Darwin-2013, Shroff-O'Reilly,Android Cookbook: Problems


and Solutions for Android Developers

https://developer.android.com

www.tutorialspoint.com

You might also like