/* MonkeyTalk - a cross-platform functional testing tool
Copyright (C) 2012 Gorilla Logic, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
package com.gorillalogic.fonemonkey.automators;
import android.app.Activity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MenuItem.OnMenuItemClickListener;
import android.view.SubMenu;
import com.gorillalogic.fonemonkey.ActivityManager;
import com.gorillalogic.fonemonkey.Log;
import com.gorillalogic.fonemonkey.exceptions.FoneMonkeyScriptFailure;
import com.gorillalogic.monkeytalk.automators.AutomatorConstants;
/**
*
* Works in conjunction with WindowAutomator to provide menu recording.
*
* @author sstern
*
*/
public class MenuAutomator extends AutomatorBase implements OnMenuItemClickListener {
@Override
public int getOrdinal() {
return 1;
}
@Override
public void record(String operation, String... args) {
super.record(operation, getMenuItem() == null ? super.getMonkeyID() : getMenuItem()
.getTitle().toString());
}
private static Class<?> componentClass = MenuItem.class;
static {
Log.log("Initializing MenuAutomator");
}
@Override
public String getComponentType() {
return AutomatorConstants.TYPE_MENU;
}
public MenuItem getMenuItem() {
return (MenuItem) getComponent();
}
@Override
public Class<?> getComponentClass() {
return componentClass;
}
@Override
public String play(String action, String... args) {
if (action.equalsIgnoreCase(AutomatorConstants.ACTION_SELECT)
|| action.equalsIgnoreCase(AutomatorConstants.ACTION_SELECT_INDEX)) {
assertArgCount(action, args, 1);
final String title = args[0];
final Activity activity = AutomationManager.getTopActivity();
if (activity == null) {
throw new IllegalStateException("Unable to find top activity");
}
Menu menu = ActivityManager.getCurrentMenu();
if (menu == null) {
throw new FoneMonkeyScriptFailure("Unable to find menu.");
}
int size = menu.size();
int itemId = -1;
if (action.equals(AutomatorConstants.ACTION_SELECT)) {
outer: for (int i = 0; i < size; i++) {
MenuItem item = menu.getItem(i);
if (item.getTitle().toString().equals(title)) {
itemId = item.getItemId();
break;
}
// HACK: just brute force down some more (so: menus, sub-menus, sub-sub-menus)
if (item.hasSubMenu()) {
SubMenu sub = item.getSubMenu();
for (int j = 0; j < sub.size(); j++) {
MenuItem subitem = sub.getItem(j);
if (subitem.getTitle().toString().equals(title)) {
itemId = subitem.getItemId();
sub.close();
break outer;
}
if (subitem.hasSubMenu()) {
SubMenu subsub = subitem.getSubMenu();
for (int k = 0; k < subsub.size(); k++) {
MenuItem subsubitem = subsub.getItem(k);
if (subsubitem.getTitle().toString().equals(title)) {
itemId = subsubitem.getItemId();
subsub.close();
sub.close();
break outer;
}
}
}
}
}
}
if (itemId == -1) {
String msg = getComponentType()
+ " selection failed. Unable to find item with title: " + title;
throw new FoneMonkeyScriptFailure(msg);
}
} else {
if (args.length == 0) {
throw new FoneMonkeyScriptFailure(AutomatorConstants.ACTION_SELECT_INDEX
+ " requires an argument specifying the index to select");
}
String index = args[0];
int i;
try {
i = Integer.valueOf(index);
} catch (NumberFormatException e) {
throw new FoneMonkeyScriptFailure(AutomatorConstants.ACTION_SELECT_INDEX
+ ": index argument must be an integer. Found \"" + index + "\"");
}
if (i > size || i < 1) {
throw new FoneMonkeyScriptFailure("Invalid index " + index
+ " specified. Menu has " + size + " items");
}
itemId = menu.getItem(i - 1).getItemId();
}
AutomationManager.runOnUIThread(new Runnable() {
public void run() {
activity.openOptionsMenu();
}
});
// HACK: wait a little for menu to open
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// ignore
}
final int id = itemId;
final Menu m = menu;
AutomationManager.runOnUIThread(new Runnable() {
public void run() {
activity.closeOptionsMenu();
m.performIdentifierAction(id, Menu.NONE);
}
});
return null;
}
return super.play(action, args);
}
/*
* (non-Javadoc)
*
* @see android.view.MenuItem.OnMenuItemClickListener#onMenuItemClick(android.view.MenuItem)
*/
@Override
public boolean onMenuItemClick(MenuItem item) {
record(AutomatorConstants.ACTION_LONG_SELECT, getMenuItem() == null ? super.getMonkeyID()
: getMenuItem().getTitle().toString());
return false;
}
@Override
public String getValue() {
final Activity activity = AutomationManager.getTopActivity();
if (activity == null) {
throw new IllegalStateException("Unable to find top activity");
}
String value = "";
Menu menu = ActivityManager.getCurrentMenu();
// get titles for menu items to return
for (int i = 0; i < menu.size(); i++) {
value += menu.getItem(i);
if (i < menu.size() - 1)
value += ", ";
}
return value;
}
}