diff --git a/apps/Fallback/res/values-cs/strings.xml b/apps/Fallback/res/values-cs/strings.xml
index b9d34f940..1fc121cf0 100644
--- a/apps/Fallback/res/values-cs/strings.xml
+++ b/apps/Fallback/res/values-cs/strings.xml
@@ -15,7 +15,7 @@
-->
- "Záloha"
- "Akce není podporována"
- "Tato akce není momentálně podporována."
+ "Záloha"
+ "Akce není podporována"
+ "Tato akce není momentálně podporována."
diff --git a/apps/Fallback/res/values-da/strings.xml b/apps/Fallback/res/values-da/strings.xml
index b3dfa6313..4584e6130 100644
--- a/apps/Fallback/res/values-da/strings.xml
+++ b/apps/Fallback/res/values-da/strings.xml
@@ -15,7 +15,7 @@
-->
- "Reserve"
- "Ikke understøttet handling"
- "Handlingen er ikke understøttet i øjeblikket."
+ "Reserve"
+ "Ikke understøttet handling"
+ "Handlingen er ikke understøttet i øjeblikket."
diff --git a/apps/Fallback/res/values-de/strings.xml b/apps/Fallback/res/values-de/strings.xml
index 8d59ddf39..90bbb165e 100644
--- a/apps/Fallback/res/values-de/strings.xml
+++ b/apps/Fallback/res/values-de/strings.xml
@@ -15,7 +15,7 @@
-->
- "Fallback"
- "Nicht unterstützte Aktion"
- "Diese Aktion wird zurzeit nicht unterstützt."
+ "Fallback"
+ "Nicht unterstützte Aktion"
+ "Diese Aktion wird zurzeit nicht unterstützt."
diff --git a/apps/Fallback/res/values-el/strings.xml b/apps/Fallback/res/values-el/strings.xml
index fecaf4af4..b985af7be 100644
--- a/apps/Fallback/res/values-el/strings.xml
+++ b/apps/Fallback/res/values-el/strings.xml
@@ -15,7 +15,7 @@
-->
- "Εναλλακτική"
- "Ενέργεια που δεν υποστηρίζεται"
- "Αυτή η ενέργεια δεν υποστηρίζεται αυτήν τη στιγμή."
+ "Εναλλακτική"
+ "Ενέργεια που δεν υποστηρίζεται"
+ "Αυτή η ενέργεια δεν υποστηρίζεται αυτήν τη στιγμή."
diff --git a/apps/Fallback/res/values-es-rUS/strings.xml b/apps/Fallback/res/values-es-rUS/strings.xml
index 0ce57511e..d15a287e4 100644
--- a/apps/Fallback/res/values-es-rUS/strings.xml
+++ b/apps/Fallback/res/values-es-rUS/strings.xml
@@ -15,7 +15,7 @@
-->
- "Fallback"
- "Acción no admitida"
- "Esa acción no se admite actualmente."
+ "Fallback"
+ "Acción no admitida"
+ "Esa acción no se admite actualmente."
diff --git a/apps/Fallback/res/values-es/strings.xml b/apps/Fallback/res/values-es/strings.xml
index 0ce57511e..d15a287e4 100644
--- a/apps/Fallback/res/values-es/strings.xml
+++ b/apps/Fallback/res/values-es/strings.xml
@@ -15,7 +15,7 @@
-->
- "Fallback"
- "Acción no admitida"
- "Esa acción no se admite actualmente."
+ "Fallback"
+ "Acción no admitida"
+ "Esa acción no se admite actualmente."
diff --git a/apps/Fallback/res/values-fr/strings.xml b/apps/Fallback/res/values-fr/strings.xml
index 024ae4203..df1e299cd 100644
--- a/apps/Fallback/res/values-fr/strings.xml
+++ b/apps/Fallback/res/values-fr/strings.xml
@@ -15,7 +15,7 @@
-->
- "Application de secours"
- "Action non prise en charge"
- "Cette action n\'est actuellement pas prise en charge."
+ "Application de secours"
+ "Action non prise en charge"
+ "Cette action n\'est actuellement pas prise en charge."
diff --git a/apps/Fallback/res/values-it/strings.xml b/apps/Fallback/res/values-it/strings.xml
index d216e59d1..2d08c1bf4 100644
--- a/apps/Fallback/res/values-it/strings.xml
+++ b/apps/Fallback/res/values-it/strings.xml
@@ -15,7 +15,7 @@
-->
- "Fallback"
- "Azione non supportata"
- "L\'azione non è al momento supportata."
+ "Fallback"
+ "Azione non supportata"
+ "L\'azione non è al momento supportata."
diff --git a/apps/Fallback/res/values-ja/strings.xml b/apps/Fallback/res/values-ja/strings.xml
index 79aeb42ee..f22090929 100644
--- a/apps/Fallback/res/values-ja/strings.xml
+++ b/apps/Fallback/res/values-ja/strings.xml
@@ -15,7 +15,7 @@
-->
- "Fallback"
- "サポートされていない操作"
- "現在サポートされていない操作です。"
+ "Fallback"
+ "サポートされていない操作"
+ "現在サポートされていない操作です。"
diff --git a/apps/Fallback/res/values-ko/strings.xml b/apps/Fallback/res/values-ko/strings.xml
index ec1c33046..2c2973fa9 100644
--- a/apps/Fallback/res/values-ko/strings.xml
+++ b/apps/Fallback/res/values-ko/strings.xml
@@ -15,7 +15,7 @@
-->
- "폴백"
- "지원되지 않는 작업"
- "이 작업은 현재 지원되지 않습니다."
+ "폴백"
+ "지원되지 않는 작업"
+ "이 작업은 현재 지원되지 않습니다."
diff --git a/apps/Fallback/res/values-nb/strings.xml b/apps/Fallback/res/values-nb/strings.xml
index 6fed6609a..02814e606 100644
--- a/apps/Fallback/res/values-nb/strings.xml
+++ b/apps/Fallback/res/values-nb/strings.xml
@@ -15,7 +15,7 @@
-->
- "Fallback"
- "Ustøttet handling"
- "Denne handlingen er ikke støttet nå."
+ "Fallback"
+ "Ustøttet handling"
+ "Denne handlingen er ikke støttet nå."
diff --git a/apps/Fallback/res/values-nl/strings.xml b/apps/Fallback/res/values-nl/strings.xml
index f347964e4..8989efd80 100644
--- a/apps/Fallback/res/values-nl/strings.xml
+++ b/apps/Fallback/res/values-nl/strings.xml
@@ -15,7 +15,7 @@
-->
- "Reserve"
- "Niet-ondersteunde actie"
- "Die actie wordt momenteel niet ondersteund."
+ "Reserve"
+ "Niet-ondersteunde actie"
+ "Die actie wordt momenteel niet ondersteund."
diff --git a/apps/Fallback/res/values-pl/strings.xml b/apps/Fallback/res/values-pl/strings.xml
index 73a176ae2..574049805 100644
--- a/apps/Fallback/res/values-pl/strings.xml
+++ b/apps/Fallback/res/values-pl/strings.xml
@@ -15,7 +15,7 @@
-->
- "Wycofanie"
- "Nieobsługiwana czynność"
- "Ta czynność nie jest aktualnie obsługiwana."
+ "Wycofanie"
+ "Nieobsługiwana czynność"
+ "Ta czynność nie jest aktualnie obsługiwana."
diff --git a/apps/Fallback/res/values-pt-rPT/strings.xml b/apps/Fallback/res/values-pt-rPT/strings.xml
index 3c7ec9dcf..b226ea52f 100644
--- a/apps/Fallback/res/values-pt-rPT/strings.xml
+++ b/apps/Fallback/res/values-pt-rPT/strings.xml
@@ -15,7 +15,7 @@
-->
- "Fallback"
- "Acção não suportada"
- "Esta·acção·ainda·não·é·suportada."
+ "Fallback"
+ "Acção não suportada"
+ "Esta acção ainda não é suportada."
diff --git a/apps/Fallback/res/values-pt/strings.xml b/apps/Fallback/res/values-pt/strings.xml
index 08a3faaaf..395004cb6 100644
--- a/apps/Fallback/res/values-pt/strings.xml
+++ b/apps/Fallback/res/values-pt/strings.xml
@@ -15,7 +15,7 @@
-->
- "Fallback"
- "Ação não suportada"
- "Essa ação não é suportada no momento."
+ "Fallback"
+ "Ação não suportada"
+ "Essa ação não é suportada no momento."
diff --git a/apps/Fallback/res/values-ru/strings.xml b/apps/Fallback/res/values-ru/strings.xml
index 24c3480a2..084c3f3f9 100644
--- a/apps/Fallback/res/values-ru/strings.xml
+++ b/apps/Fallback/res/values-ru/strings.xml
@@ -15,7 +15,7 @@
-->
- "Переход в обходной режим"
- "Неподдерживаемое действие"
- "В настоящее время это действие не поддерживается."
+ "Переход в обходной режим"
+ "Неподдерживаемое действие"
+ "В настоящее время это действие не поддерживается."
diff --git a/apps/Fallback/res/values-sv/strings.xml b/apps/Fallback/res/values-sv/strings.xml
index 9dae10ddf..224d946ae 100644
--- a/apps/Fallback/res/values-sv/strings.xml
+++ b/apps/Fallback/res/values-sv/strings.xml
@@ -15,7 +15,7 @@
-->
- "Reserv"
- "Åtgärden stöds inte"
- "Den här åtgärden stöds inte för närvarande."
+ "Reserv"
+ "Åtgärden stöds inte"
+ "Den här åtgärden stöds inte för närvarande."
diff --git a/apps/Fallback/res/values-tr/strings.xml b/apps/Fallback/res/values-tr/strings.xml
index 27b860a5e..9c7ed152e 100644
--- a/apps/Fallback/res/values-tr/strings.xml
+++ b/apps/Fallback/res/values-tr/strings.xml
@@ -15,7 +15,7 @@
-->
- "Fallback"
- "Desteklenmeyen işlem"
- "Bu işlem şu an desteklenmiyor."
+ "Fallback"
+ "Desteklenmeyen işlem"
+ "Bu işlem şu an desteklenmiyor."
diff --git a/apps/Fallback/res/values-zh-rCN/strings.xml b/apps/Fallback/res/values-zh-rCN/strings.xml
index e6cfde138..5b1fbf8b4 100644
--- a/apps/Fallback/res/values-zh-rCN/strings.xml
+++ b/apps/Fallback/res/values-zh-rCN/strings.xml
@@ -15,7 +15,7 @@
-->
- "后备"
- "不支持此操作"
- "目前不支持该操作。"
+ "后备"
+ "不支持此操作"
+ "目前不支持该操作。"
diff --git a/apps/Fallback/res/values-zh-rTW/strings.xml b/apps/Fallback/res/values-zh-rTW/strings.xml
index 52afdbeb6..04d7f4f28 100644
--- a/apps/Fallback/res/values-zh-rTW/strings.xml
+++ b/apps/Fallback/res/values-zh-rTW/strings.xml
@@ -15,7 +15,7 @@
-->
- "備用"
- "不支援的操作"
- "目前不支援此操作。"
+ "備用"
+ "不支援的操作"
+ "目前不支援此操作。"
diff --git a/build/sdk.atree b/build/sdk.atree
index 4b7b4a90f..16d65de16 100644
--- a/build/sdk.atree
+++ b/build/sdk.atree
@@ -31,6 +31,7 @@ bin/sqlite3 tools/sqlite3
bin/dmtracedump tools/dmtracedump
bin/hprof-conv tools/hprof-conv
bin/mksdcard tools/mksdcard
+bin/zipalign tools/zipalign
# the uper-jar file that apps link against
out/target/common/obj/PACKAGING/android_jar_intermediates/android.jar platforms/${PLATFORM_NAME}/android.jar
@@ -39,7 +40,7 @@ out/target/common/obj/PACKAGING/android_jar_intermediates/android.jar platforms/
framework/org.eclipse.core.commands_3.4.0.I20080509-2000.jar tools/lib/org.eclipse.core.commands_3.4.0.I20080509-2000.jar
framework/org.eclipse.equinox.common_3.4.0.v20080421-2006.jar tools/lib/org.eclipse.equinox.common_3.4.0.v20080421-2006.jar
framework/org.eclipse.jface_3.4.2.M20090107-0800.jar tools/lib/org.eclipse.jface_3.4.2.M20090107-0800.jar
-
+framework/osgi.jar tools/lib/osgi.jar
sdk/sdk-build.prop platforms/${PLATFORM_NAME}/build.prop
development/tools/scripts/plugin.prop tools/lib/plugin.prop
@@ -49,7 +50,6 @@ obj/framework.aidl platforms/${PLATFORM_NAME}/framework.aidl
# sdk scripts
development/tools/scripts/AndroidManifest.template platforms/${PLATFORM_NAME}/templates/AndroidManifest.template
-development/tools/scripts/AndroidManifest.alias.template platforms/${PLATFORM_NAME}/templates/AndroidManifest.alias.template
development/tools/scripts/AndroidManifest.tests.template platforms/${PLATFORM_NAME}/templates/AndroidManifest.tests.template
development/tools/scripts/iml.template platforms/${PLATFORM_NAME}/templates/iml.template
development/tools/scripts/ipr.template platforms/${PLATFORM_NAME}/templates/ipr.template
@@ -58,11 +58,8 @@ development/tools/scripts/java_file.template platforms/${PLATFORM_NAME}/template
development/tools/scripts/java_tests_file.template platforms/${PLATFORM_NAME}/templates/java_tests_file.template
development/tools/scripts/layout.template platforms/${PLATFORM_NAME}/templates/layout.template
development/tools/scripts/strings.template platforms/${PLATFORM_NAME}/templates/strings.template
-development/tools/scripts/alias.template platforms/${PLATFORM_NAME}/templates/alias.template
development/tools/scripts/android_rules.xml platforms/${PLATFORM_NAME}/templates/android_rules.xml
-development/tools/scripts/alias_rules.xml platforms/${PLATFORM_NAME}/templates/alias_rules.xml
development/tools/scripts/build.template tools/lib/build.template
-development/tools/scripts/build.alias.template tools/lib/build.alias.template
# emacs support
development/tools/scripts/android.el tools/lib/android.el
@@ -78,6 +75,7 @@ development/samples/SkeletonApp platforms/${PLATFORM_NAME}/samples/SkeletonApp
development/samples/Snake platforms/${PLATFORM_NAME}/samples/Snake
development/samples/SoftKeyboard platforms/${PLATFORM_NAME}/samples/SoftKeyboard
development/samples/JetBoy platforms/${PLATFORM_NAME}/samples/JetBoy
+development/samples/SearchableDictionary platforms/${PLATFORM_NAME}/samples/SearchableDictionary
# dx
bin/dx platforms/${PLATFORM_NAME}/tools/dx
@@ -146,9 +144,10 @@ prebuilt/android-arm/kernel/kernel-qemu platforms/${PLATFORM_NAME}/images/kernel
external/qemu/android/avd/hardware-properties.ini tools/lib/hardware-properties.ini
# emulator skins
-development/emulator/skins/HVGA platforms/${PLATFORM_NAME}/skins/HVGA
-development/emulator/skins/QVGA platforms/${PLATFORM_NAME}/skins/QVGA
-development/emulator/skins/WVGA platforms/${PLATFORM_NAME}/skins/WVGA
+development/emulator/skins/HVGA platforms/${PLATFORM_NAME}/skins/HVGA
+development/emulator/skins/QVGA platforms/${PLATFORM_NAME}/skins/QVGA
+development/emulator/skins/WVGA800 platforms/${PLATFORM_NAME}/skins/WVGA800
+development/emulator/skins/WVGA854 platforms/${PLATFORM_NAME}/skins/WVGA854
# NOTICE files are copied by build/core/Makefile
development/tools/scripts/sdk_files_NOTICE.txt platforms/${PLATFORM_NAME}/templates/NOTICE.txt
diff --git a/build/tools/make_windows_sdk.sh b/build/tools/make_windows_sdk.sh
index 52c2f6cfd..d694ea46b 100755
--- a/build/tools/make_windows_sdk.sh
+++ b/build/tools/make_windows_sdk.sh
@@ -25,25 +25,26 @@ DIST_DIR="$2"
TEMP_DIR="$3"
[ -z "$TEMP_DIR" ] && TEMP_DIR=${TMP:-/tmp}
-
function die() {
- echo "Error:" $*
- echo "Aborting"
- exit 1
+ echo "Error:" $*
+ echo "Aborting"
+ exit 1
}
function usage() {
- echo "Usage: ${PROG_NAME} linux_or_mac_sdk.zip output_dir [temp_dir]"
- echo "If temp_dir is not given, \$TMP is used. If that's missing, /tmp is used."
- status
- exit 2
+ local NAME
+ NAME=`basename ${PROG_NAME}`
+ echo "Usage: ${NAME} linux_or_mac_sdk.zip output_dir [temp_dir]"
+ echo "If temp_dir is not given, \$TMP is used. If that's missing, /tmp is used."
+ status
+ exit 2
}
function status() {
- echo "Current values:"
- echo "- Input SDK: ${SDK_ZIP:-missing}"
- echo "- Output dir: ${DIST_DIR:-missing}"
- echo "- Temp dir: ${TEMP_DIR:-missing}"
+ echo "Current values:"
+ echo "- Input SDK: ${SDK_ZIP:-missing}"
+ echo "- Output dir: ${DIST_DIR:-missing}"
+ echo "- Temp dir: ${TEMP_DIR:-missing}"
}
function check() {
@@ -92,7 +93,14 @@ function build() {
make -j 4 emulator || die "Build failed"
# Disable parallel build: it generates "permission denied" issues when
# multiple "ar.exe" are running in parallel.
- make prebuilt adb fastboot aidl aapt dexdump dmtracedump hprof-conv mksdcard sqlite3 \
+ make aapt adb aidl \
+ prebuilt \
+ dexdump dmtracedump \
+ fastboot \
+ hprof-conv \
+ mksdcard \
+ sqlite3 \
+ zipalign \
|| die "Build failed"
}
@@ -124,12 +132,16 @@ function package() {
"Instead found " $THE_PLATFORM
[[ -d "$PLATFORM_TOOLS" ]] || die "Missing folder $PLATFORM_TOOLS."
+ # Package USB Driver
+ if type package_usb_driver 2>&1 | grep -q function ; then
+ package_usb_driver $TEMP_SDK_DIR
+ fi
# Remove obsolete stuff from tools & platform
TOOLS="$TEMP_SDK_DIR/tools"
LIB="$TEMP_SDK_DIR/tools/lib"
rm -v "$TOOLS"/{adb,android,apkbuilder,ddms,dmtracedump,draw9patch,emulator}
- rm -v "$TOOLS"/{hierarchyviewer,hprof-conv,mksdcard,sqlite3,traceview}
+ rm -v "$TOOLS"/{hierarchyviewer,hprof-conv,mksdcard,sqlite3,traceview,zipalign}
rm -v "$LIB"/*/swt.jar
rm -v "$PLATFORM_TOOLS"/{aapt,aidl,dx,dexdump}
@@ -183,8 +195,9 @@ function package() {
# Copy or move platform specific tools to the default platform.
cp -v dalvik/dx/etc/dx.bat "$PLATFORM_TOOLS"/
- # Note: mgwz.dll must be in same folder than aapt.exe
- mv -v "$TOOLS"/{aapt.exe,aidl.exe,dexdump.exe,mgwz.dll} "$PLATFORM_TOOLS"/
+ mv -v "$TOOLS"/{aapt.exe,aidl.exe,dexdump.exe} "$PLATFORM_TOOLS"/
+ # Note: mgwz.dll must be both in SDK/tools for zipalign and in SDK/platform/XYZ/tools/ for aapt
+ cp -v "$TOOLS"/mgwz.dll "$PLATFORM_TOOLS"/
# Fix EOL chars to make window users happy - fix all files at the top level only
# as well as all batch files including those in platforms//tools/
@@ -200,14 +213,14 @@ function package() {
# Now move the final zip from the temp dest to the final dist dir
mv -v "$TEMP_DIR/$DEST_NAME_ZIP" "$DIST_DIR/$DEST_NAME_ZIP"
+ # We want fastboot and adb (and its DLLs) next to the new SDK
+ for i in fastboot.exe adb.exe AdbWinApi.dll AdbWinUsbApi.dll; do
+ cp -vf out/host/windows-x86/bin/$i "$DIST_DIR"/$i
+ done
+
echo "Done"
echo
echo "Resulting SDK is in $DIST_DIR/$DEST_NAME_ZIP"
-
- # We want fastboot and adb next to the new SDK
- for i in fastboot.exe adb.exe AdbWinApi.dll; do
- mv -vf out/host/windows-x86/bin/$i "$DIST_DIR"/$i
- done
}
check
diff --git a/cmds/monkey/Android.mk b/cmds/monkey/Android.mk
index 6bedc43e8..ba9cf0410 100644
--- a/cmds/monkey/Android.mk
+++ b/cmds/monkey/Android.mk
@@ -7,6 +7,7 @@ LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_MODULE := monkey
include $(BUILD_JAVA_LIBRARY)
+################################################################
include $(CLEAR_VARS)
ALL_PREBUILT += $(TARGET_OUT)/bin/monkey
$(TARGET_OUT)/bin/monkey : $(LOCAL_PATH)/monkey | $(ACP)
diff --git a/cmds/monkey/README.NETWORK.txt b/cmds/monkey/README.NETWORK.txt
new file mode 100644
index 000000000..4e78b6c8b
--- /dev/null
+++ b/cmds/monkey/README.NETWORK.txt
@@ -0,0 +1,129 @@
+SIMPLE PROTOCOL FOR AUTOMATED NETWORK CONTROL
+
+The Simple Protocol for Automated Network Control was designed to be a
+low-level way to programmability inject KeyEvents and MotionEvents
+into the input system. The idea is that a process will run on a host
+computer that will support higher-level operations (like conditionals,
+etc.) and will talk (via TCP over ADB) to the device in Simple
+Protocol for Automated Network Control. For security reasons, the
+Monkey only binds to localhost, so you will need to use adb to setup
+port forwarding to actually talk to the device.
+
+INITIAL SETUP
+
+Setup port forwarding from a local port on your machine to a port on
+the device:
+
+$ adb forward tcp:1080 tcp:1080
+
+Start the monkey server
+
+$ adb shell monkey --port 1080
+
+Now you're ready to run commands
+
+COMMAND LIST
+
+Individual commands are separated by newlines. The Monkey will
+respond to every command with a line starting with OK for commands
+that executed without a problem, or a line starting with ERROR for
+commands that had problems being run. For commands that return a
+value, that value is returned on the same line as the OK or ERROR
+response. The value is everything after (but not include) the colon
+on that line. For ERROR values, this could be a message indicating
+what happened. A possible example:
+
+key down menu
+OK
+touch monkey
+ERROR: monkey not a number
+getvar sdk
+OK: donut
+getvar foo
+ERROR: no such var
+
+The complete list of commands follows:
+
+key [down|up] keycode
+
+This command injects KeyEvent's into the input system. The keycode
+parameter refers to the KEYCODE list in the KeyEvent class
+(http://developer.android.com/reference/android/view/KeyEvent.html).
+The format of that parameter is quite flexible. Using the menu key as
+an example, it can be 82 (the integer value of the keycode),
+KEYCODE_MENU (the name of the keycode), or just menu (and the Monkey
+will add the KEYCODE part). Do note that this last part doesn't work
+for things like KEYCODE_1 for obvious reasons.
+
+Note that sending a full button press requires sending both the down
+and the up event for that key
+
+touch [down|up|move] x y
+
+This command injects a MotionEvent into the input system that
+simulates a user touching the touchscreen (or a pointer event). x and
+y specify coordinates on the display (0 0 being the upper left) for
+the touch event to happen. Just like key events, touch events at a
+single location require both a down and an up. To simulate dragging,
+send a "touch down", then a series of "touch move" events (to simulate
+the drag), followed by a "touch up" at the final location.
+
+trackball dx dy
+
+This command injects a MotionEvent into the input system that
+simulates a user using the trackball. dx and dy indicates the amount
+of change in the trackball location (as opposed to exact coordinates
+that the touch events use)
+
+flip [open|close]
+
+This simulates the opening or closing the keyboard (like on dream).
+
+wake
+
+This command will wake the device up from sleep and allow user input.
+
+tap x y
+The tap command is a shortcut for the touch command. It will
+automatically send both the up and the down event.
+
+press keycode
+
+The press command is a shortcut for the key command. The keycode
+paramter works just like the key command and will automatically send
+both the up and the down event.
+
+type string
+
+This command will simulate a user typing the given string on the
+keyboard by generating the proper KeyEvents.
+
+listvar
+
+This command lists all the vars that the monkey knows about. They are
+returned as a whitespace separated list.
+
+getvar varname
+
+This command returns the value of the given var. listvar can be used
+to find out what vars are supported.
+
+quit
+
+Fully quit the monkey and accept no new sessions.
+
+done
+
+Close the current session and allow a new session to connect
+
+OTHER NOTES
+
+There are some convenience features added to allow running without
+needing a host process.
+
+Lines starting with a # character are considered comments. The Monkey
+eats them and returns no indication that it did anything (no ERROR and
+no OK).
+
+You can put the Monkey to sleep by using the "sleep" command with a
+single argument, how many ms to sleep.
diff --git a/cmds/monkey/example_script.txt b/cmds/monkey/example_script.txt
new file mode 100644
index 000000000..5c1c61de2
--- /dev/null
+++ b/cmds/monkey/example_script.txt
@@ -0,0 +1,57 @@
+# Touch the android
+touch down 160 200
+touch up 160 200
+sleep 1000
+
+# Hit Next
+touch down 300 450
+touch up 300 450
+sleep 1000
+
+# Hit Next
+touch down 300 450
+touch up 300 450
+sleep 1000
+
+# Hit Next
+touch down 300 450
+touch up 300 450
+sleep 1000
+
+# Go down and select the account username
+key down dpad_down
+key up dpad_down
+key down dpad_down
+key up dpad_down
+key down dpad_center
+key up dpad_center
+# account name: bill
+key down b
+key up b
+key down i
+key up i
+key down l
+key up l
+key down l
+key up l
+
+# Go down to the password field
+key down dpad_down
+key up dpad_down
+
+# password: bill
+key down b
+key up b
+key down i
+key up i
+key down l
+key up l
+key down l
+key up l
+
+# Select next
+touch down 300 450
+touch up 300 450
+
+# quit
+quit
diff --git a/cmds/monkey/src/com/android/commands/monkey/Monkey.java b/cmds/monkey/src/com/android/commands/monkey/Monkey.java
index 7ebd7274f..521de16d6 100644
--- a/cmds/monkey/src/com/android/commands/monkey/Monkey.java
+++ b/cmds/monkey/src/com/android/commands/monkey/Monkey.java
@@ -47,10 +47,10 @@ import java.util.List;
* Application that injects random key events and other actions into the system.
*/
public class Monkey {
-
+
/**
* Monkey Debugging/Dev Support
- *
+ *
* All values should be zero when checking in.
*/
private final static int DEBUG_ALLOW_ANY_STARTS = 0;
@@ -74,20 +74,20 @@ public class Monkey {
/** Ignore any not responding timeouts while running? */
private boolean mIgnoreTimeouts;
-
+
/** Ignore security exceptions when launching activities */
/** (The activity launch still fails, but we keep pluggin' away) */
private boolean mIgnoreSecurityExceptions;
-
+
/** Monitor /data/tombstones and stop the monkey if new files appear. */
private boolean mMonitorNativeCrashes;
-
+
/** Send no events. Use with long throttle-time to watch user operations */
private boolean mSendNoEvents;
/** This is set when we would like to abort the running of the monkey. */
private boolean mAbort;
-
+
/** This is set by the ActivityController thread to request collection of ANR trace files */
private boolean mRequestAnrTraces = false;
@@ -96,7 +96,7 @@ public class Monkey {
/** Kill the process after a timeout or crash. */
private boolean mKillProcessAfterError;
-
+
/** Generate hprof reports before/after monkey runs */
private boolean mGenerateHprof;
@@ -106,16 +106,16 @@ public class Monkey {
ArrayList mMainCategories = new ArrayList();
/** Applications we can switch to. */
private ArrayList mMainApps = new ArrayList();
-
+
/** The delay between event inputs **/
long mThrottle = 0;
-
+
/** The number of iterations **/
int mCount = 1000;
-
+
/** The random number seed **/
long mSeed = 0;
-
+
/** Dropped-event statistics **/
long mDroppedKeyEvents = 0;
long mDroppedPointerEvents = 0;
@@ -124,14 +124,21 @@ public class Monkey {
/** a filename to the script (if any) **/
private String mScriptFileName = null;
-
+
+ /** a TCP port to listen on for remote commands. */
+ private int mServerPort = -1;
+
private static final File TOMBSTONES_PATH = new File("/data/tombstones");
private HashSet mTombstones = null;
-
- float[] mFactors = new float[MonkeySourceRandom.FACTORZ_COUNT];
+
+ float[] mFactors = new float[MonkeySourceRandom.FACTORZ_COUNT];
MonkeyEventSource mEventSource;
private MonkeyNetworkMonitor mNetworkMonitor = new MonkeyNetworkMonitor();
-
+
+ // information on the current activity.
+ public static Intent currentIntent;
+ public static String currentPackage;
+
/**
* Monitor operations happening in the system.
*/
@@ -142,21 +149,24 @@ public class Monkey {
System.out.println(" // " + (allow ? "Allowing" : "Rejecting")
+ " start of " + intent + " in package " + pkg);
}
+ currentPackage = pkg;
+ currentIntent = intent;
return allow;
}
-
+
public boolean activityResuming(String pkg) {
System.out.println(" // activityResuming(" + pkg + ")");
boolean allow = checkEnteringPackage(pkg) || (DEBUG_ALLOW_ANY_RESTARTS != 0);
if (!allow) {
if (mVerbose > 0) {
System.out.println(" // " + (allow ? "Allowing" : "Rejecting")
- + " resume of package " + pkg);
+ + " resume of package " + pkg);
}
}
+ currentPackage = pkg;
return allow;
}
-
+
private boolean checkEnteringPackage(String pkg) {
if (pkg == null) {
return true;
@@ -168,7 +178,7 @@ public class Monkey {
return mValidPackages.contains(pkg);
}
}
-
+
public boolean appCrashed(String processName, int pid, String shortMsg,
String longMsg, byte[] crashData) {
System.err.println("// CRASH: " + processName + " (pid " + pid
@@ -223,14 +233,14 @@ public class Monkey {
return 1;
}
}
-
+
/**
* Run the procrank tool to insert system status information into the debug report.
*/
private void reportProcRank() {
commandLineReport("procrank", "procrank");
}
-
+
/**
* Run "cat /data/anr/traces.txt". Wait about 5 seconds first, to let the asynchronous
* report writing complete.
@@ -238,21 +248,21 @@ public class Monkey {
private void reportAnrTraces() {
try {
Thread.sleep(5 * 1000);
- } catch (InterruptedException e) {
+ } catch (InterruptedException e) {
}
commandLineReport("anr traces", "cat /data/anr/traces.txt");
}
-
+
/**
* Run "dumpsys meminfo"
- *
+ *
* NOTE: You cannot perform a dumpsys call from the ActivityController callback, as it will
* deadlock. This should only be called from the main loop of the monkey.
*/
private void reportDumpsysMemInfo() {
commandLineReport("meminfo", "dumpsys meminfo");
}
-
+
/**
* Print report from a single command line.
* @param reportName Simple tag that will print before the report and in various annotations.
@@ -266,7 +276,7 @@ public class Monkey {
try {
// Process must be fully qualified here because android.os.Process is used elsewhere
java.lang.Process p = Runtime.getRuntime().exec(command);
-
+
// pipe everything from process stdout -> System.err
InputStream inStream = p.getInputStream();
InputStreamReader inReader = new InputStreamReader(inStream);
@@ -275,7 +285,7 @@ public class Monkey {
while ((s = inBuffer.readLine()) != null) {
System.err.println(s);
}
-
+
int status = p.waitFor();
System.err.println("// " + reportName + " status was " + status);
} catch (Exception e) {
@@ -307,26 +317,26 @@ public class Monkey {
Debug.waitForDebugger();
}
}
-
+
// Default values for some command-line options
mVerbose = 0;
mCount = 1000;
mSeed = 0;
mThrottle = 0;
-
+
// prepare for command-line processing
mArgs = args;
mNextArg = 0;
-
+
//set a positive value, indicating none of the factors is provided yet
for (int i = 0; i < MonkeySourceRandom.FACTORZ_COUNT; i++) {
mFactors[i] = 1.0f;
}
-
+
if (!processOptions()) {
return -1;
}
-
+
// now set up additional data in preparation for launch
if (mMainCategories.size() == 0) {
mMainCategories.add(Intent.CATEGORY_LAUNCHER);
@@ -348,11 +358,11 @@ public class Monkey {
}
}
}
-
+
if (!checkInternalConfiguration()) {
return -2;
}
-
+
if (!getSystemInterfaces()) {
return -3;
}
@@ -360,11 +370,19 @@ public class Monkey {
if (!getMainApps()) {
return -4;
}
-
+
if (mScriptFileName != null) {
// script mode, ignore other options
mEventSource = new MonkeySourceScript(mScriptFileName, mThrottle);
mEventSource.setVerbose(mVerbose);
+ } else if (mServerPort != -1) {
+ try {
+ mEventSource = new MonkeySourceNetwork(mServerPort);
+ } catch (IOException e) {
+ System.out.println("Error binding to network socket.");
+ return -5;
+ }
+ mCount = Integer.MAX_VALUE;
} else {
// random source by default
if (mVerbose >= 2) { // check seeding performance
@@ -378,7 +396,7 @@ public class Monkey {
((MonkeySourceRandom) mEventSource).setFactors(i, mFactors[i]);
}
}
-
+
//in random mode, we start with a random activity
((MonkeySourceRandom) mEventSource).generateActivity();
}
@@ -387,7 +405,7 @@ public class Monkey {
if (!mEventSource.validate()) {
return -5;
}
-
+
if (mScriptFileName != null) {
// in random mode, count is the number of single events
// while in script mode, count is the number of repetition
@@ -396,12 +414,12 @@ public class Monkey {
mCount = mCount * ((MonkeySourceScript) mEventSource)
.getOneRoundEventCount();
}
-
+
// If we're profiling, do it immediately before/after the main monkey loop
if (mGenerateHprof) {
signalPersistentProcesses();
}
-
+
mNetworkMonitor.start();
int crashedAtCycle = runMonkeyCycles();
mNetworkMonitor.stop();
@@ -423,7 +441,7 @@ public class Monkey {
System.out.println("// Generated profiling reports in /data/misc");
}
}
-
+
try {
mAm.setActivityController(null);
mNetworkMonitor.unregister(mAm);
@@ -434,7 +452,7 @@ public class Monkey {
crashedAtCycle = mCount - 1;
}
}
-
+
// report dropped event stats
if (mVerbose > 0) {
System.out.print(":Dropped: keys=");
@@ -446,7 +464,7 @@ public class Monkey {
System.out.print(" flips=");
System.out.println(mDroppedFlipEvents);
}
-
+
// report network stats
mNetworkMonitor.dump();
@@ -461,10 +479,10 @@ public class Monkey {
return 0;
}
}
-
+
/**
* Process the command-line options
- *
+ *
* @return Returns true if options were parsed with no apparent errors.
*/
private boolean processOptions() {
@@ -498,28 +516,28 @@ public class Monkey {
} else if (opt.equals("--hprof")) {
mGenerateHprof = true;
} else if (opt.equals("--pct-touch")) {
- mFactors[MonkeySourceRandom.FACTOR_TOUCH] =
+ mFactors[MonkeySourceRandom.FACTOR_TOUCH] =
-nextOptionLong("touch events percentage");
} else if (opt.equals("--pct-motion")) {
- mFactors[MonkeySourceRandom.FACTOR_MOTION] =
+ mFactors[MonkeySourceRandom.FACTOR_MOTION] =
-nextOptionLong("motion events percentage");
} else if (opt.equals("--pct-trackball")) {
- mFactors[MonkeySourceRandom.FACTOR_TRACKBALL] =
+ mFactors[MonkeySourceRandom.FACTOR_TRACKBALL] =
-nextOptionLong("trackball events percentage");
} else if (opt.equals("--pct-nav")) {
- mFactors[MonkeySourceRandom.FACTOR_NAV] =
+ mFactors[MonkeySourceRandom.FACTOR_NAV] =
-nextOptionLong("nav events percentage");
} else if (opt.equals("--pct-majornav")) {
- mFactors[MonkeySourceRandom.FACTOR_MAJORNAV] =
+ mFactors[MonkeySourceRandom.FACTOR_MAJORNAV] =
-nextOptionLong("major nav events percentage");
} else if (opt.equals("--pct-appswitch")) {
- mFactors[MonkeySourceRandom.FACTOR_APPSWITCH] =
+ mFactors[MonkeySourceRandom.FACTOR_APPSWITCH] =
-nextOptionLong("app switch events percentage");
} else if (opt.equals("--pct-flip")) {
mFactors[MonkeySourceRandom.FACTOR_FLIP] =
-nextOptionLong("keyboard flip percentage");
} else if (opt.equals("--pct-anyevent")) {
- mFactors[MonkeySourceRandom.FACTOR_ANYTHING] =
+ mFactors[MonkeySourceRandom.FACTOR_ANYTHING] =
-nextOptionLong("any events percentage");
} else if (opt.equals("--throttle")) {
mThrottle = nextOptionLong("delay (in milliseconds) to wait between events");
@@ -527,7 +545,9 @@ public class Monkey {
// do nothing - it's caught at the very start of run()
} else if (opt.equals("--dbg-no-events")) {
mSendNoEvents = true;
- } else if (opt.equals("-f")) {
+ } else if (opt.equals("--port")) {
+ mServerPort = (int) nextOptionLong("Server port to listen on for commands");
+ } else if (opt.equals("-f")) {
mScriptFileName = nextOptionData();
} else if (opt.equals("-h")) {
showUsage();
@@ -544,19 +564,23 @@ public class Monkey {
return false;
}
- String countStr = nextArg();
- if (countStr == null) {
- System.err.println("** Error: Count not specified");
- showUsage();
- return false;
- }
+ // If a server port hasn't been specified, we need to specify
+ // a count
+ if (mServerPort == -1) {
+ String countStr = nextArg();
+ if (countStr == null) {
+ System.err.println("** Error: Count not specified");
+ showUsage();
+ return false;
+ }
- try {
- mCount = Integer.parseInt(countStr);
- } catch (NumberFormatException e) {
- System.err.println("** Error: Count is not a number");
- showUsage();
- return false;
+ try {
+ mCount = Integer.parseInt(countStr);
+ } catch (NumberFormatException e) {
+ System.err.println("** Error: Count is not a number");
+ showUsage();
+ return false;
+ }
}
return true;
@@ -564,7 +588,7 @@ public class Monkey {
/**
* Check for any internal configuration (primarily build-time) errors.
- *
+ *
* @return Returns true if ready to rock.
*/
private boolean checkInternalConfiguration() {
@@ -585,7 +609,7 @@ public class Monkey {
/**
* Attach to the required system interfaces.
- *
+ *
* @return Returns true if all system interfaces were available.
*/
private boolean getSystemInterfaces() {
@@ -621,7 +645,7 @@ public class Monkey {
/**
* Using the restrictions provided (categories & packages), generate a list of activities
* that we can actually switch to.
- *
+ *
* @return Returns true if it could successfully build a list of target activities
*/
private boolean getMainApps() {
@@ -644,7 +668,7 @@ public class Monkey {
final int NA = mainApps.size();
for (int a = 0; a < NA; a++) {
ResolveInfo r = mainApps.get(a);
- if (mValidPackages.size() == 0 ||
+ if (mValidPackages.size() == 0 ||
mValidPackages.contains(r.activityInfo.applicationInfo.packageName)) {
if (mVerbose >= 2) { // very verbose
System.out.println("// + Using main activity "
@@ -676,15 +700,15 @@ public class Monkey {
System.out.println("** No activities found to run, monkey aborted.");
return false;
}
-
+
return true;
}
/**
* Run mCount cycles and see if we hit any crashers.
- *
+ *
* TODO: Meta state on keys
- *
+ *
* @return Returns the last cycle which executed. If the value == mCount, no errors detected.
*/
private int runMonkeyCycles() {
@@ -749,9 +773,11 @@ public class Monkey {
} else if (injectCode == MonkeyEvent.INJECT_ERROR_SECURITY_EXCEPTION) {
systemCrashed = !mIgnoreSecurityExceptions;
}
+ } else {
+ // Event Source has signaled that we have no more events to process
+ break;
}
}
-
// If we got this far, we succeeded!
return mCount;
}
@@ -775,18 +801,18 @@ public class Monkey {
/**
* Watch for appearance of new tombstone files, which indicate native crashes.
- *
+ *
* @return Returns true if new files have appeared in the list
*/
private boolean checkNativeCrashes() {
String[] tombstones = TOMBSTONES_PATH.list();
-
+
// shortcut path for usually empty directory, so we don't waste even more objects
if ((tombstones == null) || (tombstones.length == 0)) {
mTombstones = null;
return false;
}
-
+
// use set logic to look for new files
HashSet newStones = new HashSet();
for (String x : tombstones) {
@@ -804,14 +830,14 @@ public class Monkey {
/**
* Return the next command line option. This has a number of special cases which
* closely, but not exactly, follow the POSIX command line options patterns:
- *
+ *
* -- means to stop processing additional options
* -z means option z
* -z ARGS means option z with (non-optional) arguments ARGS
* -zARGS means option z with (optional) arguments ARGS
* --zz means option zz
* --zz ARGS means option zz with (non-optional) arguments ARGS
- *
+ *
* Note that you cannot combine single letter options; -abc != -a -b -c
*
* @return Returns the option string, or null if there are no more options.
@@ -857,10 +883,10 @@ public class Monkey {
mNextArg++;
return data;
}
-
+
/**
* Returns a long converted from the next data argument, with error handling if not available.
- *
+ *
* @param opt The name of the option.
* @return Returns a long converted from the argument.
*/
@@ -904,6 +930,7 @@ public class Monkey {
System.err.println(" [--pct-appswitch PERCENT] [--pct-flip PERCENT]");
System.err.println(" [--pct-anyevent PERCENT]");
System.err.println(" [--wait-dbg] [--dbg-no-events] [-f scriptfile]");
+ System.err.println(" [--port port]");
System.err.println(" [-s SEED] [-v [-v] ...] [--throttle MILLISEC]");
System.err.println(" COUNT");
}
diff --git a/cmds/monkey/src/com/android/commands/monkey/MonkeyEvent.java b/cmds/monkey/src/com/android/commands/monkey/MonkeyEvent.java
index d926be8e4..2783dde21 100644
--- a/cmds/monkey/src/com/android/commands/monkey/MonkeyEvent.java
+++ b/cmds/monkey/src/com/android/commands/monkey/MonkeyEvent.java
@@ -22,7 +22,7 @@ import android.view.IWindowManager;
/**
* abstract class for monkey event
*/
-public abstract class MonkeyEvent {
+public abstract class MonkeyEvent {
protected int eventType;
public static final int EVENT_TYPE_KEY = 0;
public static final int EVENT_TYPE_POINTER = 1;
@@ -30,41 +30,42 @@ public abstract class MonkeyEvent {
public static final int EVENT_TYPE_ACTIVITY = 3;
public static final int EVENT_TYPE_FLIP = 4; // Keyboard flip
public static final int EVENT_TYPE_THROTTLE = 5;
-
+ public static final int EVENT_TYPE_NOOP = 6;
+
public static final int INJECT_SUCCESS = 1;
public static final int INJECT_FAIL = 0;
// error code for remote exception during injection
- public static final int INJECT_ERROR_REMOTE_EXCEPTION = -1;
+ public static final int INJECT_ERROR_REMOTE_EXCEPTION = -1;
// error code for security exception during injection
public static final int INJECT_ERROR_SECURITY_EXCEPTION = -2;
-
+
public MonkeyEvent(int type) {
eventType = type;
}
-
- /**
+
+ /**
* @return event type
- */
+ */
public int getEventType() {
return eventType;
}
-
+
/**
* @return true if it is safe to throttle after this event, and false otherwise.
*/
public boolean isThrottlable() {
return true;
}
-
-
+
+
/**
* a method for injecting event
* @param iwm wires to current window manager
* @param iam wires to current activity manager
- * @param verbose a log switch
+ * @param verbose a log switch
* @return INJECT_SUCCESS if it goes through, and INJECT_FAIL if it fails
* in the case of exceptions, return its corresponding error code
*/
- public abstract int injectEvent(IWindowManager iwm, IActivityManager iam, int verbose);
+ public abstract int injectEvent(IWindowManager iwm, IActivityManager iam, int verbose);
}
diff --git a/cmds/monkey/src/com/android/commands/monkey/MonkeyKeyEvent.java b/cmds/monkey/src/com/android/commands/monkey/MonkeyKeyEvent.java
index 877ebb576..d9c68af50 100644
--- a/cmds/monkey/src/com/android/commands/monkey/MonkeyKeyEvent.java
+++ b/cmds/monkey/src/com/android/commands/monkey/MonkeyKeyEvent.java
@@ -23,7 +23,7 @@ import android.view.KeyEvent;
/**
* monkey key event
*/
-public class MonkeyKeyEvent extends MonkeyEvent {
+public class MonkeyKeyEvent extends MonkeyEvent {
private long mDownTime = -1;
private int mMetaState = -1;
private int mAction = -1;
@@ -32,18 +32,25 @@ public class MonkeyKeyEvent extends MonkeyEvent {
private int mRepeatCount = -1;
private int mDeviceId = -1;
private long mEventTime = -1;
-
+
+ private KeyEvent keyEvent = null;
+
public MonkeyKeyEvent(int action, int keycode) {
super(EVENT_TYPE_KEY);
mAction = action;
mKeyCode = keycode;
}
-
+
+ public MonkeyKeyEvent(KeyEvent e) {
+ super(EVENT_TYPE_KEY);
+ keyEvent = e;
+ }
+
public MonkeyKeyEvent(long downTime, long eventTime, int action,
int code, int repeat, int metaState,
int device, int scancode) {
super(EVENT_TYPE_KEY);
-
+
mAction = action;
mKeyCode = code;
mMetaState = metaState;
@@ -53,49 +60,52 @@ public class MonkeyKeyEvent extends MonkeyEvent {
mDownTime = downTime;
mEventTime = eventTime;
}
-
+
public int getKeyCode() {
return mKeyCode;
}
-
+
public int getAction() {
return mAction;
}
-
+
public long getDownTime() {
return mDownTime;
}
-
+
public long getEventTime() {
return mEventTime;
}
-
+
public void setDownTime(long downTime) {
mDownTime = downTime;
}
-
+
public void setEventTime(long eventTime) {
mEventTime = eventTime;
}
-
- /**
+
+ /**
* @return the key event
- */
+ */
private KeyEvent getEvent() {
- if (mDeviceId < 0) {
- return new KeyEvent(mAction, mKeyCode);
- }
-
- // for scripts
- return new KeyEvent(mDownTime, mEventTime, mAction,
- mKeyCode, mRepeatCount, mMetaState, mDeviceId, mScancode);
+ if (keyEvent == null) {
+ if (mDeviceId < 0) {
+ keyEvent = new KeyEvent(mAction, mKeyCode);
+ } else {
+ // for scripts
+ keyEvent = new KeyEvent(mDownTime, mEventTime, mAction,
+ mKeyCode, mRepeatCount, mMetaState, mDeviceId, mScancode);
+ }
+ }
+ return keyEvent;
}
@Override
public boolean isThrottlable() {
return (getAction() == KeyEvent.ACTION_UP);
}
-
+
@Override
public int injectEvent(IWindowManager iwm, IActivityManager iam, int verbose) {
if (verbose > 1) {
@@ -124,7 +134,7 @@ public class MonkeyKeyEvent extends MonkeyEvent {
} catch (RemoteException ex) {
return MonkeyEvent.INJECT_ERROR_REMOTE_EXCEPTION;
}
-
+
return MonkeyEvent.INJECT_SUCCESS;
}
}
diff --git a/cmds/monkey/src/com/android/commands/monkey/MonkeyNoopEvent.java b/cmds/monkey/src/com/android/commands/monkey/MonkeyNoopEvent.java
new file mode 100644
index 000000000..ea9273576
--- /dev/null
+++ b/cmds/monkey/src/com/android/commands/monkey/MonkeyNoopEvent.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * 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.
+ */
+
+package com.android.commands.monkey;
+
+import java.util.List;
+
+import android.app.IActivityManager;
+import android.view.IWindowManager;
+
+
+/**
+ * monkey noop event (don't do anything).
+ */
+public class MonkeyNoopEvent extends MonkeyEvent {
+
+ public MonkeyNoopEvent() {
+ super(MonkeyEvent.EVENT_TYPE_NOOP);
+ }
+
+ @Override
+ public int injectEvent(IWindowManager iwm, IActivityManager iam, int verbose) {
+ // No real work to do
+ if (verbose > 1) {
+ System.out.println("NOOP");
+ }
+ return MonkeyEvent.INJECT_SUCCESS;
+ }
+}
diff --git a/cmds/monkey/src/com/android/commands/monkey/MonkeySourceNetwork.java b/cmds/monkey/src/com/android/commands/monkey/MonkeySourceNetwork.java
new file mode 100644
index 000000000..a9a1db416
--- /dev/null
+++ b/cmds/monkey/src/com/android/commands/monkey/MonkeySourceNetwork.java
@@ -0,0 +1,697 @@
+/*
+ * Copyright 2009, The Android Open Source Project
+ *
+ * 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.
+ */
+package com.android.commands.monkey;
+
+import android.content.Context;
+import android.os.IPowerManager;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.SystemClock;
+import android.util.Log;
+import android.view.KeyCharacterMap;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.lang.Integer;
+import java.lang.NumberFormatException;
+import java.net.InetAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Queue;
+import java.util.StringTokenizer;
+
+/**
+ * An Event source for getting Monkey Network Script commands from
+ * over the network.
+ */
+public class MonkeySourceNetwork implements MonkeyEventSource {
+ private static final String TAG = "MonkeyStub";
+
+ /**
+ * ReturnValue from the MonkeyCommand that indicates whether the
+ * command was sucessful or not.
+ */
+ public static class MonkeyCommandReturn {
+ private final boolean success;
+ private final String message;
+
+ public MonkeyCommandReturn(boolean success) {
+ this.success = success;
+ this.message = null;
+ }
+
+ public MonkeyCommandReturn(boolean success,
+ String message) {
+ this.success = success;
+ this.message = message;
+ }
+
+ boolean hasMessage() {
+ return message != null;
+ }
+
+ String getMessage() {
+ return message;
+ }
+
+ boolean wasSuccessful() {
+ return success;
+ }
+ }
+
+ public final static MonkeyCommandReturn OK = new MonkeyCommandReturn(true);
+ public final static MonkeyCommandReturn ERROR = new MonkeyCommandReturn(false);
+ public final static MonkeyCommandReturn EARG = new MonkeyCommandReturn(false,
+ "Invalid Argument");
+
+ /**
+ * Interface that MonkeyCommands must implement.
+ */
+ public interface MonkeyCommand {
+ /**
+ * Translate the command line into a sequence of MonkeyEvents.
+ *
+ * @param command the command line.
+ * @param queue the command queue.
+ * @returs MonkeyCommandReturn indicating what happened.
+ */
+ MonkeyCommandReturn translateCommand(List command, CommandQueue queue);
+ }
+
+ /**
+ * Command to simulate closing and opening the keyboard.
+ */
+ private static class FlipCommand implements MonkeyCommand {
+ // flip open
+ // flip closed
+ public MonkeyCommandReturn translateCommand(List command,
+ CommandQueue queue) {
+ if (command.size() > 1) {
+ String direction = command.get(1);
+ if ("open".equals(direction)) {
+ queue.enqueueEvent(new MonkeyFlipEvent(true));
+ return OK;
+ } else if ("close".equals(direction)) {
+ queue.enqueueEvent(new MonkeyFlipEvent(false));
+ return OK;
+ }
+ }
+ return EARG;
+ }
+ }
+
+ /**
+ * Command to send touch events to the input system.
+ */
+ private static class TouchCommand implements MonkeyCommand {
+ // touch [down|up|move] [x] [y]
+ // touch down 120 120
+ // touch move 140 140
+ // touch up 140 140
+ public MonkeyCommandReturn translateCommand(List command,
+ CommandQueue queue) {
+ if (command.size() == 4) {
+ String actionName = command.get(1);
+ int x = 0;
+ int y = 0;
+ try {
+ x = Integer.parseInt(command.get(2));
+ y = Integer.parseInt(command.get(3));
+ } catch (NumberFormatException e) {
+ // Ok, it wasn't a number
+ Log.e(TAG, "Got something that wasn't a number", e);
+ return EARG;
+ }
+
+ // figure out the action
+ int action = -1;
+ if ("down".equals(actionName)) {
+ action = MotionEvent.ACTION_DOWN;
+ } else if ("up".equals(actionName)) {
+ action = MotionEvent.ACTION_UP;
+ } else if ("move".equals(actionName)) {
+ action = MotionEvent.ACTION_MOVE;
+ }
+ if (action == -1) {
+ Log.e(TAG, "Got a bad action: " + actionName);
+ return EARG;
+ }
+
+ queue.enqueueEvent(new MonkeyMotionEvent(MonkeyEvent.EVENT_TYPE_POINTER,
+ -1, action, x, y, 0));
+ return OK;
+ }
+ return EARG;
+ }
+ }
+
+ /**
+ * Command to send Trackball events to the input system.
+ */
+ private static class TrackballCommand implements MonkeyCommand {
+ // trackball [dx] [dy]
+ // trackball 1 0 -- move right
+ // trackball -1 0 -- move left
+ public MonkeyCommandReturn translateCommand(List command,
+ CommandQueue queue) {
+ if (command.size() == 3) {
+ int dx = 0;
+ int dy = 0;
+ try {
+ dx = Integer.parseInt(command.get(1));
+ dy = Integer.parseInt(command.get(2));
+ } catch (NumberFormatException e) {
+ // Ok, it wasn't a number
+ Log.e(TAG, "Got something that wasn't a number", e);
+ return EARG;
+ }
+ queue.enqueueEvent(new MonkeyMotionEvent(MonkeyEvent.EVENT_TYPE_TRACKBALL, -1,
+ MotionEvent.ACTION_MOVE, dx, dy, 0));
+ return OK;
+
+ }
+ return EARG;
+ }
+ }
+
+ /**
+ * Command to send Key events to the input system.
+ */
+ private static class KeyCommand implements MonkeyCommand {
+ // key [down|up] [keycode]
+ // key down 82
+ // key up 82
+ public MonkeyCommandReturn translateCommand(List command,
+ CommandQueue queue) {
+ if (command.size() == 3) {
+ int keyCode = getKeyCode(command.get(2));
+ if (keyCode < 0) {
+ // Ok, you gave us something bad.
+ Log.e(TAG, "Can't find keyname: " + command.get(2));
+ return EARG;
+ }
+ Log.d(TAG, "keycode: " + keyCode);
+ int action = -1;
+ if ("down".equals(command.get(1))) {
+ action = KeyEvent.ACTION_DOWN;
+ } else if ("up".equals(command.get(1))) {
+ action = KeyEvent.ACTION_UP;
+ }
+ if (action == -1) {
+ Log.e(TAG, "got unknown action.");
+ return EARG;
+ }
+ queue.enqueueEvent(new MonkeyKeyEvent(action, keyCode));
+ return OK;
+ }
+ return EARG;
+ }
+ }
+
+ /**
+ * Get an integer keycode value from a given keyname.
+ *
+ * @param keyName the key name to get the code for
+ * @returns the integer keycode value, or -1 on error.
+ */
+ private static int getKeyCode(String keyName) {
+ int keyCode = -1;
+ try {
+ keyCode = Integer.parseInt(keyName);
+ } catch (NumberFormatException e) {
+ // Ok, it wasn't a number, see if we have a
+ // keycode name for it
+ keyCode = MonkeySourceRandom.getKeyCode(keyName);
+ if (keyCode == -1) {
+ // OK, one last ditch effort to find a match.
+ // Build the KEYCODE_STRING from the string
+ // we've been given and see if that key
+ // exists. This would allow you to do "key
+ // down menu", for example.
+ keyCode = MonkeySourceRandom.getKeyCode("KEYCODE_" + keyName.toUpperCase());
+ }
+ }
+ return keyCode;
+ }
+
+ /**
+ * Command to put the Monkey to sleep.
+ */
+ private static class SleepCommand implements MonkeyCommand {
+ // sleep 2000
+ public MonkeyCommandReturn translateCommand(List command,
+ CommandQueue queue) {
+ if (command.size() == 2) {
+ int sleep = -1;
+ String sleepStr = command.get(1);
+ try {
+ sleep = Integer.parseInt(sleepStr);
+ } catch (NumberFormatException e) {
+ Log.e(TAG, "Not a number: " + sleepStr, e);
+ return EARG;
+ }
+ queue.enqueueEvent(new MonkeyThrottleEvent(sleep));
+ return OK;
+ }
+ return EARG;
+ }
+ }
+
+ /**
+ * Command to type a string
+ */
+ private static class TypeCommand implements MonkeyCommand {
+ // wake
+ public MonkeyCommandReturn translateCommand(List command,
+ CommandQueue queue) {
+ if (command.size() == 2) {
+ String str = command.get(1);
+
+ char[] chars = str.toString().toCharArray();
+
+ // Convert the string to an array of KeyEvent's for
+ // the built in keymap.
+ KeyCharacterMap keyCharacterMap = KeyCharacterMap.
+ load(KeyCharacterMap.BUILT_IN_KEYBOARD);
+ KeyEvent[] events = keyCharacterMap.getEvents(chars);
+
+ // enqueue all the events we just got.
+ for (KeyEvent event : events) {
+ queue.enqueueEvent(new MonkeyKeyEvent(event));
+ }
+ return OK;
+ }
+ return EARG;
+ }
+ }
+
+ /**
+ * Command to wake the device up
+ */
+ private static class WakeCommand implements MonkeyCommand {
+ // wake
+ public MonkeyCommandReturn translateCommand(List command,
+ CommandQueue queue) {
+ if (!wake()) {
+ return ERROR;
+ }
+ return OK;
+ }
+ }
+
+ /**
+ * Command to "tap" at a location (Sends a down and up touch
+ * event).
+ */
+ private static class TapCommand implements MonkeyCommand {
+ // tap x y
+ public MonkeyCommandReturn translateCommand(List command,
+ CommandQueue queue) {
+ if (command.size() == 3) {
+ int x = 0;
+ int y = 0;
+ try {
+ x = Integer.parseInt(command.get(1));
+ y = Integer.parseInt(command.get(2));
+ } catch (NumberFormatException e) {
+ // Ok, it wasn't a number
+ Log.e(TAG, "Got something that wasn't a number", e);
+ return EARG;
+ }
+
+ queue.enqueueEvent(new MonkeyMotionEvent(MonkeyEvent.EVENT_TYPE_POINTER,
+ -1, MotionEvent.ACTION_DOWN,
+ x, y, 0));
+ queue.enqueueEvent(new MonkeyMotionEvent(MonkeyEvent.EVENT_TYPE_POINTER,
+ -1, MotionEvent.ACTION_UP,
+ x, y, 0));
+ return OK;
+ }
+ return EARG;
+ }
+ }
+
+ /**
+ * Command to "press" a buttons (Sends an up and down key event.)
+ */
+ private static class PressCommand implements MonkeyCommand {
+ // press keycode
+ public MonkeyCommandReturn translateCommand(List command,
+ CommandQueue queue) {
+ if (command.size() == 2) {
+ int keyCode = getKeyCode(command.get(1));
+ if (keyCode < 0) {
+ // Ok, you gave us something bad.
+ Log.e(TAG, "Can't find keyname: " + command.get(1));
+ return EARG;
+ }
+
+ queue.enqueueEvent(new MonkeyKeyEvent(KeyEvent.ACTION_DOWN, keyCode));
+ queue.enqueueEvent(new MonkeyKeyEvent(KeyEvent.ACTION_UP, keyCode));
+ return OK;
+
+ }
+ return EARG;
+ }
+ }
+
+ /**
+ * Force the device to wake up.
+ *
+ * @return true if woken up OK.
+ */
+ private static final boolean wake() {
+ IPowerManager pm =
+ IPowerManager.Stub.asInterface(ServiceManager.getService(Context.POWER_SERVICE));
+ try {
+ pm.userActivityWithForce(SystemClock.uptimeMillis(), true, true);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Got remote exception", e);
+ return false;
+ }
+ return true;
+ }
+
+ // This maps from command names to command implementations.
+ private static final Map COMMAND_MAP = new HashMap();
+
+ static {
+ // Add in all the commands we support
+ COMMAND_MAP.put("flip", new FlipCommand());
+ COMMAND_MAP.put("touch", new TouchCommand());
+ COMMAND_MAP.put("trackball", new TrackballCommand());
+ COMMAND_MAP.put("key", new KeyCommand());
+ COMMAND_MAP.put("sleep", new SleepCommand());
+ COMMAND_MAP.put("wake", new WakeCommand());
+ COMMAND_MAP.put("tap", new TapCommand());
+ COMMAND_MAP.put("press", new PressCommand());
+ COMMAND_MAP.put("type", new TypeCommand());
+ COMMAND_MAP.put("listvar", new MonkeySourceNetworkVars.ListVarCommand());
+ COMMAND_MAP.put("getvar", new MonkeySourceNetworkVars.GetVarCommand());
+ }
+
+ // QUIT command
+ private static final String QUIT = "quit";
+ // DONE command
+ private static final String DONE = "done";
+
+ // command response strings
+ private static final String OK_STR = "OK";
+ private static final String ERROR_STR = "ERROR";
+
+ public static interface CommandQueue {
+ /**
+ * Enqueue an event to be returned later. This allows a
+ * command to return multiple events. Commands using the
+ * command queue still have to return a valid event from their
+ * translateCommand method. The returned command will be
+ * executed before anything put into the queue.
+ *
+ * @param e the event to be enqueued.
+ */
+ public void enqueueEvent(MonkeyEvent e);
+ };
+
+ // Queue of Events to be processed. This allows commands to push
+ // multiple events into the queue to be processed.
+ private static class CommandQueueImpl implements CommandQueue{
+ private final Queue queuedEvents = new LinkedList();
+
+ public void enqueueEvent(MonkeyEvent e) {
+ queuedEvents.offer(e);
+ }
+
+ /**
+ * Get the next queued event to excecute.
+ *
+ * @returns the next event, or null if there aren't any more.
+ */
+ public MonkeyEvent getNextQueuedEvent() {
+ return queuedEvents.poll();
+ }
+ };
+
+ private final CommandQueueImpl commandQueue = new CommandQueueImpl();
+
+ private BufferedReader input;
+ private PrintWriter output;
+ private boolean started = false;
+
+ private ServerSocket serverSocket;
+ private Socket clientSocket;
+
+ public MonkeySourceNetwork(int port) throws IOException {
+ // Only bind this to local host. This means that you can only
+ // talk to the monkey locally, or though adb port forwarding.
+ serverSocket = new ServerSocket(port,
+ 0, // default backlog
+ InetAddress.getLocalHost());
+ }
+
+ /**
+ * Start a network server listening on the specified port. The
+ * network protocol is a line oriented protocol, where each line
+ * is a different command that can be run.
+ *
+ * @param port the port to listen on
+ */
+ private void startServer() throws IOException {
+ clientSocket = serverSocket.accept();
+ // At this point, we have a client connected. Wake the device
+ // up in preparation for doing some commands.
+ wake();
+
+ input = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
+ // auto-flush
+ output = new PrintWriter(clientSocket.getOutputStream(), true);
+ }
+
+ /**
+ * Stop the server from running so it can reconnect a new client.
+ */
+ private void stopServer() throws IOException {
+ clientSocket.close();
+ input.close();
+ output.close();
+ started = false;
+ }
+
+ /**
+ * Helper function for commandLineSplit that replaces quoted
+ * charaters with their real values.
+ *
+ * @param input the string to do replacement on.
+ * @returns the results with the characters replaced.
+ */
+ private static String replaceQuotedChars(String input) {
+ return input.replace("\\\"", "\"");
+ }
+
+ /**
+ * This function splits the given line into String parts. It obey's quoted
+ * strings and returns them as a single part.
+ *
+ * "This is a test" -> returns only one element
+ * This is a test -> returns four elements
+ *
+ * @param line the line to parse
+ * @return the List of elements
+ */
+ private static List commandLineSplit(String line) {
+ ArrayList result = new ArrayList();
+ StringTokenizer tok = new StringTokenizer(line);
+
+ boolean insideQuote = false;
+ StringBuffer quotedWord = new StringBuffer();
+ while (tok.hasMoreTokens()) {
+ String cur = tok.nextToken();
+ if (!insideQuote && cur.startsWith("\"")) {
+ // begin quote
+ quotedWord.append(replaceQuotedChars(cur));
+ insideQuote = true;
+ } else if (insideQuote) {
+ // end quote
+ if (cur.endsWith("\"")) {
+ insideQuote = false;
+ quotedWord.append(" ").append(replaceQuotedChars(cur));
+ String word = quotedWord.toString();
+
+ // trim off the quotes
+ result.add(word.substring(1, word.length() - 1));
+ } else {
+ quotedWord.append(" ").append(replaceQuotedChars(cur));
+ }
+ } else {
+ result.add(replaceQuotedChars(cur));
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Translate the given command line into a MonkeyEvent.
+ *
+ * @param commandLine the full command line given.
+ */
+ private void translateCommand(String commandLine) {
+ Log.d(TAG, "translateCommand: " + commandLine);
+ List parts = commandLineSplit(commandLine);
+ if (parts.size() > 0) {
+ MonkeyCommand command = COMMAND_MAP.get(parts.get(0));
+ if (command != null) {
+ MonkeyCommandReturn ret = command.translateCommand(parts,
+ commandQueue);
+ if (ret.wasSuccessful()) {
+ if (ret.hasMessage()) {
+ returnOk(ret.getMessage());
+ } else {
+ returnOk();
+ }
+ } else {
+ if (ret.hasMessage()) {
+ returnError(ret.getMessage());
+ } else {
+ returnError();
+ }
+ }
+ }
+ }
+ }
+
+ public MonkeyEvent getNextEvent() {
+ if (!started) {
+ try {
+ startServer();
+ } catch (IOException e) {
+ Log.e(TAG, "Got IOException from server", e);
+ return null;
+ }
+ started = true;
+ }
+
+ // Now, get the next command. This call may block, but that's OK
+ try {
+ while (true) {
+ // Check to see if we have any events queued up. If
+ // we do, use those until we have no more. Then get
+ // more input from the user.
+ MonkeyEvent queuedEvent = commandQueue.getNextQueuedEvent();
+ if (queuedEvent != null) {
+ // dispatch the event
+ return queuedEvent;
+ }
+
+ String command = input.readLine();
+ if (command == null) {
+ Log.d(TAG, "Connection dropped.");
+ // Treat this exactly the same as if the user had
+ // ended the session cleanly with a done commant.
+ command = DONE;
+ }
+
+ if (DONE.equals(command)) {
+ // stop the server so it can accept new connections
+ try {
+ stopServer();
+ } catch (IOException e) {
+ Log.e(TAG, "Got IOException shutting down!", e);
+ return null;
+ }
+ // return a noop event so we keep executing the main
+ // loop
+ return new MonkeyNoopEvent();
+ }
+
+ // Do quit checking here
+ if (QUIT.equals(command)) {
+ // then we're done
+ Log.d(TAG, "Quit requested");
+ // let the host know the command ran OK
+ returnOk();
+ return null;
+ }
+
+ // Do comment checking here. Comments aren't a
+ // command, so we don't echo anything back to the
+ // user.
+ if (command.startsWith("#")) {
+ // keep going
+ continue;
+ }
+
+ // Translate the command line. This will handle returning error/ok to the user
+ translateCommand(command);
+ }
+ } catch (IOException e) {
+ Log.e(TAG, "Exception: ", e);
+ return null;
+ }
+ }
+
+ /**
+ * Returns ERROR to the user.
+ */
+ private void returnError() {
+ output.println(ERROR_STR);
+ }
+
+ /**
+ * Returns ERROR to the user.
+ *
+ * @param msg the error message to include
+ */
+ private void returnError(String msg) {
+ output.print(ERROR_STR);
+ output.print(":");
+ output.println(msg);
+ }
+
+ /**
+ * Returns OK to the user.
+ */
+ private void returnOk() {
+ output.println(OK_STR);
+ }
+
+ /**
+ * Returns OK to the user.
+ *
+ * @param returnValue the value to return from this command.
+ */
+ private void returnOk(String returnValue) {
+ output.print(OK_STR);
+ output.print(":");
+ output.println(returnValue);
+ }
+
+ public void setVerbose(int verbose) {
+ // We're not particualy verbose
+ }
+
+ public boolean validate() {
+ // we have no pre-conditions to validate
+ return true;
+ }
+}
diff --git a/cmds/monkey/src/com/android/commands/monkey/MonkeySourceNetworkVars.java b/cmds/monkey/src/com/android/commands/monkey/MonkeySourceNetworkVars.java
new file mode 100644
index 000000000..e9890ad2b
--- /dev/null
+++ b/cmds/monkey/src/com/android/commands/monkey/MonkeySourceNetworkVars.java
@@ -0,0 +1,197 @@
+/*
+ * Copyright 2009, The Android Open Source Project
+ *
+ * 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.
+ */
+package com.android.commands.monkey;
+
+import android.os.Build;
+import android.os.SystemClock;
+import android.view.Display;
+import android.view.WindowManagerImpl;
+import android.util.DisplayMetrics;
+
+import com.android.commands.monkey.MonkeySourceNetwork.CommandQueue;
+import com.android.commands.monkey.MonkeySourceNetwork.MonkeyCommand;
+import com.android.commands.monkey.MonkeySourceNetwork.MonkeyCommandReturn;
+
+import java.lang.Integer;
+import java.lang.Float;
+import java.lang.Long;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+
+public class MonkeySourceNetworkVars {
+ /**
+ * Interface to get the value of a var.
+ */
+ private static interface VarGetter {
+ /**
+ * Get the value of the var.
+ * @returns the value of the var.
+ */
+ public String get();
+ }
+
+ private static class StaticVarGetter implements VarGetter {
+ private final String value;
+
+ public StaticVarGetter(String value) {
+ this.value = value;
+ }
+
+ public String get() {
+ return value;
+ }
+ }
+
+ // Use a TreeMap to keep the keys sorted so they get displayed nicely in listvar
+ private static final Map VAR_MAP = new TreeMap();
+
+ static {
+ VAR_MAP.put("build.board", new StaticVarGetter(Build.BOARD));
+ VAR_MAP.put("build.brand", new StaticVarGetter(Build.BRAND));
+ VAR_MAP.put("build.device", new StaticVarGetter(Build.DEVICE));
+ VAR_MAP.put("build.display", new StaticVarGetter(Build.DISPLAY));
+ VAR_MAP.put("build.fingerprint", new StaticVarGetter(Build.FINGERPRINT));
+ VAR_MAP.put("build.host", new StaticVarGetter(Build.HOST));
+ VAR_MAP.put("build.id", new StaticVarGetter(Build.ID));
+ VAR_MAP.put("build.model", new StaticVarGetter(Build.MODEL));
+ VAR_MAP.put("build.product", new StaticVarGetter(Build.PRODUCT));
+ VAR_MAP.put("build.tags", new StaticVarGetter(Build.TAGS));
+ VAR_MAP.put("build.brand", new StaticVarGetter(Long.toString(Build.TIME)));
+ VAR_MAP.put("build.type", new StaticVarGetter(Build.TYPE));
+ VAR_MAP.put("build.user", new StaticVarGetter(Build.USER));
+ VAR_MAP.put("build.cpu_abi", new StaticVarGetter(Build.CPU_ABI));
+ VAR_MAP.put("build.manufacturer", new StaticVarGetter(Build.MANUFACTURER));
+ VAR_MAP.put("build.version.incremental", new StaticVarGetter(Build.VERSION.INCREMENTAL));
+ VAR_MAP.put("build.version.release", new StaticVarGetter(Build.VERSION.RELEASE));
+ VAR_MAP.put("build.version.sdk", new StaticVarGetter(Integer.toString(Build.VERSION.SDK_INT)));
+ VAR_MAP.put("build.version.codename", new StaticVarGetter(Build.VERSION.CODENAME));
+
+ // Display
+ Display display = WindowManagerImpl.getDefault().getDefaultDisplay();
+ VAR_MAP.put("display.width", new StaticVarGetter(Integer.toString(display.getWidth())));
+ VAR_MAP.put("display.height", new StaticVarGetter(Integer.toString(display.getHeight())));
+
+ DisplayMetrics dm = new DisplayMetrics();
+ display.getMetrics(dm);
+ VAR_MAP.put("display.density", new StaticVarGetter(Float.toString(dm.density)));
+
+ // am. note that the current activity information isn't valid
+ // until the first activity gets launched after the monkey has
+ // been started.
+ VAR_MAP.put("am.current.package", new VarGetter() {
+ public String get() {
+ return Monkey.currentPackage;
+ }
+ });
+ VAR_MAP.put("am.current.action", new VarGetter() {
+ public String get() {
+ if (Monkey.currentIntent == null) {
+ return null;
+ }
+ return Monkey.currentIntent.getAction();
+ }
+ });
+ VAR_MAP.put("am.current.comp.class", new VarGetter() {
+ public String get() {
+ if (Monkey.currentIntent == null) {
+ return null;
+ }
+ return Monkey.currentIntent.getComponent().getClassName();
+ }
+ });
+ VAR_MAP.put("am.current.comp.package", new VarGetter() {
+ public String get() {
+ if (Monkey.currentIntent == null) {
+ return null;
+ }
+ return Monkey.currentIntent.getComponent().getPackageName();
+ }
+ });
+ VAR_MAP.put("am.current.data", new VarGetter() {
+ public String get() {
+ if (Monkey.currentIntent == null) {
+ return null;
+ }
+ return Monkey.currentIntent.getDataString();
+ }
+ });
+ VAR_MAP.put("am.current.categories", new VarGetter() {
+ public String get() {
+ if (Monkey.currentIntent == null) {
+ return null;
+ }
+ StringBuffer sb = new StringBuffer();
+ for (String cat : Monkey.currentIntent.getCategories()) {
+ sb.append(cat).append(" ");
+ }
+ return sb.toString();
+ }
+ });
+
+ // clock
+ VAR_MAP.put("clock.realtime", new VarGetter() {
+ public String get() {
+ return Long.toString(SystemClock.elapsedRealtime());
+ }
+ });
+ VAR_MAP.put("clock.uptime", new VarGetter() {
+ public String get() {
+ return Long.toString(SystemClock.uptimeMillis());
+ }
+ });
+ VAR_MAP.put("clock.millis", new VarGetter() {
+ public String get() {
+ return Long.toString(System.currentTimeMillis());
+ }
+ });
+ }
+
+ /**
+ * Command to list the "vars" that the monkey knows about.
+ */
+ public static class ListVarCommand implements MonkeySourceNetwork.MonkeyCommand {
+ // listvar
+ public MonkeyCommandReturn translateCommand(List command,
+ CommandQueue queue) {
+ Set keys = VAR_MAP.keySet();
+ StringBuffer sb = new StringBuffer();
+ for (String key : keys) {
+ sb.append(key).append(" ");
+ }
+ return new MonkeyCommandReturn(true, sb.toString());
+ }
+ }
+
+ /**
+ * Command to get the value of a var.
+ */
+ public static class GetVarCommand implements MonkeyCommand {
+ // getvar varname
+ public MonkeyCommandReturn translateCommand(List command,
+ CommandQueue queue) {
+ if (command.size() == 2) {
+ VarGetter getter = VAR_MAP.get(command.get(1));
+ if (getter == null) {
+ return new MonkeyCommandReturn(false, "unknown var");
+ }
+ return new MonkeyCommandReturn(true, getter.get());
+ }
+ return MonkeySourceNetwork.EARG;
+ }
+ }
+}
diff --git a/cmds/monkey/src/com/android/commands/monkey/MonkeySourceRandom.java b/cmds/monkey/src/com/android/commands/monkey/MonkeySourceRandom.java
index 5f9c10f03..27c8a5171 100644
--- a/cmds/monkey/src/com/android/commands/monkey/MonkeySourceRandom.java
+++ b/cmds/monkey/src/com/android/commands/monkey/MonkeySourceRandom.java
@@ -31,7 +31,7 @@ import java.util.Random;
/**
* monkey event queue
*/
-public class MonkeySourceRandom implements MonkeyEventSource {
+public class MonkeySourceRandom implements MonkeyEventSource {
/** Key events that move around the UI. */
private static final int[] NAV_KEYS = {
KeyEvent.KEYCODE_DPAD_UP, KeyEvent.KEYCODE_DPAD_DOWN,
@@ -55,7 +55,7 @@ public class MonkeySourceRandom implements MonkeyEventSource {
/** Nice names for all key events. */
private static final String[] KEY_NAMES = {
"KEYCODE_UNKNOWN",
- "KEYCODE_MENU",
+ "KEYCODE_SOFT_LEFT",
"KEYCODE_SOFT_RIGHT",
"KEYCODE_HOME",
"KEYCODE_BACK",
@@ -146,7 +146,7 @@ public class MonkeySourceRandom implements MonkeyEventSource {
"KEYCODE_REWIND",
"KEYCODE_FORWARD",
"KEYCODE_MUTE",
-
+
"TAG_LAST_KEYCODE" // EOL. used to keep the lists in sync
};
@@ -158,34 +158,50 @@ public class MonkeySourceRandom implements MonkeyEventSource {
public static final int FACTOR_SYSOPS = 5;
public static final int FACTOR_APPSWITCH = 6;
public static final int FACTOR_FLIP = 7;
- public static final int FACTOR_ANYTHING = 8;
+ public static final int FACTOR_ANYTHING = 8;
public static final int FACTORZ_COUNT = 9; // should be last+1
-
-
+
+
/** percentages for each type of event. These will be remapped to working
* values after we read any optional values.
- **/
+ **/
private float[] mFactors = new float[FACTORZ_COUNT];
private ArrayList mMainApps;
private int mEventCount = 0; //total number of events generated so far
private MonkeyEventQueue mQ;
- private Random mRandom;
+ private Random mRandom;
private int mVerbose = 0;
private long mThrottle = 0;
private boolean mKeyboardOpen = false;
- /**
+ /**
* @return the last name in the key list
*/
public static String getLastKeyName() {
return KEY_NAMES[KeyEvent.getMaxKeyCode() + 1];
}
-
+
public static String getKeyName(int keycode) {
return KEY_NAMES[keycode];
}
-
+
+ /**
+ * Looks up the keyCode from a given KEYCODE_NAME. NOTE: This may
+ * be an expensive operation.
+ *
+ * @param keyName the name of the KEYCODE_VALUE to lookup.
+ * @returns the intenger keyCode value, or -1 if not found
+ */
+ public static int getKeyCode(String keyName) {
+ for (int x = 0; x < KEY_NAMES.length; x++) {
+ if (KEY_NAMES[x].equals(keyName)) {
+ return x;
+ }
+ }
+ return -1;
+ }
+
public MonkeySourceRandom(long seed, ArrayList MainApps, long throttle) {
// default values for random distributions
// note, these are straight percentages, to match user input (cmd line args)
@@ -199,7 +215,7 @@ public class MonkeySourceRandom implements MonkeyEventSource {
mFactors[FACTOR_APPSWITCH] = 2.0f;
mFactors[FACTOR_FLIP] = 1.0f;
mFactors[FACTOR_ANYTHING] = 15.0f;
-
+
mRandom = new SecureRandom();
mRandom.setSeed((seed == 0) ? -1 : seed);
mMainApps = MainApps;
@@ -220,25 +236,25 @@ public class MonkeySourceRandom implements MonkeyEventSource {
} else {
defaultSum += mFactors[i];
++defaultCount;
- }
+ }
}
-
+
// if the user request was > 100%, reject it
if (userSum > 100.0f) {
System.err.println("** Event weights > 100%");
return false;
}
-
+
// if the user specified all of the weights, then they need to be 100%
if (defaultCount == 0 && (userSum < 99.9f || userSum > 100.1f)) {
System.err.println("** Event weights != 100%");
return false;
}
-
+
// compute the adjustment necessary
float defaultsTarget = (100.0f - userSum);
float defaultsAdjustment = defaultsTarget / defaultSum;
-
+
// fix all values, by adjusting defaults, or flipping user values back to >0
for (int i = 0; i < FACTORZ_COUNT; ++i) {
if (mFactors[i] <= 0.0f) { // user values are zero or negative
@@ -247,46 +263,46 @@ public class MonkeySourceRandom implements MonkeyEventSource {
mFactors[i] *= defaultsAdjustment;
}
}
-
+
// if verbose, show factors
-
+
if (mVerbose > 0) {
System.out.println("// Event percentages:");
for (int i = 0; i < FACTORZ_COUNT; ++i) {
System.out.println("// " + i + ": " + mFactors[i] + "%");
}
- }
-
+ }
+
// finally, normalize and convert to running sum
float sum = 0.0f;
for (int i = 0; i < FACTORZ_COUNT; ++i) {
sum += mFactors[i] / 100.0f;
mFactors[i] = sum;
- }
+ }
return true;
}
-
+
/**
* set the factors
- *
+ *
* @param factors: percentages for each type of event
*/
public void setFactors(float factors[]) {
int c = FACTORZ_COUNT;
if (factors.length < c) {
c = factors.length;
- }
+ }
for (int i = 0; i < c; i++)
mFactors[i] = factors[i];
}
-
+
public void setFactors(int index, float v) {
mFactors[index] = v;
}
-
+
/**
* Generates a random motion event. This method counts a down, move, and up as multiple events.
- *
+ *
* TODO: Test & fix the selectors when non-zero percentages
* TODO: Longpress.
* TODO: Fling.
@@ -294,13 +310,13 @@ public class MonkeySourceRandom implements MonkeyEventSource {
* TODO: More useful than the random walk here would be to pick a single random direction
* and distance, and divvy it up into a random number of segments. (This would serve to
* generate fling gestures, which are important).
- *
+ *
* @param random Random number source for positioning
- * @param motionEvent If false, touch/release. If true, touch/move/release.
- *
+ * @param motionEvent If false, touch/release. If true, touch/move/release.
+ *
*/
private void generateMotionEvent(Random random, boolean motionEvent){
-
+
Display display = WindowManagerImpl.getDefault().getDefaultDisplay();
float x = Math.abs(random.nextInt() % display.getWidth());
@@ -310,12 +326,12 @@ public class MonkeySourceRandom implements MonkeyEventSource {
if (downAt == -1) {
downAt = eventTime;
}
-
- MonkeyMotionEvent e = new MonkeyMotionEvent(MonkeyEvent.EVENT_TYPE_POINTER,
- downAt, MotionEvent.ACTION_DOWN, x, y, 0);
- e.setIntermediateNote(false);
+
+ MonkeyMotionEvent e = new MonkeyMotionEvent(MonkeyEvent.EVENT_TYPE_POINTER,
+ downAt, MotionEvent.ACTION_DOWN, x, y, 0);
+ e.setIntermediateNote(false);
mQ.addLast(e);
-
+
// sometimes we'll move during the touch
if (motionEvent) {
int count = random.nextInt(10);
@@ -323,34 +339,34 @@ public class MonkeySourceRandom implements MonkeyEventSource {
// generate some slop in the up event
x = (x + (random.nextInt() % 10)) % display.getWidth();
y = (y + (random.nextInt() % 10)) % display.getHeight();
-
- e = new MonkeyMotionEvent(MonkeyEvent.EVENT_TYPE_POINTER,
- downAt, MotionEvent.ACTION_MOVE, x, y, 0);
- e.setIntermediateNote(true);
+
+ e = new MonkeyMotionEvent(MonkeyEvent.EVENT_TYPE_POINTER,
+ downAt, MotionEvent.ACTION_MOVE, x, y, 0);
+ e.setIntermediateNote(true);
mQ.addLast(e);
}
}
// TODO generate some slop in the up event
- e = new MonkeyMotionEvent(MonkeyEvent.EVENT_TYPE_POINTER,
- downAt, MotionEvent.ACTION_UP, x, y, 0);
- e.setIntermediateNote(false);
+ e = new MonkeyMotionEvent(MonkeyEvent.EVENT_TYPE_POINTER,
+ downAt, MotionEvent.ACTION_UP, x, y, 0);
+ e.setIntermediateNote(false);
mQ.addLast(e);
}
-
+
/**
* Generates a random trackball event. This consists of a sequence of small moves, followed by
* an optional single click.
- *
+ *
* TODO: Longpress.
* TODO: Meta state
* TODO: Parameterize the % clicked
* TODO: More useful than the random walk here would be to pick a single random direction
* and distance, and divvy it up into a random number of segments. (This would serve to
* generate fling gestures, which are important).
- *
+ *
* @param random Random number source for positioning
- *
+ *
*/
private void generateTrackballEvent(Random random) {
Display display = WindowManagerImpl.getDefault().getDefaultDisplay();
@@ -362,47 +378,47 @@ public class MonkeySourceRandom implements MonkeyEventSource {
// generate a small random step
int dX = random.nextInt(10) - 5;
int dY = random.nextInt(10) - 5;
-
-
- e = new MonkeyMotionEvent(MonkeyEvent.EVENT_TYPE_TRACKBALL, -1,
- MotionEvent.ACTION_MOVE, dX, dY, 0);
- e.setIntermediateNote(i > 0);
+
+
+ e = new MonkeyMotionEvent(MonkeyEvent.EVENT_TYPE_TRACKBALL, -1,
+ MotionEvent.ACTION_MOVE, dX, dY, 0);
+ e.setIntermediateNote(i > 0);
mQ.addLast(e);
}
-
+
// 10% of trackball moves end with a click
if (0 == random.nextInt(10)) {
long downAt = SystemClock.uptimeMillis();
-
-
- e = new MonkeyMotionEvent(MonkeyEvent.EVENT_TYPE_TRACKBALL, downAt,
- MotionEvent.ACTION_DOWN, 0, 0, 0);
- e.setIntermediateNote(true);
+
+
+ e = new MonkeyMotionEvent(MonkeyEvent.EVENT_TYPE_TRACKBALL, downAt,
+ MotionEvent.ACTION_DOWN, 0, 0, 0);
+ e.setIntermediateNote(true);
mQ.addLast(e);
-
-
- e = new MonkeyMotionEvent(MonkeyEvent.EVENT_TYPE_TRACKBALL, downAt,
- MotionEvent.ACTION_UP, 0, 0, 0);
- e.setIntermediateNote(false);
+
+
+ e = new MonkeyMotionEvent(MonkeyEvent.EVENT_TYPE_TRACKBALL, downAt,
+ MotionEvent.ACTION_UP, 0, 0, 0);
+ e.setIntermediateNote(false);
mQ.addLast(e);
- }
+ }
}
-
- /**
+
+ /**
* generate a random event based on mFactor
*/
- private void generateEvents() {
+ private void generateEvents() {
float cls = mRandom.nextFloat();
int lastKey = 0;
boolean touchEvent = cls < mFactors[FACTOR_TOUCH];
boolean motionEvent = !touchEvent && (cls < mFactors[FACTOR_MOTION]);
- if (touchEvent || motionEvent) {
+ if (touchEvent || motionEvent) {
generateMotionEvent(mRandom, motionEvent);
return;
}
-
- if (cls < mFactors[FACTOR_TRACKBALL]) {
+
+ if (cls < mFactors[FACTOR_TRACKBALL]) {
generateTrackballEvent(mRandom);
return;
}
@@ -427,23 +443,23 @@ public class MonkeySourceRandom implements MonkeyEventSource {
} else {
lastKey = 1 + mRandom.nextInt(KeyEvent.getMaxKeyCode() - 1);
}
-
+
MonkeyKeyEvent e = new MonkeyKeyEvent(KeyEvent.ACTION_DOWN, lastKey);
mQ.addLast(e);
-
+
e = new MonkeyKeyEvent(KeyEvent.ACTION_UP, lastKey);
mQ.addLast(e);
}
-
+
public boolean validate() {
//check factors
return adjustEventFactors();
}
-
+
public void setVerbose(int verbose) {
mVerbose = verbose;
}
-
+
/**
* generate an activity event
*/
@@ -452,18 +468,18 @@ public class MonkeySourceRandom implements MonkeyEventSource {
mRandom.nextInt(mMainApps.size())));
mQ.addLast(e);
}
-
+
/**
* if the queue is empty, we generate events first
- * @return the first event in the queue
+ * @return the first event in the queue
*/
public MonkeyEvent getNextEvent() {
if (mQ.isEmpty()) {
generateEvents();
- }
- mEventCount++;
- MonkeyEvent e = mQ.getFirst();
- mQ.removeFirst();
+ }
+ mEventCount++;
+ MonkeyEvent e = mQ.getFirst();
+ mQ.removeFirst();
return e;
}
}
diff --git a/docs/SDK_RELEASE_NOTES b/docs/SDK_RELEASE_NOTES
index e117528e3..381c5da66 100644
--- a/docs/SDK_RELEASE_NOTES
+++ b/docs/SDK_RELEASE_NOTES
@@ -1,8 +1,8 @@
-
+
-click here if you are not redirected
+click here if you are not redirected
-
\ No newline at end of file
+