Is it possible to measure the how far the phone travels vertically

前端 未结 3 1433
没有蜡笔的小新
没有蜡笔的小新 2021-02-09 05:02

I\'m just wondering if it is possible / where would I get started in measuring the upwards and downwards movement of an Android device. I\'d need it to be as accurate as possibl

3条回答
  •  梦毁少年i
    2021-02-09 05:54

    Before going to solution, I would split the solution in small assets and put the puzzle for solution

    1. We need to listen to phone sensors
    2. We need to check phone is in vertical position or not
    3. We need to make a time counter that register the phone vertically and count up
    4. We need to display the time on screen

    For step one, I would implement SensorEventListener to our class, this will allow us to use onSensorChanged method.

    @Override
    public void onSensorChanged(SensorEvent event) {
        if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
            listenToSensors(event);
        }
    }
    
    private void listenToSensors(SensorEvent event) {
        if (isPhoneVertical(event)) {
            timeCounter();
            if (mStatus) {
                mStartTime = getStartTime();
                mStatus = false;
            }
        } else {
            if (!mStatus) {
                mTotalTime = getDiffTime() + mTotalTime;
                mStatus = true;
            }
        }
    }
    

    For step two, I have built a method called isPhoneVertical to check if our phone is in vertical way or not, it is primarily checking the y axis. You can change the steep degree by changing maxVertical. Less value her less steep, 0 means the phone should almost be 100% vertical. For my test it is set to 3.

    private boolean isPhoneVertical(SensorEvent event) {
        float[] values = event.values;
        double y = values[1];
        // do not change this value
        double yAxisInitValue = 10.0;
        double verMargin = yAxisInitValue - maxVertical;
    
        return y >= verMargin;
    }
    

    For step 3 I have made few method to check start time and stop time and update a global variable that keep track of time in seconds.

    private long getStartTime() {
        return System.currentTimeMillis() / 1000;
    }
    
    private long getDiffTime() {
        return getStartTime() - mStartTime;
    }
    

    For step 4 I have made a regular runOnUiThread to update the time on screen.

    private void timeCounter() {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                mView1.setText("Phone has been vertical for: " + getDiffTime() + " seconds");
                mView2.setText("The total time: " + (mTotalTime + getDiffTime()) + "");
            }
        });
    }
    

    That said this solution is to illustrate how this goal can be reached, I am sure it can be done different ways. But I wanted to show the logic behind the solution.

    And here is a screen shot of the app that counts the time for each time the phone is vertical and total time it has been vertical.

    The solution including some explanations:

    MainActivity.java

    public class MainActivity extends Activity implements SensorEventListener {
        private SensorManager mSensorManager;
        private Sensor mAccelerometer;
        private TextView mView1, mView2;
        private long mStartTime;
        private long mTotalTime;
        private boolean mStatus = true;
        // less value her less steep, 0 means the phone should almost be 100% vertical
        // try it out
        private double maxVertical = 3.0;
    
        @Override
        public void onCreate(Bundle savedInstanceState) {
            requestWindowFeature(Window.FEATURE_NO_TITLE);
            getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                    WindowManager.LayoutParams.FLAG_FULLSCREEN);
    
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            mView1 = (TextView) findViewById(R.id.textView1);
            mView2 = (TextView) findViewById(R.id.textView2);
    
            mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
            mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
        }
    
        @Override
        public void onSensorChanged(SensorEvent event) {
            if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
                listenToSensors(event);
            }
        }
    
        private void listenToSensors(SensorEvent event) {
            if (isPhoneVertical(event)) {
                timeCounter();
                if (mStatus) {
                    mStartTime = getStartTime();
                    mStatus = false;
                }
            } else {
                if (!mStatus) {
                    mTotalTime = getDiffTime() + mTotalTime;
                    mStatus = true;
                }
            }
        }
    
        // This method return true only for specific phone orientation
        // y axis for vertical orientation
        private boolean isPhoneVertical(SensorEvent event) {
            float[] values = event.values;
            double y = values[1];
            // do not change this value
            double yAxisInitValue = 10.0;
            double verMargin = yAxisInitValue - maxVertical;
    
            return y >= verMargin;
        }
    
        private long getStartTime() {
            return System.currentTimeMillis() / 1000;
        }
    
        private long getDiffTime() {
            return getStartTime() - mStartTime;
        }
    
        // update steps in user interface
        private void timeCounter() {
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    mView1.setText("Phone has been vertical for: " + getDiffTime() + " seconds");
                    mView2.setText("The total time: " + (mTotalTime + getDiffTime()) + "");
                }
            });
        }
    
        @Override
        public void onAccuracyChanged(Sensor sensor, int accuracy) {
    
        }
    
        @Override
        protected void onResume() {
            super.onResume();
            mSensorManager.registerListener(this,
                    mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
                    SensorManager.SENSOR_DELAY_NORMAL);
        }
    
        @Override
        protected void onPause() {
            super.onPause();
            // if you want to collect data while mobile screen off, just disable the
            // following line, the app will still collecting sensor data
            mSensorManager.unregisterListener(this);
        }
    }
    

    Activity_main.xml

    
    
    
        
    
        
    
    

    I will leave some link for reading as well.

    • https://developer.android.com/reference/android/hardware/SensorManager.html
    • http://www.livescience.com/40103-accelerometer-vs-gyroscope.html
    • https://physics.stackexchange.com/questions/41653/how-do-i-get-the-total-acceleration-from-3-axes
    • https://code.tutsplus.com/tutorials/how-to-recognize-user-activity-with-activity-recognition--cms-25851
    • http://www.vogella.com/tutorials/AndroidSensor/article.html
    • How to get Android phone orientation matching human orientation?

    If you think I might add more information that can help you further with your question please let me know. It is also unclear if you was looking for walking detection/counter, if that is some thing you are interesting in, look at following answers/links.

    • Activity Recognition Api
    • How to detect walking with Android accelerometer
    • how to calculate exact foot step count using accelerometer in android?
    • Detect Movement Accurately using Accelerometer in Android

    and GitHub source codes

    • https://github.com/bagilevi/android-pedometer
    • https://github.com/tartakynov/robowalk

提交回复
热议问题