Due: Tuesday June 2, end of day.
This application detects whether someone moved your phone while you left it somewhere. The UI is as below:
The app tells you if the phone was moved. When you start the app, it waits 30 seconds before starting to detect motion. Then, it remembers if someone has moved the phone. When you get back and use the phone again, it tells you whether the phone has been moved.
When you start the app, it should create a background service running in its own thread. You might want to take the code of ServiceExample (https://bitbucket.org/luca_de_alfaro/services-example) as starting point for the code. The background service remembers the time T0 when it has been started, and listen to the acceleration, using a listener that is very similar to the one used in Assignment 5. For simplicity, we don't really detect movement, but only whether the phone was moved away from a flat position, that is, we detect if there is significant acceleration in the x or y directions. Read just the acceleration in the x and y axes, so you don't have to worry about removing the effect of gravity; in any case it's unlikely that a curious housemate manages to pick up the phone and keep it completely horizontal.
The service remembers in a variable first_accel_time
the time when the first significant acceleration occurred. When you start the service, you should set first_accel_time
= null. Whenever the service detects that there is acceleration above the significance threshold at time T1, it does as follows:
first_accel_time
= T1 (here, I assume T1 is an object e.g. a Date; this is just the idea, it is up to you to adapt it and make it become code). The service has a method, that can be called from the activity. The method is used to check if someone moved the phone at least 30 seconds ago, to give you time to pick the phone up and check. The method does something like this (this is not code, it's just to give you the idea):
public boolean didItMove() {
Date d = new Date();
boolean moved = false;
synchronized(myLock) {
if (first_accel_time != null && d - first_accel_time > 30 seconds) {
moved = true;
}
}
return moved;
}
Above, myLock is used because first_accel_time
is an object (might be of type Date for instance) or a long, and those types do not have atomic update in Java. Another alternative would be to do without the lock, and declare first_accel_time to be of type AtomicLong. See the tutorial I posted.
When the activity executed onResume, it must do the following:
didItMove
to the Service, which calls didItMove
in the ServiceTask (as in the sample code I gave you, you need to relay the call from Activity to Service to ServiceTask). This tells the activity if the phone was moved; update UI accordingly. When someone presses the CLEAR button, the activity should call the service, and the service should:
When someone presses the EXIT button, the activity should unbind and stop from the process, then exit. You can exit from an activity by calling finish().
Note: when the activity executes onPause, it should unbind from the process, but it should NOT stop it! If you stop the service in onPause, onStop, or onDestroy, then the phone cannot detect whether it's being moved if the screen goes off, or if the person moving it exits from the app by pressing the Home button.
The only thing that should stop the service is the EXIT button.
On most phones, the above will work fine. On some phones, though, the sensor updates will cease after a while after the phone goes to sleep. To force the phone to keep the CPU on, we acquire a WakeLock. Use these lines:
In the onStartCommand
method of the service:
PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
Wakelock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
"MyWakelockTag");
wakeLock.acquire();
In the onDestroy of the Service:
wakeLock.release();
Note that you need to ask permission in AndroidManifest.xml in order to use the wakelock. See the documentation I linked.