也许这会给你一个想法......
压力动力学.java
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import android.content.Context;
import android.util.Log;
/**
* Keyboard sensor
*/
public class PressureDynamics extends Thread implements FeatureExtractor{
public static final String AVG_TOUCH_PRESSURE = "Avg_Touch_Pressure";
public static final String AVG_TOUCH_AREA = "Avg_Touch_Area";
private static final int EVENT_BYTE_SIZE = 16;
private InputStream _fis = null;
private boolean _shouldRun;
private Map<String, TouchScreenSensor> _sensors;
public PressureDynamics(Context context, Collection<FeatureInfo> featureInfos,
Long timeStamp){
super("Pressure Dynamics Feature Extractor Thread");
_shouldRun = true;
_sensors = new HashMap<String, TouchScreenSensor>();
int featureCount = 0;
for (FeatureInfo featureInfo : featureInfos){
String name = featureInfo.name;
try{
if (name.equalsIgnoreCase(AVG_TOUCH_PRESSURE)){
TouchScreenSensor s = new AvgTouchPressureSensor(featureInfo);
_sensors.put(AVG_TOUCH_PRESSURE, s);
}else if (name.equalsIgnoreCase(AVG_TOUCH_AREA)){
TouchScreenSensor s = new AvgTouchAreaSensor(featureInfo);
_sensors.put(AVG_TOUCH_AREA, s);
}else{
Log.e(FE_TAG, "Unhandled feature by " + getClass().getCanonicalName()
+ ": " + name);
continue;
}
++featureCount;
}catch(RuntimeException e){
Log.e(FE_TAG, "Unable to initialize feature: " + name, e);
}
}
if (featureCount == 0){
throw new FeatureExtractorInitException("No features of "
+ getClass().getCanonicalName() + " could be initialized");
}
_fis = openTouchScreenInputStream();
start();
}
private static InputStream openTouchScreenInputStream(){
final String HTC_TOUCH_SCREEN_INPUT_FILEPATH = "/dev/input/event1";
LocalServerConn localServerConn;
try{
localServerConn = LocalServerConn.getInstance();
localServerConn.runLocalServer();
}catch(Exception e){
throw new FeatureExtractorInitException(
"Unable to collect Touch Screen features", e);
}
try{
FileDescriptor[] fdArr = localServerConn
.sendFileDescriptorReq(HTC_TOUCH_SCREEN_INPUT_FILEPATH);
if (fdArr == null || fdArr.length == 0){
throw new FeatureExtractorInitException("Can't open keyboard device");
}
return new FileInputStream(fdArr[0]);
}catch(IOException e){
throw new FeatureExtractorInitException("Can't open keyboard input stream: "
+ e.getMessage(), e);
}
}
public void close(){
_shouldRun = false;
}
public void collectData(List<MonitoredData> monitoredData, ParcelableDate endTime){
for (Sensor s : _sensors.values()){
s.collectData(monitoredData, endTime);
}
}
public void run(){
int n;
int pos = 0;
byte[] buffer = new byte[256];
for (;;){
try{
n = _fis.read(buffer, pos, EVENT_BYTE_SIZE);
/*
* check if we are shutting down - this may have the thread hanging around
* until the next touch event comes in
*/
if (_shouldRun == false){
break;
}
pos += n;
// Log.v(FE_TAG, "read touch screen event: " + n + " bytes\n");
if (pos >= EVENT_BYTE_SIZE){
long currentTimeMillis = System.currentTimeMillis();
TouchEvent touchScreenEvent = new TouchEvent(buffer,
currentTimeMillis);
updateSensors(touchScreenEvent, currentTimeMillis);
pos -= EVENT_BYTE_SIZE;
}
}catch(IOException e){
Log.e(FE_TAG, e.getMessage(), e);
}
}
}
private void updateSensors(TouchEvent touchScreenEvent, long currentTimeMillis){
try{
// currently filter out all non preassure event types
//
switch ((int)touchScreenEvent.getCode()){
case TouchEvent.X_POS_EVENT:
case TouchEvent.Y_POS_EVENT:
case TouchEvent.TOUCH_DEVICE_TYPE_EVENT:
break;
case TouchEvent.ABS_PRESSURE_EVENT:
_sensors.get(AVG_TOUCH_PRESSURE).updateSensor(touchScreenEvent,
currentTimeMillis);
break;
case TouchEvent.ABS_TOOL_WIDTH_EVENT:
_sensors.get(AVG_TOUCH_AREA).updateSensor(touchScreenEvent,
currentTimeMillis);
break;
default:
Log.e(FE_TAG, "unrecognized touch event code :"
+ touchScreenEvent.getCode());
break;
}
}catch(Exception e){
Log.e(FE_TAG, e.getMessage(), e);
}
}
public String toString(){
return getClass().getSimpleName();
}
private static abstract class TouchScreenSensor extends Sensor{
private TouchScreenSensor(String name, FeatureInfo info){
//super(name, info.getValueTimeout());
super(name);
}
public abstract void updateSensor(TouchEvent event, long currentTimeMillis);
}
private static class AvgTouchPressureSensor extends TouchScreenSensor{
public AvgTouchPressureSensor(FeatureInfo info){
super(AVG_TOUCH_PRESSURE, info);
}
public void updateSensor(TouchEvent event, long currentTimeMillis){
addToAvg(event.getValue(), currentTimeMillis);
}
}
private static class AvgTouchAreaSensor extends TouchScreenSensor{
public AvgTouchAreaSensor(FeatureInfo info){
super(AVG_TOUCH_AREA, info);
}
public void updateSensor(TouchEvent event, long currentTimeMillis){
addToAvg(event.getValue(), currentTimeMillis);
}
}
}
传感器.java
import java.util.List;
public class Sensor{
private final String _name;
private Double _avg;
private int _count;
private long _lastValueUpdateTime;
/**
* Constructor
*
* @param name The name of the feature that is collected by this sensor
* @param valueTimeout The time period of no value changes it takes for the current
* value to reset to the initial value (in millis)
*/
public Sensor(String name){
_lastValueUpdateTime = 0;
_name = name;
_avg = null;
_count = 0;
}
public void collectData(List<MonitoredData> monitoredData, ParcelableDate endTime){
Double value = getValue(endTime.getTime());
if (value != null){
value = Utils.truncateDouble(value);
}
monitoredData.add(new MonitoredData(_name, value, endTime));
}
public Double getValue(long time){
if (time - _lastValueUpdateTime > MainActivity.getAgentLoopTime()){
_avg = null;
_count = 0;
}
return _avg;
}
public String getName(){
return _name;
}
public void addToAvg(double value, long time){
Double avg = getValue(time);
if (avg == null){
avg = value; // Initial value
}else{
value = (avg * _count + value) / (_count + 1);
}
++_count;
_avg = value;
_lastValueUpdateTime = time;
}
@Override
public String toString(){
return _name;
}
}
触摸事件.java
import android.util.Log;
import dt.util.Utils;
public class TouchEvent{
public static final int ABS_PRESSURE_EVENT = 0x18;
public static final int ABS_TOOL_WIDTH_EVENT = 0x1c;
public static final int X_POS_EVENT = 0x0;
public static final int Y_POS_EVENT = 0x1;
/* type of touching device ie. finger, stylus etc. */
public static final int TOUCH_DEVICE_TYPE_EVENT = 0x14a;
// private final long _timeStamp;
// private final int _sec;
// private final int _usec;
// 3, 1, 0 - ?
// private final long _type;
// different event types have different codes
private final long _code;
private final int _value;
//
public TouchEvent(byte[] _buffer, long currentTimeMillis){
int pos;
byte b[] = new byte[4];
byte s[] = new byte[2];
// _timeStamp = currentTimeMillis;
pos = 0;
// _sec = Utils.LittleEndianBytesToInt(_buffer);
pos += 4;
System.arraycopy(_buffer, pos, b, 0, 4);
// _usec = Utils.LittleEndianBytesToInt(b);
pos += 4;
// _type = Utils.LittleEndianBytesToUShort(s);
pos += 2;
System.arraycopy(_buffer, pos, s, 0, 2);
_code = Utils.littleEndianBytesToUShort(s);
pos += 2;
System.arraycopy(_buffer, pos, b, 0, 4);
_value = Utils.littleEndianBytesToInt(b);
if (_code != X_POS_EVENT && _code != Y_POS_EVENT
&& _code != TOUCH_DEVICE_TYPE_EVENT && _code != ABS_PRESSURE_EVENT
&& _code != ABS_TOOL_WIDTH_EVENT){
Log.d(FE_TAG, "unrecognized touch event code :" + _code);
}
}
public long getCode(){
return _code;
}
public double getValue(){
return _value;
}
}
特征信息.java
import java.util.HashMap;
public class FeatureInfo{
/** The name of the feature */
public final String name;
/** The parameters relevant to the feature */
public final HashMap<String, String> params;
/**
* Constructs a FeatureInfo object from the given parameters
*
* @param name The name of the feature
* @param params The parameters relevant to the feature
*/
public FeatureInfo(String name, HashMap<String, String> params){
this.name = name;
this.params = (params == null) ? new HashMap<String, String>() : params;
}
@Override
public String toString(){
return name;
}
public int getTimeWindow() throws IllegalArgumentException{
final String paramName = "Time_Window";
try{
int timeWindow = Integer.parseInt(params.get(paramName)) * 1000;
if (timeWindow <= 0){
throw new IllegalArgumentException("Must be a positive integer");
}
return timeWindow;
}catch(Exception e){// NullPointer or Parsing
throw new IllegalArgumentException("Corrupt parameter: " + paramName
+ " in feature " + name, e);
}
}
// public int getTimeWindow() throws IllegalArgumentException{
// final String paramName = "Time_Window";
// try{
// int timeWindow = Integer.parseInt(params.get(paramName)) * 1000;
// if (timeWindow <= 0){
// throw new IllegalArgumentException("Must be a positive integer");
// }
// return timeWindow;
// }catch(Exception e){// NullPointer or Parsing
// throw new IllegalArgumentException("Corrupt parameter: " + paramName
// + " in feature " + name, e);
// }
// }
public int getValueTimeout() throws IllegalArgumentException{
final String paramName = "Value_Timeout";
try{
int valueTimeout = Integer.parseInt(params.get(paramName)) * 1000;
if (valueTimeout <= 0){
throw new IllegalArgumentException("Must be a positive integer");
}
return valueTimeout;
}catch(Exception e){// NullPointer or Parsing
throw new IllegalArgumentException("Corrupt parameter: " + paramName
+ " in feature " + name, e);
}
}
public double getMovieAverageWeight() throws IllegalArgumentException{
final String paramName = "Moving_Average_Weight";
try{
double movingAverageWeight = Double.parseDouble(params.get(paramName));
if (movingAverageWeight < 0 || movingAverageWeight > 1){
throw new IllegalArgumentException("Must be positive and 1.0 at most");
}
return movingAverageWeight;
}catch(Exception e){// NullPointer or Parsing
throw new IllegalArgumentException("Corrupt parameter: " + paramName
+ " in feature " + name, e);
}
}
public boolean getIncludeEventTimes(){
final String paramName = "Include_Event_Times";
return Boolean.parseBoolean(params
.get(paramName));
}
public boolean getIncludeMaximalEntity(){
final String paramName = "Include_Maximal_Entity";
return Boolean.parseBoolean(params
.get(paramName));
}
}
监控数据.java
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
@SuppressWarnings("unchecked")
public class MonitoredData implements Map, Parcelable{
public static final int DEFAULT = 0;
public static final int HAS_EXTRAS = 1;
protected String _name;
protected ParcelableDate _startTime, _endTime;
protected Object _value;
protected Bundle _extras;
public static final Parcelable.Creator<MonitoredData> CREATOR = new Parcelable.Creator<MonitoredData>(){
public MonitoredData createFromParcel(Parcel in){
ClassLoader cl = ParcelableDate.class.getClassLoader();
String name = in.readString();
Object value = in.readValue(null);
ParcelableDate startTime = (ParcelableDate)in.readParcelable(cl);
ParcelableDate endTime = (ParcelableDate)in.readParcelable(cl);
Bundle extras = in.readBundle();
MonitoredData monitoredData = new MonitoredData(name, value, startTime,
endTime);
if (extras != null){
monitoredData.setExtras(extras);
}
return monitoredData;
}
public MonitoredData[] newArray(int size){
return new MonitoredData[size];
}
};
private static DateFormat _sdf = new SimpleDateFormat("dd/MM/yyyy hh:mm:ss");
public MonitoredData(String name, Object value, Date endTime){
this(name, value, new ParcelableDate(endTime), new ParcelableDate(endTime));
}
public MonitoredData(String name, Object value, ParcelableDate endTime){
this(name, value, endTime, endTime);
}
public MonitoredData(String name, Object value, Date startTime, Date endTime){
this(name, value, new ParcelableDate(startTime), new ParcelableDate(endTime));
}
public MonitoredData(String name, Object value, Date startTime, ParcelableDate endTime){
this(name, value, new ParcelableDate(startTime), endTime);
}
public MonitoredData(String name, Object value, ParcelableDate startTime,
ParcelableDate endTime){
_name = name;
_startTime = startTime;
_endTime = endTime;
_value = value;
_extras = null;
}
public void setExtras(Bundle extras){
_extras = extras;
}
public Map<String, Object> toMap(){
TreeMap<String, Object> map = new TreeMap<String, Object>();
map.put("Name", _name);
map.put("StartTime", _startTime);
map.put("EndTime", _endTime);
map.put("Value", _value);
return map;
}
public String conciseToString(){
String extrasToString = (_extras != null && !_extras.isEmpty()) ? " - "
+ _extras.toString() : "";
return "{" + getName() + " = " + getValue() + "}" + extrasToString;
}
public int describeContents(){
return (_extras == null || _extras.isEmpty()) ? DEFAULT : HAS_EXTRAS;
}
public ParcelableDate getEndTime(){
return _endTime;
}
public String getName(){
return _name;
}
public ParcelableDate getStartTime(){
return _startTime;
}
public Object getValue(){
return _value;
}
public Bundle getExtras(){
return _extras;
}
public String toString(){
StringBuilder sb = new StringBuilder("{");
sb.append("Name = " + getName() + ", ");
sb.append("Value = " + getValue() + ", ");
sb.append("StartTime = " + _sdf.format(getStartTime()) + ", ");
sb.append("EndTime = " + _sdf.format(getEndTime()));
sb.append("}");
return sb.toString();
}
public void writeToParcel(Parcel dest, int flags){
dest.writeString(getName());
dest.writeValue(getValue());
dest.writeParcelable(getStartTime(), 0);
dest.writeParcelable(getEndTime(), 0);
dest.writeBundle(_extras);
}
public void clear(){
throw new UnsupportedOperationException();
}
public boolean containsKey(Object key){
throw new UnsupportedOperationException();
}
public boolean containsValue(Object value){
throw new UnsupportedOperationException();
}
public Set entrySet(){
return Collections.unmodifiableSet(toMap().entrySet());
}
public Object get(Object key){
throw new UnsupportedOperationException();
}
public boolean isEmpty(){
throw new UnsupportedOperationException();
}
public Set keySet(){
throw new UnsupportedOperationException();
}
public Object put(Object key, Object value){
throw new UnsupportedOperationException();
}
public void putAll(Map arg0){
throw new UnsupportedOperationException();
}
public Object remove(Object key){
throw new UnsupportedOperationException();
}
public int size(){
throw new UnsupportedOperationException();
}
public Collection values(){
throw new UnsupportedOperationException();
}
/**
* Returns the value of the monitored data as a Double.
* Null is returned if the value is null or is can not be converted to double.
*
* @return The value as double if possible, null otherwise
*/
public Double mdToDouble(){
Double sample;
Object val = getValue();
if (val instanceof Double){
sample = ((Double)val).doubleValue();
}else if (val instanceof Long){
sample = ((Long)val).doubleValue();
}else if (val instanceof Integer){
sample = ((Integer)val).doubleValue();
}else{
sample = null;
}
return sample;
}
}
实用程序.java
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.Formatter;
import java.util.List;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;
import android.content.Context;
import android.content.res.Resources;
import android.os.Environment;
import android.widget.Toast;
public class Utils{
public static byte[] append(byte[] first, byte[] second){
byte[] bytes;
bytes = new byte[first.length + second.length];
System.arraycopy(first, 0, bytes, 0, first.length);
System.arraycopy(second, 0, bytes, first.length, second.length);
return bytes;
}
public static int bytesToInt(byte[] bytes){
return (bytes[3] & 0xFF) | ((bytes[2] & 0xFF) << 8) | ((bytes[1] & 0xFF) << 16)
| ((bytes[0] & 0xFF) << 24);
}
public static int littleEndianBytesToInt(byte[] bytes){
return (bytes[0] & 0xFF) | ((bytes[1] & 0xFF) << 8) | ((bytes[2] & 0xFF) << 16)
| ((bytes[3] & 0xFF) << 24);
}
public static long littleEndianBytesToUShort(byte[] arr){
return (arr[1] << 8) | arr[0];
}
public static void displayShortAlert(Context context, String message){
Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
}
public static XmlPullParser getXPP(Context context, int resourceId, boolean isBinary){
XmlPullParser xpp;
Resources resources = context.getResources();
if (isBinary){
return resources.getXml(resourceId);
}else{
try{
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
xpp = factory.newPullParser();
xpp.setInput(resources.openRawResource(resourceId), null);
}catch(XmlPullParserException e){
xpp = null;
}
return xpp;
}
}
public static byte[] intToBytes(int i){
byte[] bytes = new byte[]{(byte)((i >> 24) & 0xff), (byte)((i >> 16) & 0xff),
(byte)((i >> 8) & 0xff), (byte)((i) & 0xff)};
return bytes;
}
/*
* debugging
*/
public static String printByteArray(byte[] bytes, int len){
StringBuilder sb = new StringBuilder();
sb.append("msg len: " + len + " :");
Formatter f = new Formatter(sb);
for (int i = 0; i < len; i++){
f.format("%2x", bytes[i]);
}
sb.append("\n");
return sb.toString();
}
public static List<Integer> getPids(String fileName){
String line;
int pidIndex = -1;
try{
Process p = Runtime.getRuntime().exec("ps " + fileName);
p.waitFor();
BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()), 256);
if ((line = br.readLine()) == null){
throw new IllegalStateException("Unable to read ps output");
}
String[] tokens = line.split(" +");
for (int i = 0; i < tokens.length; ++i){
if (tokens[i].equalsIgnoreCase("pid")){
pidIndex = i;
}
}
if (pidIndex < 0){
throw new IllegalStateException("Unable to locate pid field in ps output");
}
List<Integer> pids = new ArrayList<Integer>();
while ((line = br.readLine()) != null){
tokens = line.split(" +");
assert tokens.length < 9;
try{
pids.add(Integer.parseInt(tokens[pidIndex]));
}catch(NumberFormatException e){
throw new IllegalStateException("Pid is not an integer");
}
}
br.close();
return pids;
}catch(Exception e){
throw new IllegalStateException("Unable to read running process through ps: "
+ e.getMessage(), e);
}
}
public static void killProcesses(List<Integer> pids){
for (Integer pid : pids){
android.os.Process.killProcess(pid);
}
}
public static void killProcesses(String processName){
killProcesses(getPids(processName));
}
public static void suKillProcesses(List<Integer> pids){
StringBuilder cmd = new StringBuilder("kill");
for (Integer pid : pids){
cmd.append(" ").append(pid);
}
try{
Runtime.getRuntime().exec(new String[]{"su", "-c", cmd.toString()});
}catch(IOException e){
e.printStackTrace();
}
}
public static void suKillProcess(int pid){
try{
Runtime.getRuntime().exec(new String[]{"su", "-c", "kill " + pid});
}catch(IOException e){
e.printStackTrace();
}
}
public static void suKillProcesses(String processName){
suKillProcesses(getPids(processName));
}
public static double truncateDouble(double d){
long l = Math.round(d * 100);
return l / 100.0;
}
public static double calcMovingAvg(double oldVal, double newVal, double newValWeight){
return (oldVal * (1.0 - newValWeight)) + (newValWeight * newVal);
}
public static double calcAvg(double oldAvg, int count, double newVal){
return (oldAvg * count + newVal) / (count + 1);
}
public static void writeLogToFile(Context context, boolean onSdcard, String prefix, int timeWindowInSeconds) throws Exception{
final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH-mm-ss");
final DateFormat logDF = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
final long currentTime = System.currentTimeMillis();
final long startTime = currentTime - timeWindowInSeconds * 1000;
final String currentYear = Calendar.getInstance().get(Calendar.YEAR) + "-";
final String logFileName = prefix + sdf.format(new Date(currentTime)) + ".log";
BufferedReader logcatIn;
Process logcat;
OutputStream logFile;
try{
logcat = Runtime.getRuntime().exec("logcat -v time -d *:d");
logcatIn = new BufferedReader(new InputStreamReader(logcat
.getInputStream()), 1024);
}catch(IOException e){
throw new Exception("Unable to launch logcat: " + e.getMessage(), e);
}
try{
if (onSdcard){
logFile = new FileOutputStream(new File(Environment.getExternalStorageDirectory(), logFileName));
}else{
logFile = context.openFileOutput(logFileName, 0);
}
}catch(IOException e){
throw new Exception("Unable to create log file: " + e.getMessage(), e);
}
PrintWriter pw = new PrintWriter(logFile, false);
String line;
long logLineTime;
while ((line = logcatIn.readLine()) != null){
logLineTime = logDF.parse(currentYear + line.substring(0, line.indexOf(".") + 4)).getTime();
if (logLineTime >= startTime){
pw.println(line);
}
}
pw.flush();
pw.close();
logcatIn.close();
logcat.destroy();
}
}
特征提取器.java
import java.util.List;
/**
* A class capable of extracting one or more features. It MUST have a public constructor
* with the following parameters in this order:
* <ul>
* <li>Context context</li>
* <li>Collection<FeatureInfo> featureInfos</li>
* <li>Long timeStamp</li>
* </ul>
*
*/
public interface FeatureExtractor{
/**
* Invoked during a data collection. It is up to the extractor to add the data
* relevant to it's monitored features to the monitoredData list.
*
* @param monitoredData The overall collected data (from all extractors) so far
* @param endTime The time of the current data collection
*/
public void collectData(List<MonitoredData> monitoredData, ParcelableDate endTime);
/**
* Invoked when the feature extractor is no longer needed. This is the place to
* release any resources, unregister any listeners, close any threads, etc.
*/
public void close();
}
FeatureExtractorInitException.java
public class FeatureExtractorInitException extends RuntimeException{
private static final long serialVersionUID = 1L;
public FeatureExtractorInitException(String message){
super(message);
}
public FeatureExtractorInitException(String message, Throwable t){
super(message, t);
}
public FeatureExtractorInitException(Throwable t){
super(t);
}
}