/* This file is part of SlumDroid <https://github.com/slumdroid/slumdroid>.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3
* as published by the Free Software Foundation.
*
* 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 General Public License <http://www.gnu.org/licenses/gpl-3.0.txt>
* for more details.
*
* Copyright (C) 2012-2016 Gennaro Imparato
*/
package it.slumdroid.tool.components.planner;
import static it.slumdroid.droidmodels.model.InteractionType.CHANGE_ORIENTATION;
import static it.slumdroid.droidmodels.model.InteractionType.LIST_LONG_SELECT;
import static it.slumdroid.droidmodels.model.InteractionType.LIST_SELECT;
import static it.slumdroid.droidmodels.model.InteractionType.PRESS_ACTION;
import static it.slumdroid.droidmodels.model.InteractionType.PRESS_BACK;
import static it.slumdroid.droidmodels.model.InteractionType.PRESS_MENU;
import static it.slumdroid.droidmodels.model.InteractionType.WRITE_TEXT;
import static it.slumdroid.droidmodels.model.SimpleType.ACTION_HOME;
import static it.slumdroid.droidmodels.model.SimpleType.DIALOG_TITLE;
import static it.slumdroid.droidmodels.model.SimpleType.PREFERENCE_LIST;
import static it.slumdroid.tool.Resources.EXTRA_INPUTS;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import android.content.pm.ActivityInfo;
import it.slumdroid.droidmodels.model.ActivityState;
import it.slumdroid.droidmodels.model.Transition;
import it.slumdroid.droidmodels.model.UserEvent;
import it.slumdroid.droidmodels.model.UserInput;
import it.slumdroid.droidmodels.model.WidgetState;
import it.slumdroid.droidmodels.testcase.TestCaseEvent;
import it.slumdroid.droidmodels.testcase.TestCaseInput;
import it.slumdroid.tool.components.abstractor.Abstractor;
import it.slumdroid.tool.components.automation.Automation;
import it.slumdroid.tool.model.EventHandler;
import it.slumdroid.tool.model.InputHandler;
import it.slumdroid.tool.utilities.AllPassFilter;
// TODO: Auto-generated Javadoc
/**
* The Class UltraPlanner.
*/
public class UltraPlanner {
/** The filters. */
protected AllPassFilter eventFilter, inputFilter;
/** The user. */
protected EventHandler user;
/** The form filler. */
protected InputHandler formFiller;
/** The abstractor. */
protected Abstractor abstractor;
/** The include action. */
protected boolean includeAction;
/** The include menu. */
protected boolean includeMenu;
/** The include rotation. */
protected boolean includeRotation;
/**
* Adds the plan for activity widgets.
*
* @param thePlanner the planner
* @param theState the state
*/
private void addPlanForActivityWidgets(Plan thePlanner, ActivityState theState) {
setIncludeAction(false);
setIncludeMenu(true);
int orientation = Automation.getCurrentActivity().getRequestedOrientation();
if (orientation == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
|| orientation == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) {
setIncludeRotation(false);
} else {
setIncludeRotation(true);
}
for (WidgetState widget: getEventFilter()) {
reductionActions(widget, theState);
Collection<UserEvent> events = getUser().handleEvent(widget);
for (UserEvent event: events) {
if (event == null) {
continue;
} else {
if (event.getType().equals(LIST_SELECT)
|| event.getType().equals(LIST_LONG_SELECT)) {
Collection<UserInput> inputs = new ArrayList<UserInput>();
Transition transition = getAbstractor().createTransition(theState, inputs, event);
thePlanner.addTransition(transition);
} else {
if (includeEvent(event)) {
adjacentValues(thePlanner, theState, event);
}
}
}
}
}
}
/**
* Reduction actions.
*
* @param theWidget the widget
* @param theState the state
*/
private void reductionActions(WidgetState theWidget , ActivityState theState) {
if (theWidget.getSimpleType().equals(ACTION_HOME)
&& theWidget.isClickable()
&& theWidget.isAvailable()) {
setIncludeAction(true);
return;
}
if (theWidget.getSimpleType().equals(DIALOG_TITLE)) {
setIncludeMenu(false);
return;
}
if (theWidget.getSimpleType().equals(PREFERENCE_LIST)) {
setIncludeMenu(false);
setIncludeRotation(false);
return;
}
}
/**
* Adjacent values.
*
* @param thePlanner the planner
* @param theState the state
* @param theEvent the event
*/
private void adjacentValues(Plan thePlanner, ActivityState theState, UserEvent theEvent) {
ArrayList<List<UserInput>> macroInputs = new ArrayList<List<UserInput>>();
int numWidgets = 0;
for(WidgetState formWidget: getInputFilter()) {
List<UserInput> alternatives = getFormFiller().handleInput(formWidget);
if(alternatives.size() != 0) {
macroInputs.add(alternatives);
numWidgets++;
}
}
Collection<UserInput> inputs = new ArrayList<UserInput>();
for(int widget = 0; widget < numWidgets; widget++) {
UserInput input = macroInputs.get(widget).get(0);
if (includeInput(input, theEvent)) {
inputs.add(input);
}
}
Transition transition = getAbstractor().createTransition(theState, inputs, theEvent);
thePlanner.addTransition(transition);
for(int widget = 0; widget < numWidgets; widget++) {
for(int inPut = 1; inPut < macroInputs.get(widget).size(); inPut++) {
Collection<UserInput> combinations = new ArrayList<UserInput>();
for(int component = 0; component < numWidgets; component++) {
if(component == widget) {
UserInput input = macroInputs.get(widget).get(inPut);
if (includeInput(input, theEvent)) {
combinations.add(input);
}
continue;
}
UserInput input = macroInputs.get(component).get(0);
if (includeInput(input, theEvent)) {
combinations.add(((TestCaseInput)input).clone());
}
}
transition = getAbstractor().createTransition(theState, combinations,((TestCaseEvent)theEvent).clone());
thePlanner.addTransition(transition);
}
}
}
/**
* Include event.
*
* @param theEvent the event
* @return true, if successful
*/
private boolean includeEvent(UserEvent theEvent) {
if (theEvent.getType().equals(WRITE_TEXT) && EXTRA_INPUTS != null) {
for (String extra: EXTRA_INPUTS) {
String[] inputs = extra.split("( )?,( )?");
if (inputs[1].equals(theEvent.getWidget().getId())) {
return false;
}
}
}
return true;
}
/**
* Include input.
*
* @param theInput the input
* @param theEvent the event
* @return true, if successful
*/
private boolean includeInput(UserInput theInput, UserEvent theEvent) {
return (theInput != null)
&& !((theInput.getWidget().getId().equals(theEvent.getWidget().getId()))
&& (theInput.getType().equals(theEvent.getType())));
}
/**
* Gets the plan for activity.
*
* @param theState the state
* @return the plan for activity
*/
public Plan getPlanForActivity(ActivityState theState) {
Plan planner = new Plan();
addPlanForActivityWidgets(planner, theState);
UserEvent event;
Transition transition;
if (isIncludeMenu()) {
event = getAbstractor().createEvent(PRESS_MENU);
transition = getAbstractor().createTransition(theState, event);
planner.addTransition(transition);
}
if (isIncludeAction()) {
event = getAbstractor().createEvent(PRESS_ACTION);
transition = getAbstractor().createTransition(theState, event);
planner.addTransition(transition);
}
if (isIncludeRotation()) {
event = getAbstractor().createEvent(CHANGE_ORIENTATION);
transition = getAbstractor().createTransition(theState, event);
planner.addTransition(transition);
}
event = getAbstractor().createEvent(PRESS_BACK);
transition = getAbstractor().createTransition(theState, event);
planner.addTransition(transition);
return planner;
}
/**
* Gets the event filter.
*
* @return the event filter
*/
public AllPassFilter getEventFilter() {
return this.eventFilter;
}
/**
* Sets the event filter.
*
* @param eventFilter the new event filter
*/
public void setEventFilter(AllPassFilter eventFilter) {
this.eventFilter = eventFilter;
}
/**
* Gets the input filter.
*
* @return the input filter
*/
public AllPassFilter getInputFilter() {
return this.inputFilter;
}
/**
* Sets the input filter.
*
* @param inputFilter the new input filter
*/
public void setInputFilter(AllPassFilter inputFilter) {
this.inputFilter = inputFilter;
}
/**
* Gets the user.
*
* @return the user
*/
public EventHandler getUser() {
return this.user;
}
/**
* Sets the user.
*
* @param user the new user
*/
public void setUser(EventHandler user) {
this.user = user;
}
/**
* Gets the form filler.
*
* @return the form filler
*/
public InputHandler getFormFiller() {
return this.formFiller;
}
/**
* Sets the form filler.
*
* @param formFiller the new form filler
*/
public void setFormFiller(InputHandler formFiller) {
this.formFiller = formFiller;
}
/**
* Gets the abstractor.
*
* @return the abstractor
*/
public Abstractor getAbstractor() {
return this.abstractor;
}
/**
* Sets the abstractor.
*
* @param abstractor the new abstractor
*/
public void setAbstractor(Abstractor abstractor) {
this.abstractor = abstractor;
}
/**
* Checks if is include action.
*
* @return true, if is include action
*/
public boolean isIncludeAction() {
return includeAction;
}
/**
* Sets the include action.
*
* @param includeAction the new include action
*/
public void setIncludeAction(boolean includeAction) {
this.includeAction = includeAction;
}
/**
* Checks if is include menu.
*
* @return true, if is include menu
*/
public boolean isIncludeMenu() {
return includeMenu;
}
/**
* Sets the include menu.
*
* @param includeMenu the new include menu
*/
public void setIncludeMenu(boolean includeMenu) {
this.includeMenu = includeMenu;
}
/**
* Checks if is include rotation.
*
* @return true, if is include rotation
*/
public boolean isIncludeRotation() {
return includeRotation;
}
/**
* Sets the include rotation.
*
* @param includeRotation the new include rotation
*/
public void setIncludeRotation(boolean includeRotation) {
this.includeRotation = includeRotation;
}
}