+ All Categories
Home > Documents > Batch Step Sensor android Project

Batch Step Sensor android Project

Date post: 07-Oct-2015
Category:
Upload: syam-babu
View: 27 times
Download: 0 times
Share this document with a friend
Description:
Android Batch Step Sensor Project Report

of 112

Transcript

PROJECT FORMAT

PROJECT FORMATABSTRACT

INTRODUCTION

FEASIBILITY STUDY

SYSTEM ANALYSIS

Existing system

Proposed system

SYSTEM REQUIREMENTS

Software requirements

Hardware requirements

DATA FLOW DIAGRAMS

ABOUT THE LANGUAGE (FRONT-END AND BACK-END)

SOURCE CODE (its in Microsoft word for documentation)

SCREEN SHOTS (same as above)

TESTING

MAINTENANCE

CONCLUSION

FUTURE ENHANCEMENTS

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 detectorandstep 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 sensorsgive 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 STUDYAs 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 FeasibilityThis 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 ANALYSISExisting SystemThe 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 non-batch 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 REQUIREMENTSHARDWRE 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 aboveSoftware RequirementsEither 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 androidControl Flow Diagram

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.javapackage 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;

}

}

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 mCardActions = new ArrayList();

/**

* 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:

*

  • *
  • {@link #PROGRESS_TYPE_NO_PROGRESS} disables the progress indicator *
  • {@link #PROGRESS_TYPE_NORMAL}

    * displays a standard, linear progress indicator.

    *
  • {@link #PROGRESS_TYPE_INDETERMINATE} displays an indeterminate (infite) progress

    * indicator.

    *
  • {@link #PROGRESS_TYPE_LABEL} only displays a label text in the progress area

    * of the card.

    *

*

* @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:

*

  • {@link Card#PROGRESS_TYPE_NORMAL: Standard progress bar with label text *
  • {@link Card#PROGRESS_TYPE_INDETERMINATE}: Indeterminate progress bar with label txt *
  • {@link Card#PROGRESS_TYPE_LABEL}: Label only, no progresss bar *

*/

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:

*

  • {@link Card#PROGRESS_TYPE_NORMAL: Standard progress bar with label text *
  • {@link Card#PROGRESS_TYPE_INDETERMINATE}:

    * Indeterminate progress bar with label txt

    *
  • {@link Card#PROGRESS_TYPE_LABEL}: Label only, no progresss bar * @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.javapackage 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 ShotsTestingCreate a Test CaseActivity 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:In the Package Explorer, right-click on the /src directory for test project and select New > Package. Set the Name field to .tests (for example, com.example.android.testingfun.tests) and click Finish. Right-click on the test package you created, and select New > Class. Set the Name field to Test (for example, MyFirstTestActivityTest) and click Finish. Set Up Your Test FixtureA 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: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. In the Project Explorer, right-click on the test class that created earlier and select Run As > Android Junit Test. In the Android Device Chooser dialog, select the device that just connected, then click OK. 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 TestsAn 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.MAINTENANCEMaintenance of Android Application - Install a good ROM and a good KernelOfficial 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 cachesCaches 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, backupFull 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 dayLike 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 batteryBatteries 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 moreHaving 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 applicationsOften 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 spaceFull 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 timeIts 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 Wi-Fi); 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.CONCLUSIONAs 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 c

Recommended