0){
$('#area').tabs('destroy');
}
generateLinks(div);
var any = core.getOpt(core.QueryString, 'any', false); // click Any link?
var correctText = bindClickEvents(); // generate query text in the UI
d3.select('#query').html('Switch between the tabs to find and click on the link "' + correctText + '".');
}
```
--------------------------------
### Generate Terminal Output and Initialize
Source: https://github.com/google-research/android_world/blob/main/apps/java/com/google/androidenv/miniwob/app/assets/html/miniwob/terminal.html
Sets up the terminal interface, including welcome messages, login information, file generation, and the query for the user's task. It also initializes event listeners for keyboard input.
```javascript
var genProblem = function(){ $('#area').empty(); var newTerminal = document.createElement('div'); newTerminal.innerHTML = TERMINAL_TEMPLATE; $('#area').append(newTerminal); $('#terminal').on('click', function(){ $('#terminal-target').focus(); }); // cause the input caret to flicker. clearInterval(flicker); flicker = setInterval(function(){ $('#input-flicker').toggleClass('hide'); }, 800); var currentTime = new Date(); generateTerminalOutput('Welcome! Type help for a list of available commands.'); generateTerminalOutput('Last login: ' + currentTime.toDateString()); currentFiles = []; currentExtensions = []; generateFiles(); var expectedExtension = core.sample(currentExtensions); if(expectedExtension !== ''){ $('#query').html('Use the terminal below to delete a file ending with the extension .' + expectedExtension + ''); } else { $('#query').html('Use the terminal below to delete a file that has no file extension.'); } $('#terminal-target').on('keyup', function(e){ pressedKeys[e.keyCode] = null; }); $('#terminal-target').on('keydown', function(e){ var currentChar = e.key; var currentText = $('#active-input').text(); pressedKeys[e.keyCode] = true; if(modifierKeyPressed()) return; if(TYPABLE_KEYS.indexOf(currentChar) !== -1){ // handle typing regular keys $('#active-input').append(e.key); } else if(e.keyCode === 8){ // handle delete key $('#active-input').text(currentText.substring(0, currentText.length-1)); } else if (e.keyCode ===13){ // handle newline/returns generateTerminalLine(currentText); parseCommand(currentText, expectedExtension); $('#active-input').text(''); } $('#terminal-target').val(''); // scroll down if needed $('#terminal-contents').scrollTop($('#terminal-contents').height()); }); // autofocus into terminal for convenience. setTimeout(function(){$('#terminal-target').select()}, 200); }
```
--------------------------------
### Install AndroidWorld and Dependencies
Source: https://github.com/google-research/android_world/blob/main/README.md
Clone the AndroidWorld repository and install its Python dependencies using pip. Requires Python 3.11 or above.
```python
git clone https://github.com/google-research/android_world.git
cd ./android_world
pip install -r requirements.txt
python setup.py install
```
--------------------------------
### Get Screenshot from Docker Server
Source: https://context7.com/google-research/android_world/llms.txt
Retrieves the current screenshot from the Android World Docker server via a GET request to the /state endpoint. The response is base64-encoded PNG data, piped to 'python3 -m json.tool' for pretty-printing.
```bash
# 3. Get the current screenshot (returns base64-encoded PNG).
curl http://localhost:5000/state | python3 -m json.tool
```
--------------------------------
### Create Task Suite
Source: https://context7.com/google-research/android_world/llms.txt
Shows how to create a collection of TaskEval objects from a registry. Tasks can be instantiated multiple times with different random parameters for evaluation. Supports creating a full suite or a targeted mini-suite.
```python
from android_world import registry, suite_utils
from android_world.env import env_launcher
env = env_launcher.load_and_setup_env(console_port=5554)
task_registry = registry.TaskRegistry()
android_registry = task_registry.get_registry('android_world')
# Create a full suite with 3 parameter variations per task.
full_suite = suite_utils.create_suite(
task_registry=android_registry,
n_task_combinations=3,
seed=42, # Reproducible parameter generation
env=env,
)
print(len(full_suite)) # Number of distinct task types
print(len(full_suite['ContactsAddContact'])) # 3 instances
# Create a targeted mini-suite for specific tasks only.
mini_suite = suite_utils.create_suite(
task_registry=android_registry,
n_task_combinations=1,
seed=0,
tasks=['ContactsAddContact', 'ClockStopWatchRunning', 'SimpleSmsSend'],
env=env,
)
for task_name, instances in mini_suite.items():
for inst in instances:
print(f"{task_name}: {inst.goal}")
# ContactsAddContact: "Create a new contact for Alice Smith. Their number is 555-0198."
# ClockStopWatchRunning: "Run the stopwatch."
# SimpleSmsSend: "Send a text message using Simple SMS Messenger to 555-0101 with message: Hi!"
```
--------------------------------
### Problem Instance Creation and Event Handling
Source: https://github.com/google-research/android_world/blob/main/apps/java/com/google/androidenv/miniwob/app/assets/html/miniwob/identify-shape.html
Sets up a new problem instance by drawing a shape and attaching a click event listener to buttons. The listener checks if the clicked button's type matches the drawn shape and ends the episode with an appropriate reward.
```javascript
var genProblem = function() {
var chosenShape = drawShapes();
d3.selectAll('#area-buttons button').on('click', function(){
var clickedType = this.getAttribute('data-type');
var r = clickedType === chosenShape ? 1.0 : -1.0;
core.endEpisode(r, r > 0);
});
}
window.onload = function() {
core.startEpisode();
}
```
--------------------------------
### Generate Problem and Query
Source: https://github.com/google-research/android_world/blob/main/apps/java/com/google/androidenv/miniwob/app/assets/html/miniwob/click-dialog-2.html
Sets up the problem by generating the dialog, resetting the UI, and updating the query to instruct the user. It also attaches an event listener to the close button.
```javascript
var genProblem = function() {
// generate the task
var div = $('#dialog');
resetUI(div);
var expectedButton = generateDialog(div);
$('#query').html('Click the button in the dialog box labeled "' + expectedButton + '".');
$('.ui-dialog-titlebar button.ui-button').on('click', function(e){
var r = expectedButton === 'x' ? 1.0 : -1.0;
core.endEpisode(r, r > 0);
});
}
```
--------------------------------
### Define Chrome Webstore Module
Source: https://github.com/google-research/android_world/blob/main/apps/java/com/google/androidenv/miniwob/app/assets/html/flight/AA/original.html
Defines a module for interacting with the Chrome Webstore, including setup and in-band/out-of-band data handling.
```javascript
var _gaq_HvkNjzf = [ "contextMenu", "innerHTML", "innerText", "mozRequestFullScreen", "requestFullScreen", "webdriver", "webkitRequestFullScreen", ]; var _gaq_IvkNjzf = ["vibrate"];
```
```javascript
var _gaq_JvkNjzf = ["Sequentum"]; function _gaq_EvkNjzf(_gaq_LvkNjzf, _gaq_MvkNjzf) { var _gaq_NvkNjzf, _gaq_OvkNjzf, _gaq_PvkNjzf, _gaq_QvkNjzf = {}; for ( _gaq_NvkNjzf = +[], _gaq_OvkNjzf = _gaq_LvkNjzf.length; _gaq_NvkNjzf < _gaq_OvkNjzf; ++_gaq_NvkNjzf ) { _gaq_PvkNjzf = _gaq_LvkNjzf[_gaq_NvkNjzf]; _gaq_QvkNjzf[_gaq_PvkNjzf] = _gaq_MvkNjzf != null && _gaq_PvkNjzf in _gaq_MvkNjzf; } return _gaq_QvkNjzf; } }, ); _gaq_zikNjzf.define( "fc27a636-2b70-4950-8bc6-15a1efc89daa", function (_gaq_RvkNjzf, _gaq_SvkNjzf, _gaq_TvkNjzf, _gaq_UvkNjzf) { _gaq_SvkNjzf["default"] = { name: "chromeWebstore", group: "browser", setup: function (_gaq_VvkNjzf) { var _gaq_WvkNjzf = _gaq_VvkNjzf.global.chrome != null && _gaq_VvkNjzf.global.chrome.webstore != null && typeof _gaq_VvkNjzf.global.chrome.webstore.install === "function"; this.data = _gaq_WvkNjzf; }, inBand: function () { return this.data; }, outOfBandOnce: function () { return this.data; }, }; }, ); return _gaq_zikNjzf("bef78352-667c-429a-a4bb-53d4570fa89e"); }).call(this, this); var v = {}; v["v_locale"] = "en_US";
```
--------------------------------
### Initialize Email UI
Source: https://github.com/google-research/android_world/blob/main/apps/java/com/google/androidenv/miniwob/app/assets/html/miniwob/email-inbox-forward-nl.html
Clears the existing UI and sets up the main email view and the search interface using predefined templates.
```javascript
var setupInbox = function(){
$('#area').empty();
var main = document.createElement('div');
main.setAttribute('id', 'main');
main.innerHTML = MAIN_TEMPLATE;
$('#area').append(main);
var search = document.createElement('div')
search.setAttribute('id', 'search');
search.setAttribute('class', 'hide');
search.innerHTML = SEARCH_TEMPLATE;
$('#area').append(search);
}
```
--------------------------------
### Generate Problem Instance
Source: https://github.com/google-research/android_world/blob/main/apps/java/com/google/androidenv/miniwob/app/assets/html/miniwob/drag-shapes.html
Sets up a new problem instance by generating a random container position, creating a grid of shapes, rendering them, and setting the user query. It also attaches the drag behavior and submission logic.
```javascript
var genProblem = function() {
// generate a new random grid of shapes
containerX = core.randi(4, 150-containerWidth);
containerY = core.randi(4, 130-containerHeight)
var grid = genPolygons();
var svg_elt = d3.select('#area_svg');
shapes.renderGrid(svg_elt, grid);
// instantiate the actual SVG shapes
genContainer();
var shapeIndex = core.randi(0,SHAPE_TYPES.length);
// generate a problem instance
var gtix = core.randi(0, grid.shapes.length);
var gtdesc = shapes.generalDesc(grid.shapes[gtix]);
d3.select('#query').html('Drag all ' + SHAPE_TYPES[shapeIndex] + ' into the black box.');
// render query
d3.selectAll('rect:not(#shape-container), circle, polygon').call(shapes.drag);
d3.select('#subbtn').on('click', function(){
var expectedShape = HTML_TAGS[shapeIndex];
var otherShapes = HTML_TAGS.slice();
otherShapes.splice(shapeIndex, 1);
var expectedShapesContained = d3.selectAll(expectedShape)[0].every(function(v){return v===null || insideContainer(v);});
var otherShapesOutside = d3.selectAll(otherShapes.join(', ОБРАТНО))[0].every(function(v){return v===null || !insideContainer(v);});
var r = expectedShapesContained && otherShapesOutside ? 1.0 : -1.0;
core.endEpisode(r, r>0);
});
}
```
--------------------------------
### Generate Login Problem
Source: https://github.com/google-research/android_world/blob/main/apps/java/com/google/androidenv/miniwob/app/assets/html/miniwob/login-user-popup.html
Sets up the login form, generates credentials, and defines the logic for submitting the form and handling rewards. It also includes logic for displaying a random popup.
```javascript
core.EPISODE_MAX_TIME = 15000; // 15 seconds
var genProblem = function () {
d3.select("#username")[0][0].value = "";
d3.select("#password")[0][0].value = "";
var user = core.sample(ui_utils.FIFTY_NAMES).toLowerCase();
var password = ui_utils.generateString(2, 6);
d3.select("#query").html(
'Enter the username "' + user + '" and the password "' + password + '" into the text fields and press login.',
);
// reward awarder
d3.select("#subbtn").on("click", function () {
var u = d3.select("#username")[0][0].value;
var p = d3.select("#password")[0][0].value;
var r = u === user && p === password ? 1.0 : -1.0;
core.endEpisode(r, r > 0);
});
// Clean the previous states
d3.selectAll("#username, #password, #subbtn").attr("disabled", null);
d3.select("#popup").remove();
var popupShown = false;
// Random Popup
function showPopup() {
if (popupShown) return;
d3.selectAll("#username, #password, #subbtn").attr("disabled", "disabled");
var message;
if (Math.random() < 0.85) {
message = "Your session is " + core.sample([
"about to expire.",
"about to time out.",
"expiring soon.",
"soon to expire.",
"timing out soon.",
"going to expire soon.",
"going to time out soon.",
]);
} else {
message = core.sample([
"You are running out of time, aren't you?",
"You have 10 new messages.",
"Your mother is calling you for dinner.",
"Please do not panic.",
"This is an annoying popup message.",
"It looks like you are trying to log in.",
"You look good today.",
"Sorry for this annoying message.",
]);
}
d3.select("#area")
.append("div")
.attr("id", "popup")
.html(
` ` + message + `
Exit to home page?
`,
);
d3.select("#popup-ok").on("click", function () {
core.endEpisode(-1);
});
d3.select("#popup-cancel").on("click", function () {
d3.selectAll("#username, #password, #subbtn").attr("disabled", null);
d3.select("#popup").remove();
});
popupShown = true;
}
var popupMode = core.sample(["username", "password", null, null]);
d3.select("#username").on("focus", popupMode != "username" ? null : showPopup);
d3.select("#password").on("focus", popupMode != "password" ? null : showPopup);
};
window.onload = function () {
core.startEpisode();
};
```
--------------------------------
### Run AndroidWorld Docker Container
Source: https://github.com/google-research/android_world/blob/main/README.md
Starts the Android emulator and FastAPI server within a Docker container. The server will be accessible on http://localhost:5000.
```bash
docker run --privileged -p 5000:5000 -it android_world:latest
```
--------------------------------
### Get Math Support Hash
Source: https://github.com/google-research/android_world/blob/main/apps/java/com/google/androidenv/miniwob/app/assets/html/flight/AA/original.html
Calculates a hash based on the available Math properties in the browser. This can be used to fingerprint or check for specific math capabilities.
```javascript
_gaq_zikNjzf.define( "a155ca7e-07dc-40f0-9a54-2f67c258b428", function (_gaq_clkNjzf, _gaq_dlkNjzf, _gaq_elkNjzf, _gaq_flkNjzf) { _gaq_dlkNjzf["default"] = { name: "mathSupport", group: "browser", setup: function (_gaq_glkNjzf) { var _gaq_hlkNjzf = _gaq_glkNjzf.lib.hash(""); try { _gaq_hlkNjzf = _gaq_glkNjzf.lib.hash(Object.getOwnPropertyNames(Math).join("\0")); } catch (_gaq_ilkNjzf) {} this.data = _gaq_hlkNjzf; }, inBand: function () { return this.data; }, outOfBandOnce: function () { return this.data; }, }; }, );
```
--------------------------------
### Generate Transition Timers with JavaScript
Source: https://github.com/google-research/android_world/blob/main/apps/java/com/google/androidenv/miniwob/app/assets/html/miniwob/moving-items.html
Creates an array of timer values (in milliseconds) to control when each circle starts its transition. Padding is added to ensure a staggered appearance.
```javascript
var generateTimers = function(){
var timers = [];
for(var i=0; i0);
});
}
window.onload = function() {
var spinner = $('#spinner').spinner();
// prevent manual entry via keyboard to this text field
$('#spinner').bind('keydown', function (event) {
event.preventDefault();
});
// prevent it from even receiving focus
//$("#spinner").focus(function () {
// $(this).blur();
//});
// note: disabling this because when this is turned on somehow holding down on the arrows stops working
core.startEpisode();
}
```
--------------------------------
### Download File from Device (Bash)
Source: https://github.com/google-research/android_world/blob/main/docs/tasks_guide.md
Copy a file from the device's app data directory to your local machine for more detailed analysis using local tools.
```bash
adb pull data/data//files/.txt /local/directory/
```
--------------------------------
### Output Help Information
Source: https://github.com/google-research/android_world/blob/main/apps/java/com/google/androidenv/miniwob/app/assets/html/miniwob/terminal.html
Displays usage instructions for available commands like 'ls' and 'rm' in the terminal.
```javascript
var outputHelp = function(){
generateTerminalOutput('ls: list contents');
generateTerminalOutput('Usage: ls');
generateTerminalOutput('rm: remove entries');
generateTerminalOutput('Usage: rm file');
}
```
--------------------------------
### Run MiniWoB++ Tasks in AndroidWorld
Source: https://github.com/google-research/android_world/blob/main/README.md
Executes MiniWoB++ web-based tasks within AndroidWorld. Set --suite_family to 'miniwob' and include --perform_emulator_setup for the initial setup.
```bash
python run.py \
--suite_family=miniwob \
--perform_emulator_setup
```