Welcome to the Treehouse Community
Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.
Looking to learn something new?
Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.
Start your free trial
Akash malhotra
3,025 PointsShake detector Fun facts
I want to implement a shake detector in my Fun Facts app, so that the user can either click the button or shake the phone to go to the next fact. I'm new to android and having difficulty understanding how to implement transitions on this simple app. I understand how the button works because it's built in. I got this shakedetector,java file from a previous retired project in Treehouse, and I'm unable to watch the video from that retired section for some reason.
This is the shake detector.
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
public class ShakeDetector implements SensorEventListener {
// Minimum acceleration needed to count as a shake movement
private static final int MIN_SHAKE_ACCELERATION = 5;
// Minimum number of movements to register a shake
private static final int MIN_MOVEMENTS = 2;
// Maximum time (in milliseconds) for the whole shake to occur
private static final int MAX_SHAKE_DURATION = 500;
// Arrays to store gravity and linear acceleration values
private float[] mGravity = { 0.0f, 0.0f, 0.0f };
private float[] mLinearAcceleration = { 0.0f, 0.0f, 0.0f };
// Indexes for x, y, and z values
private static final int X = 0;
private static final int Y = 1;
private static final int Z = 2;
// OnShakeListener that will be notified when the shake is detected
private OnShakeListener mShakeListener;
// Start time for the shake detection
long startTime = 0;
// Counter for shake movements
int moveCount = 0;
// Constructor that sets the shake listener
public ShakeDetector(OnShakeListener shakeListener) {
mShakeListener = shakeListener;
}
@Override
public void onSensorChanged(SensorEvent event) {
// This method will be called when the accelerometer detects a change.
// Call a helper method that wraps code from the Android developer site
setCurrentAcceleration(event);
// Get the max linear acceleration in any direction
float maxLinearAcceleration = getMaxCurrentLinearAcceleration();
// Check if the acceleration is greater than our minimum threshold
if (maxLinearAcceleration > MIN_SHAKE_ACCELERATION) {
long now = System.currentTimeMillis();
// Set the startTime if it was reset to zero
if (startTime == 0) {
startTime = now;
}
long elapsedTime = now - startTime;
// Check if we're still in the shake window we defined
if (elapsedTime > MAX_SHAKE_DURATION) {
// Too much time has passed. Start over!
resetShakeDetection();
}
else {
// Keep track of all the movements
moveCount++;
// Check if enough movements have been made to qualify as a shake
if (moveCount > MIN_MOVEMENTS) {
// It's a shake! Notify the listener.
mShakeListener.onShake();
// Reset for the next one!
resetShakeDetection();
}
}
}
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// Intentionally blank
}
private void setCurrentAcceleration(SensorEvent event) {
/*
* BEGIN SECTION from Android developer site. This code accounts for
* gravity using a high-pass filter
*/
// alpha is calculated as t / (t + dT)
// with t, the low-pass filter's time-constant
// and dT, the event delivery rate
final float alpha = 0.8f;
// Gravity components of x, y, and z acceleration
mGravity[X] = alpha * mGravity[X] + (1 - alpha) * event.values[X];
mGravity[Y] = alpha * mGravity[Y] + (1 - alpha) * event.values[Y];
mGravity[Z] = alpha * mGravity[Z] + (1 - alpha) * event.values[Z];
// Linear acceleration along the x, y, and z axes (gravity effects removed)
mLinearAcceleration[X] = event.values[X] - mGravity[X];
mLinearAcceleration[Y] = event.values[Y] - mGravity[Y];
mLinearAcceleration[Z] = event.values[Z] - mGravity[Z];
/*
* END SECTION from Android developer site
*/
}
private float getMaxCurrentLinearAcceleration() {
// Start by setting the value to the x value
float maxLinearAcceleration = mLinearAcceleration[X];
// Check if the y value is greater
if (mLinearAcceleration[Y] > maxLinearAcceleration) {
maxLinearAcceleration = mLinearAcceleration[Y];
}
// Check if the z value is greater
if (mLinearAcceleration[Z] > maxLinearAcceleration) {
maxLinearAcceleration = mLinearAcceleration[Z];
}
// Return the greatest value
return maxLinearAcceleration;
}
private void resetShakeDetection() {
startTime = 0;
moveCount = 0;
}
/*
* Definition for OnShakeListener definition. I would normally put this
* into it's own .java file, but I included it here for quick reference
* and to make it easier to include this file in our project.
*/
public interface OnShakeListener {
public void onShake();
}
}
Here are my files:
Here are the files:
colorwheel.java:
package com.iamakash.funfacts;
import android.graphics.Color;
import java.util.Random;
/**
* Created by akash on 2015-07-26.
*/
public class colorwheel {
public String[] mcolors = {
"#39add1",
"#3079ab",
"#c25975",
"#e15258",
"#f9845b",
"#838cc7",
"#7d669e",
"#53bbb4",
"#51b46d",
"#e0ab18",
"#637a91",
"#f092b0",
"#b7c0c7",
"#4169E1",
"#F0F8FF",
"#FFEBCD",
"#F5F5DC",
"#FFE4C4 ",
"#000000",
"#FFEBCD",
"#0000FF",
"#8A2BE2",
};
public int getcolor(){
//button clicked, update with new fact
String COLOR = "";
//randomly select fact
Random randomGenerator = new Random();
int randomNumber = randomGenerator.nextInt(mcolors.length);
COLOR=mcolors[randomNumber];
int colorAsInt= Color.parseColor(COLOR);
return colorAsInt;
}
}
factbook.java:
import java.util.Random;
public class factBook {
public String[] mfacts = {
"Ants stretch when they wake up in the morning.",
"Ostriches can run faster than horses.",
"Olympic gold medals are actually made mostly of silver.",
"You are born with 300 bones; by the time you are an adult you will have 206.",
"It takes about 8 minutes for light from the Sun to reach Earth.",
"Some bamboo plants can grow almost a meter in just one day.",
};
public String getFact(){
//button clicked, update with new fact
String fact = "";
//randomly select fact
Random randomGenerator = new Random();
int randomNumber = randomGenerator.nextInt(mfacts.length);
fact=mfacts[randomNumber];
return fact;
}
}
MainActivity.Java:
import android.app.Activity;
import android.app.DatePickerDialog;
import android.graphics.Color;
import android.support.v7.app.ActionBar;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.RelativeLayout;
import android.widget.TextView;
import java.util.*;
public class FunFactsActivity extends Activity {
private factBook mFactBook=new factBook();
private colorwheel mcolorwheel= new colorwheel();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fun_facts);
//declare view variables
final TextView factlabel = (TextView) findViewById(R.id.facttextView);
final Button showFactButton = (Button) findViewById(R.id.showfactbutton);
final RelativeLayout relativeLayout=(RelativeLayout) findViewById(R.id.relativeLayout);
View.OnClickListener Listener = new View.OnClickListener() {
@Override
public void onClick(View view) {
String fact= mFactBook.getFact();
//update label with dynamic fact
factlabel.setText(fact);
int color=mcolorwheel.getcolor();
relativeLayout.setBackgroundColor(color);
};
};
showFactButton.setOnClickListener(Listener);
};
};
Can someone explain where I would implement the shake detector. Thanks!
1 Answer
adamghani
7,955 PointsHi Akash!
I think what you're doing is a cool addition to the Fun Facts app!
Ok, it looks like you're all set up, you just need to utilize the ShakeDetector.OnShakeListener.onShake() method in order for you to show a new fact.
before jumping into this code, read this doc on SensorManager and make sure to check out the code snippet.
public class FunFactsActivity extends Activity {
...
private ShakeDetector mShakeDetector;
private SensorManager mSensorManager;
private Sensor mAccelerometer;
...
@Override
protected void onCreate(Bundle savedInstanceState) {
....
mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
mShakeDetector = new ShakeDetector(new ShakeDetector.OnShakeListener() {
@Override
public void onShake() {
showFact();
}
});
}
...
@Override
protected void onResume() {
super.onResume();
mSensorManager.registerListener(mShakeDetector, mAccelerometer, SensorManager.SENSOR_DELAY_UI);
// Registers (mShakeDetector which implements) SensorEventListener
}
@Override
protected void onPause() {
mSensorManager.unregisterListener(mShakeDetector);
super.onPause();
}
}
For best practice, add uses-feature for the accelerometer in AndroidManifest.xml
<uses-feature android:name="android.hardware.sensor.accelerometer" android:required="true"/>
Reference: http://stackoverflow.com/a/11972661/3743265 Ben's Answer :-)
feel free to leave me a comment on this Answer if something doesn't make sense.
Good luck and happy coding! :-)
Akash malhotra
3,025 PointsAkash malhotra
3,025 PointsThanks for the response! So, the code you provided, is that to be added in between my code? Also, how would i be able to test this on the android emulator, since I can't physically shake it
Akash malhotra
3,025 PointsAkash malhotra
3,025 PointsI can't figure it out, I'm getting so many errors, can you help me fix the code please!. Okay, so I have a file "ShakeDetector.java" which contains the first code snippet I posted in the question. What do I put in the FunFactsActivity.java file??
This is what I have so far, I tried combining your code with what I had before ( scroll up to see in question post).
Note: * Remember, I want user to be able to click the button AND shake the device, to go to the next fact*
I'm getting red errors on the "Onresume" and "Onpause" methods, as well as Public void OnClick, as well as the last
"showFactButton.setOnClickListener(Listener);"
I really appreciate your help, please respond ASAP=)
adamghani
7,955 Pointsadamghani
7,955 Points"Thanks for the response! So, the code you provided, is that to be added in between my code? Also, how would i be able to test this on the android emulator, since I can't physically shake it"
Yes, the code that i posted is to be added in with your FunFactsActivity.java class. as for the emulator accelerometer question, I think Genymotion can do that, you have to check, my advice is to post this question on another thread, because its another question and you'll get more answers :-).
"Note: * Remember, I want user to be able to click the button AND shake the device, to go to the next fact"
Your first question was "user can either click the button or shake the phone to go to the next fact" , i'm confused, so i'll continue assuming that its an OR, if that isn't the case and you want the user to press the button AND(then) shake then you just need to create a flag that you turn on if the button is pressed and when there is a shake, show the new fact if the flag is on and then reset the flag to false.
This is the complete java class, you just need to copy and paste it. but, i highly recommend for you to go through the Java course here at Team Treehouse, because you have some basic Java mistake & bad practices.
I hope this helps. Good luck ! :-)