/*
* Software Name : ATK
*
* Copyright (C) 2007 - 2012 France Télécom
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ------------------------------------------------------------------
* File Name : DefaultTouchScreenEventfilter.java
*
* Created : 26/11/2009
* Author(s) : France Telecom
*/
package com.orange.atk.phone.android;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import org.apache.log4j.Logger;
import com.orange.atk.phone.PhoneInterface;
import com.orange.atk.util.Position;
/**
* Class used to filter output of very common touch screen,
* He is found on HTC G1, Samsung SPICA , MOtorola Morisson...
* @author Moreau Fabien - GFI - FMOREAU@gfi.fr
*
*/
class DefaultTouchScreenEventfilter extends EventFilter {
protected int ALLOW_PIXEL_MOVE = 10;
protected int ALLOW_SOFTKEY_MOVE = 20;
//code to detect movement
protected static String X_POSITION="xxx";
protected static String Y_POSITION="xxx";
protected static String XY_POSITION="xxx";
protected static String FLUSH_EVENT="xxx";
protected static String FLUSH_EVENT2="xxx";
/**
* Pattern corresponding to a touch down event.<p>
* When the phone returns a range of value corresponding to the pressure,
* this parameter must be set to the <b>smallest possible value</b>.
*/
protected static String MOUSE_DOWN;
/**
* Pattern corresponding the max of a touch down event.<p>
* When the phone returns a range of value corresponding to the pressure,
* this parameter must be set to the <b>biggest possible value</b>.
* Otherwise, this parameter is ignored and set to null.
*/
protected static String MOUSE_DOWN_MAX = null;
/**
* When the phone returns a range of value corresponding to the pressure,
* this parameter is set to the <b>smallest suffix</b>
* of the pattern corresponding to a touch down.
* Otherwise, this parameter is ignored and set to 0.
*/
protected static int MOUSE_DOWN_SUFFIX_MIN = 0;
/**
* When the phone returns a range of value corresponding to the pressure,
* this parameter is set to the <b>biggest suffix</b>
* of the pattern corresponding to a touch down.
* Otherwise, this parameter is ignored and set to 0.
*/
protected static int MOUSE_DOWN_SUFFIX_MAX = 0;
/**
* Pattern corresponding to a touch up event.
*/
protected static String MOUSE_UP;
//List of Position
private List<Position> tempmoveposition;
//Discriminate if the action is a Drag or a Slide
private boolean isDragAndDrop=false;
private boolean hasMoved=false;
//time of last action such as move Mouse Down or First move
private long refTime=0;
AndroidDriver driver;
private Action action=Action.UNKNOW_ACTION;
protected int x=0;
protected int y=0;
protected int moy_x=0;
protected int moy_y=0;
protected int counter = 0;
private Position oldPosition;
private Position initialPosition;
private Action oldAction = Action.UNKNOW_ACTION;
private HashMap<String, Position> softkeyMap;
private boolean flushSent = false;
private boolean sendFlushTwiceForMouseUp = false;
/**
* Parse a 8 character hexadecimal string into an int.
* Returns -1 instead of NumberFormatException when value="FFFFFFFF"
*/
public static int parseInt(String value) {
int length = value.length();
int shift = 0;
long result = 0;
for (int i = length-1; i >= 0; i--) {
int digit = Character.digit(value.charAt(i), 16);
if (digit < 0) {
throw new NumberFormatException("unable to parse: '" + value + "' (invalid char at : " + i + ")");
}
result += ((long)digit) << shift;
shift += 4;
}
return (int)result;
}
public DefaultTouchScreenEventfilter(AndroidDriver aphone, AndroidConfHandler ges, HashMap<String, Position> softkeyMap) {
driver = aphone;
tempmoveposition = new ArrayList<Position>();
this.softkeyMap = softkeyMap;
//réecriture en hexa
if (ges.getXpattern()!=null) {
X_POSITION = convertToHexa(ges.getXpattern() );
Y_POSITION = convertToHexa(ges.getYpattern() );
} else {
XY_POSITION = convertToHexa(ges.getXYpattern() );
}
MOUSE_DOWN = convertToHexa(ges.getDownpattern() );
if(ges.getDownMaxpattern()!=null){
MOUSE_DOWN_MAX = convertToHexa(ges.getDownMaxpattern());
MOUSE_DOWN_SUFFIX_MAX = Integer.parseInt(MOUSE_DOWN_MAX.substring(10,18), 16);
MOUSE_DOWN_SUFFIX_MIN = Integer.parseInt(MOUSE_DOWN.substring(10,18), 16);
}
MOUSE_UP = convertToHexa(ges.getUppattern() );
if (ges.getFlushpattern()!=null) FLUSH_EVENT = convertToHexa(ges.getFlushpattern() );
if (ges.getFlush2pattern()!=null) FLUSH_EVENT2 = convertToHexa(ges.getFlush2pattern() );
ALLOW_PIXEL_MOVE = ges.getMoveThreshold();
sendFlushTwiceForMouseUp = ges.sendFlushTwiceForMouseUp();
Logger.getLogger(this.getClass() ).debug("DefaultTouchScreenEventfilter");
}
String convertToHexa(String dec) {
String result="";
String[] X_POSITIONs = dec.split(" ");
int position=0;
for(String element : X_POSITIONs){
try{
position++;
long x = Integer.parseInt(element);
String hexel = Long.toHexString(x);
if(position==3) {
for(int i=hexel.length() ; i<8 ;i++)
hexel = "0"+hexel;
} else {
for(int i=hexel.length() ; i<4 ;i++)
hexel = "0"+hexel;
}
//don't start with space.
if(position!=1)
result+=" ";
result+=hexel;
}catch (Exception e) {
Logger.getLogger(this.getClass()).warn("error during conversion command in hexa", e);
}
}
Logger.getLogger(this.getClass()).debug(dec+"-->"+result);
return result;
}
public enum Action {
MOUSE_DOWN, MOUSE_UP, MOUSE_MOVE,UNKNOW_ACTION//,MOUSE_DOWN_SLIDE,MOUSE_DOWN_DRAG
}
protected String splitChar(){
return ": ";
}
protected Long parseTimestamp(String s){
String timeTable[] = s.split("-");
//timeTable[0]: time in s - timeTable[1]: time in microsecond
//time in ms:
Long time = Long.parseLong(timeTable[0])*1000+Long.parseLong(timeTable[1])/1000;
return time;
}
@Override
public void processline( String line) {
Logger.getLogger(this.getClass() ).debug("processline : "+line);
String commands[] = line.split(splitChar());
String command = commands[1];
String timepart = commands[0];
Long time = parseTimestamp(timepart);
if (command.startsWith(FLUSH_EVENT) ) {
if (flushSent) {
if (sendFlushTwiceForMouseUp) action= Action.MOUSE_UP;
flushSent = false;
} else flushSent = true;
checkAction(time);
} else if (!command.startsWith(FLUSH_EVENT2)) {
flushSent = false;
if (command.startsWith(MOUSE_DOWN)) {
if (oldAction == Action.MOUSE_DOWN || oldAction == Action.MOUSE_MOVE )
action = Action.MOUSE_MOVE;
else
action= Action.MOUSE_DOWN;
}else if(command.startsWith(MOUSE_UP) ) {
if (oldAction != Action.MOUSE_MOVE && oldAction != Action.MOUSE_DOWN) action= Action.UNKNOW_ACTION;
else action= Action.MOUSE_UP;
}else if(command.startsWith(X_POSITION)) {
//Logger.getLogger(this.getClass() ).debug("Command X="+command);
x= (((int) ((float)Long.parseLong(command.substring(10),16)/driver.SCREEN_RATIO_X)));
}else if(command.startsWith(Y_POSITION)) {
//Logger.getLogger(this.getClass() ).debug("Command Y="+command);
y= (int) ((float)Long.parseLong(command.substring(10),16)/driver.SCREEN_RATIO_Y);
}else if(command.startsWith(XY_POSITION)) {
x= (int) ((float)(Long.parseLong(command.substring(10,14),16) - Long.parseLong("8000",16))/driver.SCREEN_RATIO_X);
y= (int) ((float)Long.parseLong(command.substring(14),16)/driver.SCREEN_RATIO_Y);
checkAction(time);
}else if (MOUSE_DOWN_MAX!=null){
if(command.startsWith(MOUSE_DOWN_MAX.substring(0, 10))) {
String endCommand = command.substring(10,18);
Integer valueCommand = parseInt(endCommand);
//Integer valueCommand = Integer.parseInt(endCommand);
if(valueCommand>=MOUSE_DOWN_SUFFIX_MIN && valueCommand<=MOUSE_DOWN_SUFFIX_MAX){
if (oldAction == Action.MOUSE_DOWN || oldAction == Action.MOUSE_MOVE )
action = Action.MOUSE_MOVE;
else
action= Action.MOUSE_DOWN;
} else if (valueCommand<MOUSE_DOWN_SUFFIX_MIN) { // We consider then that it is MOUSE UP event
if (oldAction != Action.MOUSE_MOVE && oldAction != Action.MOUSE_DOWN) action= Action.UNKNOW_ACTION;
else action= Action.MOUSE_UP;
}
}
}
}
}
private void perform_average() {
if (moy_x == 0) moy_x = x;
else moy_x = ((moy_x * counter) + x )/ (counter+1);
counter++;
if (moy_y == 0) moy_y = y;
else moy_y = ((moy_y * counter) + y )/ (counter+1);
counter++;
}
private void checkAction(Long time) {
if (action == Action.UNKNOW_ACTION && (oldAction == Action.MOUSE_DOWN || oldAction == Action.MOUSE_MOVE ))
action = Action.MOUSE_MOVE;
switchaction( x, y, action, time);
oldAction = action;
action= Action.UNKNOW_ACTION;
}
private void switchaction(int x,int y, Action action, Long time)
{
switch(action) {
case MOUSE_UP:
Logger.getLogger(this.getClass() ).debug("MOUSE UP x="+x+" - y="+y+" - time="+time);
if(hasMoved) {
tempmoveposition.add(new Position(x,y,(time-refTime)));
if(isDragAndDrop){
driver.phoneTouchScreenDragndrop(tempmoveposition);
} else {
driver.phoneTouchScreenSlide(tempmoveposition);
}
} else {
perform_average();
boolean isSoftKeyPress = false;
Iterator<String> keys = softkeyMap.keySet().iterator();
while (keys.hasNext() && !isSoftKeyPress) {
String key = keys.next();
Position pos = softkeyMap.get(key);
int key_x = pos.getX();
int key_y = pos.getY();
if ((key_x-ALLOW_SOFTKEY_MOVE < moy_x ) && (moy_x < key_x+ALLOW_SOFTKEY_MOVE) && (key_y-ALLOW_SOFTKEY_MOVE < moy_y ) && (moy_y < key_y+ALLOW_SOFTKEY_MOVE)) {
driver.phoneKey(key, (int) (time - refTime), 0);
isSoftKeyPress = true;
}
}
if (!isSoftKeyPress) driver.phoneTouchScreenPressed(moy_x, moy_y,time - refTime);
}
//FLUSH temp
tempmoveposition = new ArrayList<Position>();
isDragAndDrop = false;
hasMoved=false;
initialPosition=null;
oldPosition=null;
moy_x = 0;
moy_y = 0;
counter = 0;
break;
case MOUSE_DOWN:
//Start Timer
Logger.getLogger(this.getClass() ).debug("MOUSE DOWN x="+x+" - y="+y+" - time="+time);
perform_average();
oldPosition =new Position(x,y,0);
tempmoveposition.add(oldPosition);
initialPosition = oldPosition;
refTime = time;
break;
case MOUSE_MOVE:
Logger.getLogger(this.getClass() ).debug("MOUSE MOVE x="+x+" - y="+y+" - time="+time);
perform_average();
if (initialPosition==null) {
oldPosition =new Position(x,y,0);
tempmoveposition.add(oldPosition);
initialPosition = oldPosition;
refTime = time;
} else {
if(((Math.abs(initialPosition.getX()-x) >ALLOW_PIXEL_MOVE ||
Math.abs(initialPosition.getY()-y) >ALLOW_PIXEL_MOVE ))){
if (!hasMoved && (time-refTime)>PhoneInterface.TOUCHSCREEN_LONG_EVENT_MIN_TIME )
isDragAndDrop = true;
hasMoved=true;
}
if(oldPosition!=null&&
((Math.abs(oldPosition.getX()-x) >ALLOW_PIXEL_MOVE ||
Math.abs(oldPosition.getY()-y) >ALLOW_PIXEL_MOVE ))){
oldPosition =new Position(x,y,(time-refTime));
tempmoveposition.add(oldPosition);
}
}
break;
}
}
}