/*
Copyright (C) 2011 - 2012, Dirk Trossen, airs@dirk-trossen.de
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation as version 2.1 of the License.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this library; if not, write to the Free Software Foundation, Inc.,
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.airs.handlers;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;
import java.util.concurrent.Semaphore;
import com.airs.AIRS_record_tab;
import com.airs.R;
import com.airs.helper.SerialPortLogger;
import com.airs.platform.HandlerManager;
import com.airs.platform.History;
import com.airs.platform.SensorRepository;
import android.app.ActivityManager;
import android.app.ActivityManager.MemoryInfo;
import android.app.ActivityManager.RunningServiceInfo;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.database.ContentObserver;
import android.database.Cursor;
import android.net.Uri;
import android.os.BatteryManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.PhoneLookup;
import android.telephony.SmsMessage;
import android.telephony.TelephonyManager;
import android.util.Log;
/**
* Class to read system related sensors, specifically the Ba, BV, Bc, BM, Rm, Sc, HS, IC, OC, SR, SS, TR, TV, TE sensor
* @see Handler
*/
public class SystemHandler implements com.airs.handlers.Handler
{
private static final int INIT_BATTERY = 1;
private static final int INIT_SCREEN = 2;
private static final int INIT_HEADSET = 3;
private static final int INIT_PHONESTATE = 4;
private static final int INIT_OUTGOINGCALL = 5;
private static final int INIT_SMSRECEIVED = 6;
private static final int INIT_SMSSENT = 7;
private static final int INIT_TIMEZONE = 8;
static private final Uri SMS_STATUS_URI = Uri.parse("content://sms/");
private Context airs;
private int oldBattery = -1;
private int Battery = 0;
private int oldOffset = -1;
private int Offset = 0;
private int voltage = 0;
private int old_voltage = -1;
private int temperature = 0;
private int old_temperature = -1;
private int oldRAM = 0;
private int ScreenOn = 0;
private int oldScreenOn = -1;
private int battery_charging = 0;
private int oldbattery_charging = -1;
private int headset = 0, oldheadset = -1;
private String caller = null, callee = null, smsReceived = null, smsSent = null;
private boolean shutdown = false;
private int polltime = 5000;
private ActivityManager am;
private boolean startedTimeZone = false, startedBattery = false, startedScreen = false, startedHeadset = false;
private boolean startedPhoneState = false, startedOutgoingCall = false, startedSMSReceived = false, startedSMSSent = false;
private Semaphore battery_semaphore1 = new Semaphore(1);
private Semaphore battery_semaphore2 = new Semaphore(1);
private Semaphore battery_semaphore3 = new Semaphore(1);
private Semaphore screen_semaphore = new Semaphore(1);
private Semaphore charger_semaphore = new Semaphore(1);
private Semaphore headset_semaphore = new Semaphore(1);
private Semaphore caller_semaphore = new Semaphore(1);
private Semaphore callee_semaphore = new Semaphore(1);
private Semaphore received_semaphore = new Semaphore(1);
private Semaphore sent_semaphore = new Semaphore(1);
private Semaphore template_semaphore = new Semaphore(1);
private Semaphore timezone_semaphore = new Semaphore(1);
private SmsObserver smsSentObserver;
private void wait(Semaphore sema)
{
try
{
sema.acquire();
}
catch(Exception e)
{
}
}
/**
* Method to acquire sensor data
* Here, we start various receivers for system data upon first Acquire() call
* @param sensor String of the sensor symbol
* @param query String of the query to be fulfilled - not used here
* @see com.airs.handlers.Handler#Acquire(java.lang.String, java.lang.String)
*/
public byte[] Acquire(String sensor, String query)
{
byte[] readings = null;
int reading_value = 0;
boolean read = false, task_first;
StringBuffer buffer = null;
// are we shutting down?
if (shutdown == true)
return null;
read = false;
// recording template used?
if(sensor.compareTo("TZ") == 0)
{
// has timezone been started?
if (startedTimeZone == false)
{
// send message to handler thread to start timezone
Message msg = mHandler.obtainMessage(INIT_TIMEZONE);
mHandler.sendMessage(msg);
}
wait(timezone_semaphore); // block until semaphore available: it will block after the first usage since templates need only one reading!
if (Offset != oldOffset)
{
read = true;
reading_value = Offset;
oldOffset = Offset;
}
}
// recording template used?
if(sensor.compareTo("TE") == 0)
{
wait(template_semaphore); // block until semaphore available: it will block after the first usage since templates need only one reading!
// create Stringbuffer with template being used
buffer = new StringBuffer("TE");
buffer.append(AIRS_record_tab.current_template);
return buffer.toString().getBytes();
}
// battery level?
if(sensor.compareTo("Ba") == 0)
{
// has Battery been started?
if (startedBattery == false)
{
// send message to handler thread to start Battery
Message msg = mHandler.obtainMessage(INIT_BATTERY);
mHandler.sendMessage(msg);
}
wait(battery_semaphore1); // block until semaphore available
// any difference in value?
if (Battery != oldBattery)
{
read = true;
reading_value = Battery;
oldBattery = Battery;
}
}
// battery voltage?
if(sensor.compareTo("BV") == 0)
{
// has Battery been started?
if (startedBattery == false)
{
// send message to handler thread to start Battery
Message msg = mHandler.obtainMessage(INIT_BATTERY);
mHandler.sendMessage(msg);
}
wait(battery_semaphore2); // block until semaphore available
// any difference in value?
if (voltage != old_voltage)
{
read = true;
reading_value = voltage;
old_voltage = voltage;
}
}
// battery temperature?
if(sensor.compareTo("BM") == 0)
{
// has Battery been started?
if (startedBattery == false)
{
// send message to handler thread to start Battery
Message msg = mHandler.obtainMessage(INIT_BATTERY);
mHandler.sendMessage(msg);
}
wait(battery_semaphore3); // block until semaphore available
// any difference in value?
if (temperature != old_temperature)
{
read = true;
reading_value = temperature;
old_temperature = temperature;
}
}
// battery discharging?
if(sensor.compareTo("Bc") == 0)
{
// has Battery been started?
if (startedBattery == false)
{
// send message to handler thread to start Battery
Message msg = mHandler.obtainMessage(INIT_BATTERY);
mHandler.sendMessage(msg);
}
wait(charger_semaphore); // block until semaphore available
// any difference in value?
if (battery_charging != oldbattery_charging)
{
read = true;
reading_value = battery_charging;
oldbattery_charging = battery_charging;
}
}
// screen on/off?
if(sensor.compareTo("Sc") == 0)
{
// has Screen been started?
if (startedScreen == false)
{
// send message to handler thread to start Screen
Message msg = mHandler.obtainMessage(INIT_SCREEN);
mHandler.sendMessage(msg);
}
wait(screen_semaphore); // block until semaphore available
// any difference in value?
if (ScreenOn != oldScreenOn)
{
read = true;
reading_value = ScreenOn;
oldScreenOn = ScreenOn;
}
}
// headset plugged/unplugged?
if(sensor.compareTo("HS") == 0)
{
// has Headset been started?
if (startedHeadset == false)
{
// send message to handler thread to start Headset
Message msg = mHandler.obtainMessage(INIT_HEADSET);
mHandler.sendMessage(msg);
}
wait(headset_semaphore); // block until semaphore available
// any difference in value?
if (headset != oldheadset)
{
read = true;
reading_value = headset;
oldheadset = headset;
}
}
// received SMS?
if(sensor.compareTo("SR") == 0)
{
// has SMS received been started?
if (startedSMSReceived == false)
{
// send message to handler thread to start SMS receive
Message msg = mHandler.obtainMessage(INIT_SMSRECEIVED);
mHandler.sendMessage(msg);
}
wait(received_semaphore); // block until semaphore available
// any difference in value?
if (smsReceived != null)
{
// create Stringbuffer with sms number being sent
buffer = new StringBuffer("SR");
buffer.append(smsReceived.replaceAll("'","''"));
smsReceived = null;
return buffer.toString().getBytes();
}
}
// sent SMS?
if(sensor.compareTo("SS") == 0)
{
// has SMS received been started?
if (startedSMSSent == false)
{
// send message to handler thread to start SMS sent
Message msg = mHandler.obtainMessage(INIT_SMSSENT);
mHandler.sendMessage(msg);
}
wait(sent_semaphore); // block until semaphore available
// any difference in value?
if (smsSent != null)
{
// create Stringbuffer with sms number being sent
buffer = new StringBuffer("SS");
buffer.append(smsSent.replaceAll("'","''"));
smsSent = null;
return buffer.toString().getBytes();
}
else
SerialPortLogger.debug("SS sensor: buffer is NULL!");
}
// incoming call?
if(sensor.compareTo("IC") == 0)
{
// has PhoneState been started?
if (startedPhoneState == false)
{
// send message to handler thread to start PhoneState
Message msg = mHandler.obtainMessage(INIT_PHONESTATE);
mHandler.sendMessage(msg);
}
wait(caller_semaphore); // block until semaphore available
// any difference in value?
if (caller != null)
{
// create reading buffer with caller number
buffer = new StringBuffer("IC");
buffer.append(caller);
caller = null;
return buffer.toString().getBytes();
}
}
// outgoing call?
if(sensor.compareTo("OC") == 0)
{
// has Outgoing Call been started?
if (startedOutgoingCall == false)
{
// send message to handler thread to start Outgoing Call
Message msg = mHandler.obtainMessage(INIT_OUTGOINGCALL);
mHandler.sendMessage(msg);
}
wait(callee_semaphore); // block until semaphore available
// any difference in value?
if (callee !=null)
{
// create reading buffer with callee number
buffer = new StringBuffer("OC");
buffer.append(callee);
callee = null;
return buffer.toString().getBytes();
}
}
// RAM available?
if(sensor.compareTo("Rm") == 0)
{
try
{
MemoryInfo mi = new MemoryInfo();
am.getMemoryInfo(mi);
reading_value = (int)(mi.availMem / 1024L);
// reading_value = (int) Runtime.getRuntime().freeMemory();;
// any difference in value?
if (reading_value != oldRAM)
{
read = true;
oldRAM = reading_value;
}
}
catch(Exception err)
{
}
}
// Recently visited/started tasks?
if(sensor.compareTo("TR") == 0)
{
try
{
List<ActivityManager.RunningAppProcessInfo> processes;
ActivityManager.RunningAppProcessInfo pinfo;
String task;
PackageManager pm = airs.getPackageManager();
// get current tasks running
processes = am.getRunningAppProcesses();
// none???
if (processes == null)
return null;
// now create list
buffer = new StringBuffer("TR");
// start with first task
task_first=true;
int i;
for (i=0; i<processes.size(); i++)
{
pinfo = processes.get(i);
// is the process a foreground or perceptible one?
if (pinfo.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND)
{
// first task? -> then no \n at the end of it!
if (task_first == true)
task_first = false;
else
buffer.append("\n");
// get package name
task = pinfo.processName;
try
{
ApplicationInfo ai = pm.getApplicationInfo(task, 0);
task = (String)pm.getApplicationLabel(ai);
if (task != null)
buffer.append(task);
}
catch(Exception e)
{
}
}
}
return buffer.toString().getBytes();
}
catch(Exception err)
{
return null;
}
}
// Foreground tasks
if(sensor.compareTo("TV") == 0)
{
try
{
List<ActivityManager.RunningAppProcessInfo> processes;
List <RunningServiceInfo> services = am.getRunningServices(9999);
ActivityManager.RunningAppProcessInfo tinfo;
// get running services
// get current apps running
processes = am.getRunningAppProcesses();
// none???
if (processes == null)
return null;
// now create list
buffer = new StringBuffer("TV");
// start with first task
boolean process_first=true;
boolean found_service;
int i,j;
// run through all processes
for (i=0; i<processes.size(); i++)
{
tinfo = processes.get(i);
// is there at least one task visible?
if (tinfo.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE || tinfo.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_PERCEPTIBLE)
{
if (tinfo.processName != null)
{
found_service = false;
// go through all services to exclude services
for (j=0;j<services.size();j++)
{
if(services.get(j).process.compareTo(tinfo.processName) == 0)
{
if (services.get(j).clientCount == 0)
{
found_service = true;
break;
}
}
}
// found no service that is visible?
if (found_service == false)
{
try
{
// try to find the application label
ApplicationInfo ai = airs.getPackageManager().getApplicationInfo(tinfo.processName, 0);
String task = (String)airs.getPackageManager().getApplicationLabel(ai);
if (task != null)
if (task.trim().compareTo("")!=0)
{
// first task? -> then no \n at the end of it!
if (process_first == true)
process_first = false;
else
buffer.append("\n");
buffer.append(task.trim());
}
}
catch(Exception e)
{
}
}
}
}
}
return buffer.toString().getBytes();
}
catch(Exception err)
{
return null;
}
}
// anything read?
if (read == true)
{
readings = new byte[6];
readings[0] = (byte)sensor.charAt(0);
readings[1] = (byte)sensor.charAt(1);
readings[2] = (byte)((reading_value>>24) & 0xff);
readings[3] = (byte)((reading_value>>16) & 0xff);
readings[4] = (byte)((reading_value>>8) & 0xff);
readings[5] = (byte)(reading_value & 0xff);
return readings;
}
return null;
}
/**
* Method to share the last value of the given sensor
* @param sensor String of the sensor symbol to be shared
* @return human-readable string of the last sensor value
* @see com.airs.handlers.Handler#Share(java.lang.String)
*/
public String Share(String sensor)
{
// battery level?
if(sensor.compareTo("Ba") == 0)
return "The current battery is " + String.valueOf(oldBattery) + " %";
// battery voltage?
if(sensor.compareTo("BV") == 0)
return "The current battery voltage is " + String.valueOf(old_voltage) + " mV";
// battery temperature?
if(sensor.compareTo("BM") == 0)
return "The current battery temperature is " + String.valueOf(old_temperature) + " C";
// battery discharging?
if(sensor.compareTo("Bc") == 0)
if (oldbattery_charging ==1)
return "The battery is currently charging";
else
return "The battery is currently not charging";
// current RAM?
if(sensor.compareTo("Rm") == 0)
return "The currently available RAM is " + String.valueOf(oldRAM) + " kByte";
// headset plugged/unplugged?
if(sensor.compareTo("HS") == 0)
if (oldheadset ==1)
return "The headset is currently plugged in";
else
return "The headset is currently plugged in";
return null;
}
/**
* Method to view historical chart of the given sensor symbol
* @param sensor String of the symbol for which the history is being requested
* @see com.airs.handlers.Handler#History(java.lang.String)
*/
public void History(String sensor)
{
// battery level?
if(sensor.compareTo("Ba") == 0)
History.timelineView(airs, "Battery level [%]", "Ba");
// battery voltage?
if(sensor.compareTo("BV") == 0)
History.timelineView(airs, "Battery Voltage [mV]", "BV");
// battery temperature?
if(sensor.compareTo("BM") == 0)
History.timelineView(airs, "Battery Temperature [C]", "BM");
// current RAM?
if(sensor.compareTo("Rm") == 0)
History.timelineView(airs, "RAM [kByte]", "Rm");
}
/**
* Method to discover the sensor symbols support by this handler
* As the result of the discovery, appropriate {@link com.airs.platform.Sensor} entries will be added to the {@link com.airs.platform.SensorRepository}
* @see com.airs.handlers.Handler#Discover()
* @see com.airs.platform.Sensor
* @see com.airs.platform.SensorRepository
*/
public void Discover()
{
SensorRepository.insertSensor(new String("Ba"), new String("%"), airs.getString(R.string.BA_d), airs.getString(R.string.BA_e), new String("int"), 0, 0, 100, true, 0, this);
SensorRepository.insertSensor(new String("BV"), new String("mV"), airs.getString(R.string.BV_d), airs.getString(R.string.BV_e), new String("int"), 0, 0, 10, true, 0, this);
SensorRepository.insertSensor(new String("Bc"), new String("boolean"), airs.getString(R.string.BC_d), airs.getString(R.string.BC_e), new String("int"), 0, 0, 1, false, 0, this);
SensorRepository.insertSensor(new String("BM"), new String("C"), airs.getString(R.string.BM_d), airs.getString(R.string.BM_e), new String("int"), -1, 0, 100, true, 0, this);
SensorRepository.insertSensor(new String("Rm"), new String("RAM"), airs.getString(R.string.RM_d), airs.getString(R.string.RM_e), new String("int"), 0, 0, 512000000, true, polltime, this);
SensorRepository.insertSensor(new String("Sc"), new String("Screen"), airs.getString(R.string.SC_d), airs.getString(R.string.SC_e), new String("int"), 0, 0, 1, false, 0, this);
SensorRepository.insertSensor(new String("HS"), new String("Headset"), airs.getString(R.string.HS_d), airs.getString(R.string.HS_e), new String("int"), 0, 0, 1, false, 0, this);
SensorRepository.insertSensor(new String("IC"), new String("Number"), airs.getString(R.string.IC_d), airs.getString(R.string.IC_e), new String("txt"), 0, 0, 1, false, 0, this);
SensorRepository.insertSensor(new String("OC"), new String("Number"), airs.getString(R.string.OC_d), airs.getString(R.string.OC_e), new String("txt"), 0, 0, 1, false, 0, this);
SensorRepository.insertSensor(new String("SR"), new String("SMS"), airs.getString(R.string.SR_d), airs.getString(R.string.SR_e), new String("txt"), 0, 0, 1, false, 0, this);
SensorRepository.insertSensor(new String("SS"), new String("SMS"), airs.getString(R.string.SS_d), airs.getString(R.string.SS_e), new String("txt"), 0, 0, 1, false, 0, this);
SensorRepository.insertSensor(new String("TR"), new String("Tasks"), airs.getString(R.string.TR_d), airs.getString(R.string.TR_e), new String("txt"), 0, 0, 1, false, polltime, this);
SensorRepository.insertSensor(new String("TV"), new String("Tasks"), airs.getString(R.string.TV_d), airs.getString(R.string.TV_e), new String("txt"), 0, 0, 1, false, polltime, this);
SensorRepository.insertSensor(new String("TE"), new String("Template"), airs.getString(R.string.TE_d), airs.getString(R.string.TE_e), new String("txt"), 0, 0, 1, false, 0, this);
SensorRepository.insertSensor(new String("TZ"), new String("Timezone"), airs.getString(R.string.TZ_d), airs.getString(R.string.TZ_e), new String("int"), 0, 0, 10000000, false, 0, this);
}
/**
* Constructor, allocating all necessary resources for the handler
* Here, it's only arming the semaphores and obtaining a reference to the {android.app.ActivityManager} for the task information
* @param airs Reference to the calling {@link android.content.Context}
*/
public SystemHandler(Context airs)
{
// read polltime
polltime = HandlerManager.readRMS_i("SystemSensorsHandler::SystemPoll", 5) * 1000;
this.airs = airs;
try
{
// charge the semaphores to block at next call!
battery_semaphore1.acquire();
battery_semaphore2.acquire();
battery_semaphore3.acquire();
screen_semaphore.acquire();
charger_semaphore.acquire();
headset_semaphore.acquire();
caller_semaphore.acquire();
callee_semaphore.acquire();
received_semaphore.acquire();
sent_semaphore.acquire();
// get ActivityManager for list of tasks
am = (ActivityManager) airs.getSystemService(Context.ACTIVITY_SERVICE); // if something returned, enter sensor value
// get timezone offset
Offset = TimeZone.getDefault().getRawOffset();
// create date of today
Date time = new Date();
time.setTime(System.currentTimeMillis());
// if in DST, add offset to it
if (TimeZone.getDefault().inDaylightTime(time) == true)
Offset += TimeZone.getDefault().getDSTSavings();
}
catch(Exception e)
{
SerialPortLogger.debug("Semaphore!!!!");
}
}
/**
* Method to release all handler resources
* Here, we unregister the broadcast receiver and release all semaphores
* @see com.airs.handlers.Handler#destroyHandler()
*/
public void destroyHandler()
{
// we are shutting down!
shutdown = true;
// release all semaphores for unlocking the Acquire() threads
battery_semaphore1.release();
battery_semaphore2.release();
battery_semaphore3.release();
screen_semaphore.release();
charger_semaphore.release();
headset_semaphore.release();
caller_semaphore.release();
callee_semaphore.release();
received_semaphore.release();
sent_semaphore.release();
template_semaphore.release();
timezone_semaphore.release();
if (startedTimeZone == true || startedBattery == true || startedScreen==true || startedHeadset == true || startedPhoneState == true || startedOutgoingCall == true || startedSMSReceived == true)
airs.unregisterReceiver(SystemReceiver);
if (startedSMSSent == true)
airs.getContentResolver().unregisterContentObserver(smsSentObserver);
// remove all messages
mHandler.removeMessages(INIT_BATTERY);
mHandler.removeMessages(INIT_TIMEZONE);
mHandler.removeMessages(INIT_SCREEN);
mHandler.removeMessages(INIT_HEADSET);
mHandler.removeMessages(INIT_PHONESTATE);
mHandler.removeMessages(INIT_OUTGOINGCALL);
mHandler.removeMessages(INIT_SMSRECEIVED);
mHandler.removeMessages(INIT_SMSSENT);
}
private String getContactByNumber(String number)
{
try
{
// Form an array specifying which columns to return.
String[] projection = new String[] {
Contacts._ID,
Contacts.DISPLAY_NAME
};
// lookup URI for callee
Uri uri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number));
// query contact database
Cursor cur = airs.getContentResolver().query(uri, projection, null, null, null);
// move to first returned element
if (cur.moveToFirst() == true)
{
String name = cur.getString(cur.getColumnIndex(Contacts.DISPLAY_NAME));
if (name != null)
return name;
}
else
return "---";
}
catch(Exception e)
{
return "---";
}
return "---";
}
// The Handler that gets information back from the other threads, initializing phone sensors
// We use a handler here to allow for the Acquire() function, which runs in a different thread, to issue an initialization of the invidiual sensors
// since registerListener() can only be called from the main Looper thread!!
private final Handler mHandler = new Handler()
{
@Override
public void handleMessage(Message msg)
{
IntentFilter intentFilter;
// we are shutting down
if (shutdown == true)
return;
switch (msg.what)
{
case INIT_TIMEZONE:
intentFilter = new IntentFilter(Intent.ACTION_TIMEZONE_CHANGED);
airs.registerReceiver(SystemReceiver, intentFilter);
startedTimeZone = true;
break;
case INIT_BATTERY:
intentFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
airs.registerReceiver(SystemReceiver, intentFilter);
startedBattery = true;
break;
case INIT_SCREEN:
intentFilter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
airs.registerReceiver(SystemReceiver, intentFilter);
intentFilter = new IntentFilter(Intent.ACTION_SCREEN_ON);
airs.registerReceiver(SystemReceiver, intentFilter);
startedScreen = true;
break;
case INIT_HEADSET:
intentFilter = new IntentFilter(Intent.ACTION_HEADSET_PLUG);
airs.registerReceiver(SystemReceiver, intentFilter);
startedHeadset = true;
break;
case INIT_PHONESTATE:
intentFilter = new IntentFilter(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
airs.registerReceiver(SystemReceiver, intentFilter);
startedPhoneState = true;
break;
case INIT_OUTGOINGCALL:
intentFilter = new IntentFilter("android.intent.action.NEW_OUTGOING_CALL");
airs.registerReceiver(SystemReceiver, intentFilter);
startedOutgoingCall = true;
break;
case INIT_SMSRECEIVED:
intentFilter = new IntentFilter("android.provider.Telephony.SMS_RECEIVED");
// since SMS_RECEIVED is sent via ordered broadcast, we have to make sure that we
// receive this with highest priority in case a receiver aborts the broadcast!
intentFilter.setPriority(1000000);
airs.registerReceiver(SystemReceiver, intentFilter);
startedSMSReceived = true;
break;
case INIT_SMSSENT:
smsSentObserver = new SmsObserver(new Handler());
airs.getContentResolver().registerContentObserver(SMS_STATUS_URI, true, smsSentObserver);
startedSMSSent = true;
break;
default:
break;
}
}
};
private final BroadcastReceiver SystemReceiver = new BroadcastReceiver()
{
@Override
public void onReceive(Context context, Intent intent)
{
String action = intent.getAction();
// when timezone changed
if (Intent.ACTION_TIMEZONE_CHANGED.compareTo(action) == 0)
{
Offset = TimeZone.getDefault().getRawOffset();
// create date of today
Date time = new Date();
time.setTime(System.currentTimeMillis());
// if in DST, add offset to it
if (TimeZone.getDefault().inDaylightTime(time) == true)
Offset += TimeZone.getDefault().getDSTSavings();
timezone_semaphore.release(); // release semaphore
}
// When battery changed...
if (Intent.ACTION_BATTERY_CHANGED.compareTo(action) == 0)
{
int rawlevel = intent.getIntExtra("level", -1);
int scale = intent.getIntExtra("scale", -1);
voltage = intent.getIntExtra("voltage", -1);
temperature = intent.getIntExtra(BatteryManager.EXTRA_TEMPERATURE, -1);
int plugged = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);
if (rawlevel >= 0 && scale > 0)
Battery = (rawlevel * 100) / scale;
if (plugged==0)
battery_charging = 0;
else
battery_charging = 1;
battery_semaphore1.release(); // release semaphore
battery_semaphore2.release(); // release semaphore
battery_semaphore3.release(); // release semaphore
charger_semaphore.release(); // release semaphore
return;
}
// when screen is gone off
if (Intent.ACTION_SCREEN_OFF.compareTo(action) == 0)
{
ScreenOn = 0;
screen_semaphore.release(); // release semaphore
return;
}
// when screen is gone on
if (Intent.ACTION_SCREEN_ON.compareTo(action) == 0)
{
ScreenOn = 1;
screen_semaphore.release(); // release semaphore
return;
}
// when headset is plugged in/out
if (Intent.ACTION_HEADSET_PLUG.compareTo(action) == 0)
{
headset = intent.getIntExtra("state", -1);
headset_semaphore.release(); // release semaphore
return;
}
// when incoming call
if (TelephonyManager.ACTION_PHONE_STATE_CHANGED.compareTo(action) == 0)
{
String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
if (TelephonyManager.EXTRA_STATE_RINGING.equals(state))
{
try
{
caller = new String(intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER));
// append caller display name, if available
if (caller != null)
caller = caller.concat(":" + getContactByNumber(caller));
else
caller = caller.concat(":" + "---");
}
catch(Exception e)
{
caller = new String("unknown:---");
}
caller_semaphore.release(); // release semaphore
}
return;
}
// when outgoing call
if (action.compareTo("android.intent.action.NEW_OUTGOING_CALL") == 0)
{
try
{
callee = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
// append caller display name, if available
if (callee != null)
callee = callee.concat(":" + getContactByNumber(callee));
else
callee = callee.concat(":" + "---");
}
catch(Exception e)
{
callee = new String("unknown:---");
}
callee_semaphore.release(); // release semaphore
return;
}
// when incoming SMS
if (action.compareTo("android.provider.Telephony.SMS_RECEIVED") == 0)
{
Bundle extras = intent.getExtras();
if (extras == null)
return;
Object[] pdus = (Object[]) extras.get("pdus");
// get first PDU to extract originating address
SmsMessage message = SmsMessage.createFromPdu((byte[]) pdus[0]);
String Address = message.getOriginatingAddress();
smsReceived = new String(Address + ":" + getContactByNumber(Address) + ":" + message.getMessageBody());
// more than one PDU?
if (pdus.length >1)
for (int i = 1; i < pdus.length; i++)
{
// only take message body of the additional PDUs
message = SmsMessage.createFromPdu((byte[]) pdus[i]);
smsReceived = smsReceived.concat(message.getMessageBody());
}
received_semaphore.release(); // release semaphore
}
}
};
private class SmsObserver extends ContentObserver
{
public SmsObserver(Handler handler)
{
super(handler);
}
public boolean deliverSelfNotifications()
{
return true;
}
public void onChange(boolean selfChange)
{
String smsBodyStr, phoneNoStr;
super.onChange(selfChange);
try
{
Cursor sms_sent_cursor = airs.getContentResolver().query(SMS_STATUS_URI, null, null, null, null);
if (sms_sent_cursor != null)
{
if (sms_sent_cursor.moveToFirst())
{
//for send protocol is null
if(sms_sent_cursor.getString(sms_sent_cursor.getColumnIndex("protocol")) == null)
{
// long date = sms_sent_cursor.getLong(sms_sent_cursor.getColumnIndex("date"));
// for actual type=2 and SMS that has not been read according to timestamp
// public static final int STATUS_NONE = -1;
// public static final int STATUS_COMPLETE = 0;
// public static final int STATUS_PENDING = 32;
// public static final int STATUS_FAILED = 64;
if (sms_sent_cursor.getInt(sms_sent_cursor.getColumnIndex("type")) == 2)
{
smsBodyStr = sms_sent_cursor.getString(sms_sent_cursor.getColumnIndex("body")).trim();
phoneNoStr = sms_sent_cursor.getString(sms_sent_cursor.getColumnIndex("address")).trim();
Log.e("AIRS", "got an SMS sent notification - now checking if seen before");
// avoid concurrent access to this shared variable!
// do everything locally first!
String currentSMS = new String(phoneNoStr + ":" + getContactByNumber(phoneNoStr) + ":" + smsBodyStr);
String lastSeen = HandlerManager.readRMS("SystemHandler::lastSeen", "");
boolean seenBefore = true;
if (lastSeen != null)
{
if (currentSMS.compareTo(lastSeen) != 0)
seenBefore = false;
}
else
seenBefore = false;
// is SMS different from last seen one?
if (seenBefore == false)
{
smsSent = new String(currentSMS);
// write into permanent settings
HandlerManager.writeRMS("SystemHandler::lastSeen", smsSent);
// release semaphore
sent_semaphore.release();
SerialPortLogger.debug("SS sensor: valid message -> released semaphore with available permits of " + String.valueOf(sent_semaphore.availablePermits()));
// discard string for garbage collector
lastSeen = null;
}
else
SerialPortLogger.debug("SS sensor: seen that before -> nothing triggered (" + currentSMS + ")");
}
}
}
// close cursor now!
sms_sent_cursor.close();
}
}
catch(Exception sggh)
{
SerialPortLogger.debug("Exception in SS sensor handling: " + sggh.toString());
Log.e("AIRS", "Exception in SS sensor handling: " + sggh.toString());
}
}
}
}