Advertisment

Android Tutorial: Keep Track of Mobiles Through SMS

author-image
PANKAJ
New Update

When was the last time you used your mobile phone? Was it 2 minutes back? 10 minutes back? 30 minutes back? 1 hour back? Likely. Was it 2 hours back? 4 hours back? Unlikely. Unless it is your sleep time, or, unless something is wrong. Well, it looks like when you last used your phone is an important piece of information for someone interested in your welfare. This article is a continuation of the previous two articles published in PCQuest describing a safety application. The location part of the application (where are you?) was published in December 2013 and the illumination part of the application (how much light?) was published in MARCH 2014. Here we take you through writing an application that responds to an SMS message enquiring when you last used your mobile phone.

Application's Logic

When we say ‘used your mobile' here, we mean physical access. Typically that would mean you have picked up your phone or are moving around with your phone. You might not have dialed a number or clicked a photograph or even unlocked your phone. The application would consider that as long as you are physically moving the phone, all is well. Dialing and clicking is definitely counted as usage, at the same time, picking the phone from the table and putting it in your pocket is also considered usage.

The application relies on sensors that sense the orientation of your device. As you keep moving your device, it's X, Y and Z axis orientations keep changing. Now we will write an application that will note the date and time whenever the device orientation changes. And the application will respond to an SMS with the last saved date and time, which was when you last used your phone.

Coding the App

Open the SafetyMessages application that we developed in the previous articles. Unlike the previous modules which were checking the location or the illumination after receiving the SMS, this module will require a service to be always running which will keep noting the date and time whenever the orientation changes. We will start the service when the device boots, so that in every reboot the service starts again.

Grant the android.permission.RECEIVE_BOOT_COMPLETED permission. We will also need a receiver class that responds to the boot event. Add a BroadcastReceiver derived class with the name BootReceiver. Add the following lines to the manifest.

Advertisment











Create a Service derived class named OrienationService. The receiver class will start this service. Add the new service to the manifest. Go back to the BootReceiver class and in the onReceive() method add the following lines:

Intent itnStart = new Intent(context, OrientationService.class);

context.startService(itnStart);

Advertisment

We typically calculate a device's orientation by using two sensors: magnetic field sensors and accelerometers. Define the following class level variables for the new service class.

private float<> accelerometerValues;

private float<> magneticFieldValues;

private boolean blnAccelerometer = false;

private boolean blnMagnetic = false;

public static long lngTimeOld = 0;

private static int intXOld, intYOld, intZOld;

private static final String X = "X";

private static final String Y = "Y";

private static final String Z = "Z";

private static final String MOVED_TIME = "MOVED_TIME";

private static SharedPreferences prefs;

private SensorManager sm;

Also add the sensors. We listen for change in the values of the sensors by using sensor event listeners.

Advertisment

final SensorEventListener myAccelerometerListener = new SensorEventListener() {

@Override

public void onSensorChanged(SensorEvent event) {

if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {

accelerometerValues = event.values;

blnAccelerometer = true;

}

}

@Override

public void onAccuracyChanged(Sensor sensor, int accuracy) {

// TODO Auto-generated method stub

Advertisment

}

};

final SensorEventListener myMagmeticFieldListener = new SensorEventListener() {

@Override

public void onSensorChanged(SensorEvent event) {

// TODO Auto-generated method stub

if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {

magneticFieldValues = event.values;

blnMagnetic = true;

saveOrientation();

}

}

Advertisment

@Override

public void onAccuracyChanged(Sensor sensor, int accuracy) {

// TODO Auto-generated method stub

}

};

We will now create a method that checks the newly recorded orientation with the previously recorded orientation and saves the orientation if there is a change. We will call the method saveOrientation(). We are checking that both the sensors have indicated a change before proceeding with saving the orientation by using Boolean variables. We are then rounding off the orientation values to the nearest multiples of ten by doing an integer division with 10 and multiplying the result by 10. As the sensors are extremely sensitive, you may get false movements without actually using the device. The rounding off will prevent over sensitivity. The following method is being invoked by the sensor listeners.

Advertisment

private void saveOrientation(){

float<> values = new float<3>;

float<> R1 = new float<9>;

int intX, intY, intZ;

long lngTime;

GregorianCalendar calendar = new GregorianCalendar(TimeZone.getDefault());

if (blnAccelerometer && blnMagnetic) {

if (SensorManager.getRotationMatrix(R1, null, accelerometerValues, magneticFieldValues)) {

SensorManager.getOrientation(R1, values);

intX = Math.round((float)Math.toDegrees(values<0>));

intY = Math.round((float)Math.toDegrees(values<1>));

intZ = Math.round((float)Math.toDegrees(values<2>));

intX = (intX / 10) * 10;

intY = (intY / 10) * 10;

intZ = (intZ / 10) * 10;

getPreferences();

if (lngTimeOld == 0) {

savePreferences(intX, intY, intZ, System.currentTimeMillis());

}

if (sameOrientation(intX, intY, intZ, intXOld, intYOld, intZOld)) {

}

else {

lngTime = System.currentTimeMillis();

savePreferences(intX, intY, intZ, lngTime);

calendar.setTimeInMillis(lngTime);

}

}

else {

}

}

else {

}

}

We will be saving changes to the orientation using the Shared Preferences concept of Android. The previous method saves the orientation by invoking

the savePreferences() method, which we are going to define now.

private void savePreferences(int intX, int intY, int intZ, long lngTime) {

Editor editor = prefs.edit();

editor.putInt(X, intX);

editor.putInt(Y, intY);

editor.putInt(Z, intZ);

editor.putLong(MOVED_TIME, lngTime);

editor.commit();

}

Advertisment

Add the getPreferences() method. It will extract the saved preference andstore it in a class level static variable. The saveOrientation() method invokes getPreferences() to find out the old orientation values to compare with the new orientation values retrieved by the sensors.

public static void getPreferences() {

intXOld = prefs.getInt(X, 0);

intYOld = prefs.getInt(Y, 0);

intZOld = prefs.getInt(Z, 0);

lngTimeOld = prefs.getLong(MOVED_TIME, 0);

}

The saveOrientation() method calls the sameOrientation() method to check if the new orientation is different from the old orientation. To offset the hypersensitivity of the sensors, we will say that a change of 20 on only one axis or a change of 10 on two axes is not a change, in other words, the orientation has not changed.

private boolean sameOrientation(int X1, int Y1, int Z1, int X2, int Y2, int Z2) {

if (X1 == X2 && Y1 == Y2 && Z1 == Z2)

return(true);

// A change in only one axis of 20 degrees is not a change, it could be a rounding off error, or calibration

if (X1 == X2 && Y1 == Y2 && (Z1 - Z2 <= 20 || Z2 - Z1 <= 20))

return(true);

if (X1 == X2 && (Y1 - Y2 <= 20 || Y2 - Y1 <= 20) && Z1 == Z2)

return(true);

if ((X1 - X2 <= 20 || X2 - X1 <= 20) && Y1 == Y2 && Z1 == Z2)

return(true);

// A change in two axes of 10 degrees is not a change, it could be a rounding off error

if (X1 == X2 && (Y1 - Y2 == 10 || Y2 - Y1 == 10) && (Z1 - Z2 == 10 || Z2 - Z1 == 10))

return(true);

if ((X1 - X2 == 10 || X2 - X1 == 10) && Y1 == Y2 && (Z1 - Z2 == 10 || Z2 - Z1 == 10))

return(true);

if ((X1 - X2 == 10 || X2 - X1 == 10) && (Y1 - Y2 == 10 || Y2 - Y1 == 10) && Z1 == Z2)

return(true);

return(false);

}

Add the onStartCommand() method. This method will register the sensor listeners and save the first orientation and changes will be subsequently noted from this orientation by the listeners.

@Override

public int onStartCommand(Intent intent, int flags, int startId) {

super.onStartCommand(intent, flags, startId);

sm = (SensorManager)getSystemService(Context.SENSOR_SERVICE);

Sensor aSensor = sm.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);

Sensor mfSensor = sm.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);

prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());

sm.registerListener(myAccelerometerListener, aSensor, SensorManager.SENSOR_DELAY_UI);

sm.registerListener(myMagmeticFieldListener, mfSensor, SensorManager.SENSOR_DELAY_UI);

saveOrientation();

return START_STICKY;

}

In the SMS Receiver class, declare the following class level variable. This variable will define the string that will be used in the SMS message to query for when you last used your phone. You can define the value of this variable to be any other string of your choice.

private final String WHENLASTACCESSED = "#WhenLastAccessed#";

In the onReceive() method of the SMS Receiver, in addition to checking for where are you and how much light, we will now also check for when last accessed, and if that message is received, respond with the last saved time. The last saved time is extracted from the static member of the service class.

if (strMessage.equals(WHENLASTACCESSED)) {

SmsManager smsAccess = SmsManager.getDefault();

OrientationService.getPreferences();

SimpleDateFormat sdfMessage = new SimpleDateFormat("dd-MM-yyyy;HH:mm:ss", Locale.getDefault());

smsAccess.sendTextMessage(strFrom, null, sdfMessage.format(OrientationService.lngTimeOld), null, null);

}

That completes the application. You would need to keep the mobile stationary for some time while you are testing the application by sending an SMS from another handset to check if you are getting the right date and time when you last used the first handset. For finding out more information about the sensors and listeners, you can use your favorite search engine and dive into the literature available on the internet. I have not spent time on explaining the concepts here. By adding this new functionality of finding out when the phone was last used, we have come up with an informative safety application.

Advertisment