Monitoring apps, How Does Android Sensors work

Published:
Mobile monitoring is no longer news for developers. Monitoring apps are used for several reasons and are usually divided into 2 categories: spying and monitoring.
Spyware allows you to secretly check someone else phone activity remotely. This includes personal calls, text messages, browsing history etc. Monitoring in its turn is used to track smartphone activity of underage children and senior people who live alone.

In this article, we will ignore the reason why people track each others phones but study the technical part. We will start with Android sensor.

There are 3 main categories of the Android sensor: the movement, the surrounding environment, and of course location.
 
The first one is accelerometer. It tells your ‘g-force’ or in other words proper acceleration. This one is majorly used to identify motion, which refers to tilt and shake.
 
Accelerometer usage in mobile monitoring is practically used by caregivers to track their senior parents who live alone. Accelerometer helps you detect falling velocity so one can check if the person who is being tracked falls down. If he/she falls, a caretaker receives an alert message in form of SMS or an email.
 
Google Android Compatibility Manager Dan Morrill explains the usage of API in 3 easy rules:
 
  1. The coordinate system of a sensor never changes when the identical API is used.
  2. Natural orientation cannot be portrait at all times.
  3. android.view.Display.getRotation is used by applications which match with data of the sensor with display.
Moving on to the practical usage.
 
Let’s take SensorEventListener to get SensorManager notifications when values of the sensor change. As our goal is to test a shake motion, locking the orientation of the device is required.
 
public class MainActivity extends AppCompatActivity implements View.OnClickListener, SensorEventListener {
                       
                          private static final String LOG_TAG = "MainActivity";
                       
                          private static final int SENSITIVITY = 300;
                          private static final int SPEED_MULTIPLIER = 10000;
                          private static final int MOVEMENT_TIMEOUT = 100;
                       
                          private SensorManager mSensorManager;
                          private Sensor mAccelerationSensor;
                          private TransitionDrawable mTransitionDrawable;
                       
                          private TextView vTextLatitude;
                          private TextView vTextLongitude;
                          private TextView vTextAddress;
                       
                          private boolean mColorTransitionReverseDirection;
                          private long mLastTime = 0;
                          private float mLastX;
                          private float mLastY;
                          private float mLastZ;
                       
                          @Override
                          protected void onCreate(Bundle savedInstanceState) {
                              super.onCreate(savedInstanceState);
                              Log.d(LOG_TAG, "onCreate");
                              setContentView(R.layout.activity_main);
                       
                              mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
                              mAccelerationSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
                              mSensorManager.registerListener(this, mAccelerationSensor, SensorManager.SENSOR_DELAY_UI);
                       
                              RelativeLayout mainLayout = (RelativeLayout) findViewById(R.id.layout_mainPage);
                              Button vBtnLocation = (Button) findViewById(R.id.btn_locationUpdate);
                              vBtnLocation.setOnClickListener(this); // check onClick() method in class
                       
                              vTextLatitude = (TextView) findViewById(R.id.text_latitudeValue);
                              vTextLongitude = (TextView) findViewById(R.id.text_longitudeValue);
                              vTextAddress = (TextView) findViewById(R.id.text_addressValue);
                       
                              Intent locationIntent = new Intent(this, LocationUpdateService.class);
                              startService(locationIntent);
                       
                              mTransitionDrawable = (TransitionDrawable) mainLayout.getBackground();
                          }
                       
                      }

Open in new window

The sensors of the system are quite sensitive. If holding, you will find that it is always in motion, even if the hand is steady. Such data should be omitted. We need to store the exact time of the system presented in milliseconds to see how much time has passed since onSensorChanged has been invoked. We start with 100 milliseconds.
 
Moving on, you can add this code to the MainActivity:
 
@Override
                      public void onSensorChanged(SensorEvent event) {
                          Sensor sensor = event.sensor;
                          if (sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
                              float x = event.values[0];
                              float y = event.values[1];
                              float z = event.values[2];
                              Log.d(LOG_TAG, "Coordinates: x=" + x + ", y=" + y + ", z=" + z);
                              long now = System.currentTimeMillis();
                              if ((now - mLastTime) > MOVEMENT_TIMEOUT) {
                                  long timePassed = (now - mLastTime);
                                  mLastTime = now;
                                  double speed = Math.sqrt(Math.pow(x - mLastX, 2) + Math.pow(y - mLastY, 2) + Math.pow(z - mLastZ, 2))/ timePassed * SPEED_MULTIPLIER;
                                  if (speed > SENSITIVITY) {
                                      Log.d(LOG_TAG, "onSensorChanged enough");
                                      if (mColorTransitionReverseDirection) {
                                          mTransitionDrawable.reverseTransition(1000);
                                      } else {
                                          mTransitionDrawable.startTransition(1000);
                                      }
                                      mColorTransitionReverseDirection = !mColorTransitionReverseDirection;
                                  }
                                  // saving last coordinates
                                  mLastX = x;
                                  mLastY = y;
                                  mLastZ = z;
                              }
                          }
                      }
                       
                      @Override
                      public void onAccuracyChanged(Sensor sensor, int accuracy) { /* do nothing */}

Open in new window

It is wise to keep the sensor unregistered for the time when the app hibernates in order to save battery power. Now insert  these functions to the MainActivity class:
 
protected void onPause() {   
                        super.onPause();
                          mSensorManager.unregisterListener(this);
                      }
                      protected void onResume() {
                          super.onResume();
                          mSensorManager.registerListener(this, mAccelerationSensor, SensorManager.SENSOR_DELAY_UI);
                      }

Open in new window

To improve the readability onClick method is carried separately. The method is used to get coordinates and location addresses when clicked on a suitable button.   
 
@Override
                      public void onClick(View v) {
                          Log.d(LOG_TAG, "onClick");
                          if (LocationUpdateService.sLastLocation != null) {
                              double latitude = LocationUpdateService.sLastLocation.getLatitude();
                              double longitude = LocationUpdateService.sLastLocation.getLongitude();
                              vTextLatitude.setText(String.valueOf(latitude));
                              vTextLongitude.setText(String.valueOf(longitude));
                              // try to get address by coordinates
                              Geocoder gCoder = new Geocoder(this, Locale.ENGLISH);
                              try {
                                  // we don't need more than 1 result
                                  List<Address> addressList = gCoder.getFromLocation(latitude, longitude, 1);
                                  if (addressList != null && !addressList.isEmpty()) {
                                      // we use StringBuilder to ease multiple string concatenation
                                      StringBuilder addressBuilder = new StringBuilder();
                                      Address resultAddress = addressList.get(0);
                                      for (int i = 0; i < resultAddress.getMaxAddressLineIndex(); i++) {
                                          addressBuilder.append(resultAddress.getAddressLine(i));
                                          addressBuilder.append(" ");
                                      }
                                      vTextAddress.setText(addressBuilder.toString());
                                  } else {
                                      Log.e(LOG_TAG, "There's no appropriate address for such location");
                                  }
                              } catch (IOException e) {
                                  Log.e(LOG_TAG, "Error in Geocoder work " + e);
                              }
                          }
                      }
                       

Open in new window

The Android sensor allows us to check real-time location of the user in the main plain locations.
The person who owns the application can check it anytime there is the 3G/4G network or Wi-Fi.
GPS uses satellite radio indicators to receive data. In such an application an assisted global positioning system - the AGPS is used instead of GPS. It happens so because these network towers are designed with built in GPS receivers to increase the speed of the signal. These towers receive data from the satellites and then resend it to the smartphones with prior computation handled. At the end we can see:
  1.                 Prompt Location acquisition
  2.                 Decrease of battery use
  3.                 location acquisition indoor
 
To start with we need to add the AndroidManifest.xml file:
 
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
                      package="com.test.androidsensorabilities" >
                          <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
                          <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
                          <uses-permission android:name="android.permission.INTERNET" />
                          <application
                             ...
                          </application>
                      </manifest>

Open in new window

We will make our location calculations based on the background service. Create a new LocationUpdateService.java and add the following. Next, we will request updates of the location from providers, the network and the GPS to get all-round data. Keep in mind that we omit the listeners when not in use.
 
public class LocationUpdateService extends Service {
                      private static final String LOG_TAG = "LocationUpdateService";
                          private static final int TIME_DIFF = 1000; // in millis
                          private static final float DISTANCE_DIFF = 10; // in meters
                          public static Location sLastLocation; // store last location info we got
                          private LocationManager mLocationManager;
                          private LocationListener mNetworkLocationListener = new LocationListener(LocationManager.NETWORK_PROVIDER);
                          private LocationListener mGpsLocationListener = new LocationListener(LocationManager.GPS_PROVIDER);
                       
                          @Nullable
                          @Override
                          public IBinder onBind(Intent intent) {
                              return null;
                          }
                       
                          @Override
                          public void onCreate() {
                              Log.d(LOG_TAG, "onCreate");
                              if (mLocationManager == null) {
                                  mLocationManager = (LocationManager) getApplicationContext().getSystemService(Context.LOCATION_SERVICE);
                              }
                       
                              try {
                                  mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, TIME_DIFF, DISTANCE_DIFF, mGpsLocationListener);
                              } catch (java.lang.SecurityException e) {
                                  Log.w(LOG_TAG, "Cannot request location", e);
                              } catch (IllegalArgumentException e) {
                                  Log.w(LOG_TAG, "GPS provider is disabled", e);
                              }
                       
                              try {
                                  mLocationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, TIME_DIFF, DISTANCE_DIFF, mNetworkLocationListener);
                              } catch (java.lang.SecurityException e) {
                                  Log.w(LOG_TAG, "Cannot request location", e);
                              } catch (IllegalArgumentException e) {
                                  Log.w(LOG_TAG, "Network provider is disabled", e);
                              }
                          }
                          @Override
                          public void onDestroy() {
                              Log.d(LOG_TAG, "onDestroy");
                              if (mLocationManager != null) {
                                  mLocationManager.removeUpdates(mGpsLocationListener);
                                  mLocationManager.removeUpdates(mNetworkLocationListener);
                              }
                              super.onDestroy();
                          }
                      }

Open in new window

 We are adding the LocationListener internal class, which will respond to the changes in location and save the received data for exploitation.
 
 
private class LocationListener implements android.location.LocationListener {   
                      public LocationListener(String provider) {
                              sLastLocation = new Location(provider);
                          }
                          @Override
                          public void onLocationChanged(Location location) {
                              Log.d(LOG_TAG, "onLocationChanged: latitude=" + location.getLatitude() + ", longitude=" + location.getLongitude());
                              // saving current location
                              sLastLocation.set(location);
                          }
                          @Override
                          public void onProviderDisabled(String provider) { }
                          @Override
                          public void onProviderEnabled(String provider) { }
                          @Override
                          public void onStatusChanged(String provider, int status, Bundle extras) { }
                      }

Open in new window

One more important thing to keep in mind is to use a real smartphone not the emulator when testing the application. Make sure you shake the device to check the accelerometer and click on the button which updates the phone in order to receive the data on the current location of the tracked phone. If having troubles viewing location, enable ‘high accuracy’.
 
This is a brief guide to the Android sensors. This time we took location and movement.
 
0
864 Views

Comments (0)

Have a question about something in this article? You can receive help directly from the article author. Sign up for a free trial to get started.