Android CS323 Cornez

Lab 7: Working with Sensors



Exercise 1: Detecting a Shake/Jerk Gesture

    Construct an app that toggles a lightbulb on and off when the user shakes or jerks their device.

activity_main.xml




MyShakeListener.java




MainActivity.java






Exercise 2: Roaming Bee (or Ball) using the Accelerometer.

This app is created in the textbook Lab Example 8-1
  1. Construct an application containing a bee (or the ball shown below). You can add TextViews to the main layout to provide accelerometer readings.

  2. When the application first launches, the user is presented with the bee or ball positioned at a specific x, y location on the screen.
  3. The TextViews are helpful, as they display the x, y, and z-axis readings from the accelerometer.
  4. As the user tilts and rotates the device, the text fileds will be updatedto show the current accelerometer readings.
  5. In addition, the ball will move in accordance with the tilt and roll of the device, as shown in the figure.
  6. The ball will not be allowed to roll off screen, and will be deterred by the virtual boundaries of the screen.

Bee.java (or Ball.java)




MainActivity.java (Needs to be completed)






Exercise 3: Geomagnetic Rotation - Compass

. Implement a geomagnetic rotation vector for measuring the orientation of an Android device relative to a north, south, east, and west direction.

  1. A geomagnetic rotation vector sensor is a composite sensor that will be defined by the accelerometer in tandem with the magnetometer. The application may need to specify each feature in a separate a uses-feature element within the Manifest file.
  2. Indicate that motion readings will occur from an accelerometer and directional readings from a magnetometer (compass) on the device.
  3. Set a portrait screen orientation for the application.
  4. Use your own art creation for the compass image.


Exercise 4: Fling a Billiard Ball


This exercise allows users to fling a billiard ball across the screen in any direction. When the billiard ball hits the edges of the screen, it reverses direction as if it is bouncing off a wall. Friction should be applied to movement so that the ball eventually comes to a halt.

Research GestureDetector and OnGestureListener.
    Question 1: How is the velocity of a fling detected?
    Question 2: Can the velocity of a fling be detected across just the x-axis?
    Question 3: Identify the callback methods used to detect gestures.


NOTE: Rename billiardball so that it reads ball.


Create the following files:
ball_layout.xml
    This XML file is an ImageView layout that holds the billiardball.png.



main_layout.xml
    This XML file is an main activity layout. Specify the root View as a FrameLayout.
    Set the background to table.png.
    Set the id to frameLayout.
    NOTE: The FrameLayout uses a coordinate system with 0,0 in the center.



Ball.java
        public class Ball {
          public int mX;
          public int mY;
          public int mRadius;
          public double mVelocityX;
          public double mVelocityY;
          public int left, right, top, bottom;
    
          public Ball(int mX, int mY, int mRadius, double mVelocityX, double mVelocityY){
            this.mX = mX;
            this.mY = mY;
            this.mRadius = mRadius;
            this.mVelocityX = mVelocityX;
            this.mVelocityY = mVelocityY;
          }
    
          public void move(){
            mX += mVelocityX;
            mY += mVelocityY;
    
            //COLLISIONS - REVERSE DIRECTIONS
            if (mX < left){
              mX = left;
              mVelocityX *= -1;
            }
            else if (mX > right){
              mX = right;
              mVelocityX *= -1;
            }
            if (mY < top){
              mY = top;
              mVelocityY *= -1;
            }
            else if (mY > bottom){
              mY = bottom;
              mVelocityY *= -1;
            }
    
            //APPLY FRICTION TO THE VELOCITY
            mVelocityX *= .93;
            mVelocityY *= .93;
            if (Math.abs(mVelocityX) < 1) mVelocityX = 0;
            if (Math.abs(mVelocityY) < 1) mVelocityY = 0;
    
          }
          public void setCollisionBoundaries( int windowWidth, int windowHeight){
            left = -windowWidth / 2 + mRadius;
            right = windowWidth / 2 - mRadius;
            top = -windowHeight / 2 + mRadius;
            bottom = windowHeight / 2 - mRadius;
          }
        }
    
      


MainActivity.java
        import android.content.Context;
        import android.os.Bundle;
        import android.os.Handler;
        import android.support.v7.app.AppCompatActivity;
        import android.util.DisplayMetrics;
        import android.view.GestureDetector;
        import android.view.LayoutInflater;
        import android.view.MotionEvent;
        import android.view.Window;
        import android.view.WindowManager;
        import android.widget.FrameLayout;
        import android.widget.ImageView;
    
        public class MainActivity extends AppCompatActivity implements GestureDetector.OnGestureListener {
    
          private GestureDetector aGesture;
    
          private FrameLayout mainLayout;
          private Thread backgroundThread;
          private ImageView ballImageView;
          private Ball mBall;
    
          private int left, right, top, bottom;
    
          @Override
          protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
    
            //TASK 1: SET THE LAYOUT AND THE WINDOW ELEMENTS
            requestWindowFeature(Window.FEATURE_NO_TITLE);
            getSupportActionBar().hide();
            setContentView(R.layout.main_layout);
            getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
            mainLayout = (FrameLayout) findViewById(R.id.frameLayout);
    
            //TASK 2: CREATE A BILLIARD BALL
            buildBilliardBall();
    
            //TASK 3: CREATE A GESTURE DETECTOR
            aGesture = new GestureDetector(this, this);
    
            //TASK 4: CREATE THE BACKGROUND THREAD
            backgroundThread = new Thread(calculateAction);
            backgroundThread.start();
          }
    
          private void buildBilliardBall() {
            //TASK 1: THE CREATE THE DATA MODEL FOR THE BILLIARD BALL
            mBall = new Ball(0, 0, 150, 0, 0);
            DisplayMetrics metrics = new DisplayMetrics();
            getWindowManager().getDefaultDisplay().getMetrics(metrics);
            mBall.setCollisionBoundaries(metrics.widthPixels, metrics.heightPixels);
    
            //TASK 2: CREATE A LAYOUT INFLATER TO ADD THE BILLIARD BALL IMAGEVIEW TO THE LAYOUT
            LayoutInflater layoutInflater;
            layoutInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    
            //TASK 3: ADD THE BALL TO THE LAYOUT
            ballImageView = (ImageView) layoutInflater.inflate(R.layout.ball_layout, null);
            ballImageView.setScaleX((float) .3);
            ballImageView.setScaleY((float) .3);
            ballImageView.setX((float) mBall.mX);
            ballImageView.setY((float) mBall.mY);
            mainLayout.addView(ballImageView, 0);
          }
    
    
          //**************** RUNNABLE **********************
          private Runnable calculateAction = new Runnable() {
            private static final int DELAY = 50;
            public void run() {
              try {
                while (true) {
                  mBall.move();
                  Thread.sleep(DELAY);
                  threadHandler.sendEmptyMessage(0);
                }
              } catch (InterruptedException e) {
              }
            }
          };
          //****** HANDLER FOR UPDATING THE IMAGEVIEW CONTAINING THE BILLIARD BALL******
          public Handler threadHandler = new Handler() {
            public void handleMessage(android.os.Message msg) {
              //UPDATE BALL LOCATION
              ballImageView.setX((float) mBall.mX);
              ballImageView.setY((float) mBall.mY);
            }
          };
    
    
    
          //***********************TOUCH GESTURES*************************
          @Override
          public boolean onTouchEvent(MotionEvent event) {
            return aGesture.onTouchEvent(event);
          }
          @Override
          public boolean onFling(MotionEvent event1, MotionEvent event2, float velocityX, float velocityY) {
            final float ADJUST = 0.025f;
            mBall.mVelocityX = (int) velocityX * ADJUST;
            mBall.mVelocityY = (int) velocityY * ADJUST;
            return true;
          }
          @Override
          public void onLongPress(MotionEvent event) {}
          @Override
          public void onShowPress(MotionEvent event) {}
          @Override
          public boolean onDown(MotionEvent event) {return false;}
          @Override
          public boolean onScroll(MotionEvent e1, MotionEvent e2,float distanceX, float distanceY) {return false;}
          @Override
          public boolean onSingleTapUp(MotionEvent event) {return false;}
        }