/*
* 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 : Emulator.java
*
* Created : 16/06/2009
* Author(s) : France Telecom
*/
package com.orange.atk.scriptRecorder;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.HeadlessException;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import java.awt.image.renderable.ParameterBlock;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Set;
import javax.media.jai.InterpolationBilinear;
import javax.media.jai.JAI;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import org.apache.log4j.Logger;
import com.orange.atk.phone.PhoneException;
import com.orange.atk.util.Position;
public class Emulator extends JFrame {
/**
*
*/
private static final long serialVersionUID = -5706132534486760234L;
private ScriptController controller;
private Screenshot imageLabel;
// final String default_image = Platform.TMP_DIR+"screenshots"+Platform.FILE_SEPARATOR+"s.jpeg";
private Date startPress= new Date();
private Date stopPress= new Date();
//for build keyboards
private Set<String> keysList;
private HashMap<String, String> keysIcons;
private boolean landscapeformat=false;
public Emulator(final RecorderFrame owner, ScriptController sc) throws HeadlessException {
super();
controller=sc;
this.setLocationRelativeTo(owner);
setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
c.gridx=0; c.gridy=0;c.gridwidth=1; c.gridheight=5;
c.fill=GridBagConstraints.BOTH; c.weightx=1; c.weighty=1;
//images
try {
imageLabel = new Screenshot((BufferedImage) sc.getPhone().screenShot());
} catch (PhoneException e) {
e.printStackTrace();
}
add(imageLabel,c);
String[] layout = sc.getPhone().getKeyLayouts();
keysIcons = sc.getPhone().getKeys();
keysList = keysIcons.keySet();
//Standards keyboards
c.gridheight=1;
c.gridx=1;
if(layout!=null) {
for(int i=0 ; i<layout.length ; i++) {
if(layout[i].equals("QWERTY"))
add(buildQwertyKeyboard(),c );
if(layout[i].equals("9KEY_NAVIGATION"))
add(build9KeyNavigation(),c);
if(layout[i].equals("ANDROID_NAVIGATION"))
add(buildAndroidNavigation(),c);
if(layout[i].equals("PHONE"))
add(buildPhoneKeyboard(),c);
c.gridy++;
}
}
//toolbar
JPanel jtb = new JPanel(new FlowLayout());
jtb.setBorder(BorderFactory.createTitledBorder("Tool bar"));
final JComboBox otherkey = new JComboBox();
otherkey.addItem("-select a key-");
//show all keys wich aren't show yet
for(String key : keysList)
otherkey.addItem(key);
otherkey.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
String key_Pressed = (String) ((JComboBox) e.getSource()).getSelectedItem();
String value_Pressed_Key = "";
for(int i = 0; i<keysIcons.size(); i++){
if (keysIcons.containsKey(key_Pressed))
value_Pressed_Key = (String) keysIcons.get(key_Pressed);
}
Logger.getLogger(this.getClass() ).debug("Press : "+key_Pressed+" Value : "+value_Pressed_Key);
startPress = new Date();
if (stopPress!=null)
controller.addEvent("Sleep("+(startPress.getTime()-stopPress.getTime())+")");
stopPress=new Date();
controller.addEvent("Key('"+value_Pressed_Key+"', 0, 0 )");
try {
controller.getPhone().keyPress(value_Pressed_Key, 0, 0);
//controller.getPhone().keyPress(key_Pressed, 0, 0);
// MMH not needed, screenshot thread do i
// setImage((BufferedImage) controller.getPhone().screenShot());
} catch (PhoneException e1) {
e1.printStackTrace();
}
otherkey.setSelectedIndex(0);
}
});
jtb.add(new JLabel("Other keys : "));
jtb.add(otherkey);
JButton rotate = new JButton("Rotate");
rotate.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent arg0) {
landscapeformat= !landscapeformat ;
// MMH not needed, screenshot thread do i
/* try {
setImage((BufferedImage) controller.getPhone().screenShot());
} catch (PhoneException e) {
Logger.getLogger(this.getClass() ).warn("error on refresh when rotate "+e.getMessage());
}*/
}
});
jtb.add(rotate);
add(jtb,c);
//Keylistener
startPress= new Date();
stopPress= new Date();
//global parameter
//setResizable(false); //do not active because rotation of the screen need a resizable window
setTitle("Emulator");
pack();
setVisible(true);
// setAlwaysOnTop(true);
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
this.addWindowListener(new WindowAdapter(){
public void windowClosed(WindowEvent arg0) {
imageLabel.stop();
owner.stop();
}
});
}
private Component buildAndroidNavigation() {
JPanel phonekeyboard = new JPanel(new GridLayout(1,5));
phonekeyboard.setBorder(BorderFactory.createTitledBorder("Android Navigation Keys") );
for (String key : new String[]{"CALL","HOME","MENU","BACK","END_CALL"}){
String icone = keysIcons.get(key);
phonekeyboard.add(new KeyTouch(icone,key));
keysList.remove(key);
}
return phonekeyboard;
}
private Component build9KeyNavigation() {
JPanel phonenavigation = new JPanel(new GridBagLayout());
phonenavigation.setBorder(BorderFactory.createTitledBorder("Phone Navigation") );
GridBagConstraints c = new GridBagConstraints();
c.gridx=0; c.gridy=0;c.weightx=1; c.weighty=0;
//softkey 1
String icone = keysIcons.get("[");
phonenavigation.add(new KeyTouch(icone,"["),c);
keysList.remove("[");
//uparrow
c.gridheight=1; c.gridx=2;
icone = keysIcons.get("^");
phonenavigation.add(new KeyTouch(icone,"^"),c);
keysList.remove("^");
//softkey 2
c.gridheight=2; c.gridx=4;
icone = keysIcons.get("]");
phonenavigation.add(new KeyTouch(icone,"]"),c);
keysList.remove("]");
//leftarrow
c.gridheight=2; c.gridx=1;c.gridy=1;
icone = keysIcons.get("<");
phonenavigation.add(new KeyTouch(icone,"<"),c);
keysList.remove("<");
//rightarrow
c.gridx=3;
icone = keysIcons.get(">");
phonenavigation.add(new KeyTouch(icone,">"),c);
keysList.remove(">");
//centerpress
c.gridx=2;
icone = keysIcons.get(":J");
phonenavigation.add(new KeyTouch(icone,":J"),c);
keysList.remove(":J");
//green phone key
/*c.gridheight=2; c.gridx=0;c.gridy=2;
icone = keysIcons.get(":J");
phonenavigation.add(new KeyTouch(icone,":J"),c);
keysList.remove(":J");
*/
//down arrow
c.gridheight=1; c.gridx=2;c.gridy=3;
icone = keysIcons.get("V");
phonenavigation.add(new KeyTouch(icone,"V"),c);
keysList.remove("V");
//red phone key
c.gridheight=2; c.gridx=4;c.gridy=2;
icone = keysIcons.get("E");
phonenavigation.add(new KeyTouch(icone,"E"),c);
keysList.remove("E");
return phonenavigation;
}
/**
*
* @return a JPanel representing a phone number keyboard
*/
private JPanel buildPhoneKeyboard() {
JPanel phonekeyboard = new JPanel(new GridLayout(4,3));
phonekeyboard.setBorder(BorderFactory.createTitledBorder("Phone Number Keys") );
for (String key : new String[]{"1","2","3","4","5","6","7","8","9","*","0","#"}){
String icone = keysIcons.get(key);
phonekeyboard.add(new KeyTouch(icone,key));
keysList.remove(key);
}
return phonekeyboard;
}
private Component buildQwertyKeyboard() {
JPanel Qwertykeyboard = new JPanel(new GridBagLayout());
Qwertykeyboard.setBorder(BorderFactory.createTitledBorder("Qwerty Keyboard") );
GridBagConstraints c = new GridBagConstraints();
c.gridx=0; c.gridy=0;c.gridwidth=1; c.gridheight=1;
c.fill=GridBagConstraints.BOTH; c.weightx=0.1; c.weighty=0.1;
int i=0;
for (String key : new String[]{"1","2","3","4","5","6","7","8","9","0",
"Q","W","E","R","T","Y","U","I","O","P",
"A", "S", "D", "F", "G", "H", "J", "K", "L","DEL",
"Z", "X", "C", "V", "B", "N", "M", "COMMA","ENTER",
"SHIFT_L", "ALT_L", "SEARCH", "@","SPACE", "POINT", "ALT_R","SHIFT_R"}){
String icone = keysIcons.get(key);
c.gridy = (int) i/10;
c.gridx = i %10;
if (key.equals("ENTER"))
c.gridwidth=2;
if (key.equals(" "))
c.gridwidth=3;
Qwertykeyboard.add(new KeyTouch(icone,key), c);
i++;
if(key.equals("ENTER")) {
i++;
c.gridwidth=1;
}
if(key.equals(" ")) {
i=i+2;
c.gridwidth=1;
}
keysList.remove(key);
}
//TODO: find a synchronization
try {//Time to load every Image by the Toolkit
Thread.sleep(50);
} catch (InterruptedException e) {
}
return Qwertykeyboard;
}
public void setImage(Image im){
// Logger.getLogger(this.getClass() ).debug(default_image);
imageLabel.setImage(im,landscapeformat);
pack();
}
/**
* class represent button when pressed
* @author Moreau Fabien - GFI - FMOREAU@gfi.fr
*
*/
class KeyTouch extends JPanel {
private static final long serialVersionUID = 7533329665423237475L;
private Image img = null;
private String key_Pressed;
KeyTouch(String path, String key) {
super();
key_Pressed = key;
img = getToolkit().createImage(getClass().getResource(path));
addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
Logger.getLogger(this.getClass() ).debug("Press :"+key_Pressed);
startPress = new Date();
if (stopPress!=null)
controller.addEvent("Sleep("+(startPress.getTime()-stopPress.getTime())+")");
stopPress=new Date();
controller.addEvent("Key('"+key_Pressed+"', 0, 0 )");
try {
controller.getPhone().keyPress(key_Pressed, 0, 0);
} catch (PhoneException e1) {
e1.printStackTrace();
}
}
});
setMinimumSize(new Dimension(img.getWidth(this), img.getHeight(this)));
}
public void paint(Graphics g) {
super.paintComponent(g);
if(img != null)
g.drawImage(img, 0, 0, this);
}
public Dimension getPreferredSize() {
//Logger.getLogger(this.getClass() ).debug("getpreferedsize(on "+key_Pressed + " "+img.getWidth(this)+" "+img.getHeight(this));
return new Dimension(img.getWidth(this),img.getHeight(this));
}
}
/**
* class showing screenshot
* @author Moreau Fabien - GFI - FMOREAU@gfi.fr
*
*/
class Screenshot extends JPanel {
private static final long serialVersionUID = 5714691002759634005L;
private Image img = null;
private Thread autorefresh;
private boolean done = false;
public Screenshot(Image im) {
super();
img = im;
addMouseListener(new MouseAdapter(){
private int yorigin;
private int xorigin;
public void mousePressed(MouseEvent arg0) {
Logger.getLogger(this.getClass() ).debug("mousePress"+arg0.getX()+","+arg0.getY());
startPress=new Date();
xorigin=arg0.getX();
yorigin=arg0.getY();
if (stopPress!=null)
controller.addEvent("Sleep("+(startPress.getTime()-stopPress.getTime())+")");
}
public void mouseReleased(MouseEvent arg0) {
Logger.getLogger(this.getClass() ).debug("mouseRelease"+arg0.getX()+","+arg0.getY());
ArrayList<Position> positions = new ArrayList<Position>();
stopPress=new Date();
int x=arg0.getX();
int y=arg0.getY();
if (x!=xorigin && y!=yorigin && arg0.getButton() != MouseEvent.BUTTON1){
//Slide
Logger.getLogger(this.getClass() ).debug("listener.runSlide");
//controller.addEvent("SlideEvent",new String[]{""+xorigin,""+yorigin,""+x,""+y});
try {
Position posOrigin = new Position(xorigin, yorigin, 0);
Position posFinal = new Position(x, y, 0);
positions.add(posOrigin);
positions.add(posFinal);
controller.getPhone().touchScreenSlide(positions);
refresh();
} catch (PhoneException e) {
e.printStackTrace();
}
}else{
//Mouse
Logger.getLogger(this.getClass() ).debug("listener.runMousereleased");
//controller.addEvent("Mouse",new String[]{""+xorigin,""+yorigin});
try {
controller.getPhone().touchScreenPress(new Position(x, y,stopPress.getTime() - startPress.getTime()));
refresh();
} catch (PhoneException e) {
e.printStackTrace();
}
}
}
});
//Auto-Refresh (3 fps to 4 fps)
autorefresh = new Thread(){
@Override
public void run() {
try {
while(!done) {
Image phoneimg = (BufferedImage) controller.getPhone().screenShot() ;
setImage(phoneimg, landscapeformat);
repaint();
sleep(100);
}
//interupt in order to stop it
} catch (InterruptedException e) {
Logger.getLogger(this.getClass() ).warn("screenshot auto refresh interrupted");
} catch (PhoneException e) {
Logger.getLogger(this.getClass() ).warn("screenshot auto refresh error");
}
}
};
autorefresh.setPriority(Thread.MIN_PRIORITY);
autorefresh.setDaemon(true);
autorefresh.start();
}
public void refresh(){
try {
Image phoneimg = (BufferedImage) controller.getPhone().screenShot() ;
setImage(phoneimg, landscapeformat);
repaint();
} catch (PhoneException e) {
Logger.getLogger(this.getClass() ).warn("screenshot auto refresh error");
}
}
public void stop() {
done = true;
}
public void paint(Graphics g) {
super.paintComponent(g);
if(img != null)
g.drawImage(img, 0, 0, this);
}
public Dimension getPreferredSize() {
if(img != null) {
//Logger.getLogger(this.getClass() ).debug("get pref size screenshot"+img.getWidth(this)+" "+img.getHeight(this) );
return new Dimension(img.getWidth(this),img.getHeight(this));
}
return new Dimension(20,20);
}
public void setImage(Image img, boolean Landscapeformat) {
if(Landscapeformat) {
float angle = (float) Math.toRadians(-90);
// Gets the rotation center.
float centerX = img.getWidth(this) / 2f;
float centerY = img.getHeight(this) / 2f;
// Rotates the original image.
ParameterBlock pb = new ParameterBlock();
pb.addSource(img);
pb.add(centerX);
pb.add(centerY);
pb.add(angle);
pb.add(new InterpolationBilinear());
// Creates a new, rotated image and uses it on the DisplayJAI component
this.img = JAI.create("rotate", pb).getAsBufferedImage();
} else {
this.img = img;
}
repaint();
}
}
}