I'd like to run some android tests but I want to scedule or delay the execution of these tests. I'm trying to do this from SL4A. The idea is to install SL4A start the server from my laptop, run a special python script that will sleep for about 20 seconds then wakeup and launch the tests. I am performing some rather involved automation that requires my tests be run after I install them and disconnect the USB cable. I know I can issue intents from SL4A but I'm looking for the equivalent of:
adb shell am instrument \
-e class MyInstrumentationTestCase \
-w MyInstrumentationTestRunner
Can this be done via intent? Should I send a broadcast or use the start activity functions?
I've tried running a system command directly on the device from Python with this script but I get a "permission denied" error:
from subprocess import call
call(["am", "instrument", "-e", "class", "com.example.android.app.test.TestContactList", "-w", "com.example.app.test/com.zutubi.android.junitreport.JUnitReportTestRunner"])
UPDATE
I've also tried using os.system to run the command (see below modifications) and this gives a different error: soinfo_link_image(linker.cpp:1635): could not load library "libanroid_runtime.so" needed by "app_process"; caused by so info_relocate(linker.cpp:975): cannot locate symbol " sqlite3_stmt_readonly" referenced by "lib android_runtime.so"...CANNOT LINK EXECUTABLE
import os
#from subprocess import call
#call(["am", "instrument", "-e", "class", "com.example.android.app.test.TestContactList", "-w", "com.example.android.app.test/com.zutubi.android.junitreport.JUnitReportTestRunner"])
os.system('echo "Running tests"')
os.system('am instrument -e class com.example.android.app.test.TestContactList -w com.example.android.app.test/com.zutubi.android.junitreport.JUnitReportTestRunner')
What are any other options?
I have the following function, which will launch any SL4A script from within a Python SL4A script, as a separate process. You can not use subprocess for this type of thing.
You may be able to deduce what you need from this.
from android import Android
droid = Android()
def launch_script(path, visible=False):
visibilty = 'FORE' if visible else 'BACK'
activity = 'com.googlecode.android_scripting.action.LAUNCH_{0}GROUND_SCRIPT'.format(visibilty)
extras = {'com.googlecode.android_scripting.extra.SCRIPT_PATH': path}
packagename = 'com.googlecode.android_scripting'
classname = 'com.googlecode.android_scripting.activity.ScriptingLayerServiceLauncher'
intent = droid.makeIntent(activity, None, None, extras, None, packagename, classname).result
droid.startActivityIntent(intent)
Related
I have a simplest possible test app, developed with xamarin, deployed to a usb connected droid. With the goal of having one day a working intent url, I'm trying to call my main activity with adb shell am. Here are the first few lines of my MainActivity...
namespace DematAEAT_Android
{
[Activity(Label = "DematAEAT_Android", MainLauncher = true, Icon = "#drawable/icon")]
[IntentFilter(new[] { "AcquireSignedImage" },
Categories = new[] { Intent.CategoryBrowsable, Intent.CategoryDefault })]
public class MainActivity : Activity
{
int count = 1;
Here are two shell commands. In the first, the package manager successfully understands the package name and reports the apk path. In the second, the activity manager fails to resolve the class MainActivity. It fails with or without the namespace.
C:\Program Files (x86)\Android\android-sdk\platform-tools>adb -d shell pm path "fr.company.DematAEAT_Android"
package:/data/app/fr.company.DematAEAT_Android-1/base.apk
C:\Program Files (x86)\Android\android-sdk\platform-tools>adb -d shell am start -n "fr.company.DematAEAT_Android/.DematAEAT_Android.MainActivity"
Starting: Intent { cmp=fr.company.DematAEAT_Android/.DematAEAT_Android.MainActivity }
Error type 3
Error: Activity class {fr.company.DematAEAT_Android/fr.company.DematAEAT_Android.DematAEAT_Android.MainActivity} does not exist.
edit...
And yet, I can launch happily using monkey. The following command works fine. Tis as if there's a problem with the way I'm naming my activity class in the adb shell am call, but I can't spot it.
C:\Program Files (x86)\Android\android-sdk\platform-tools>adb shell monkey -p fr.company.DematAEAT_Android 1
Events injected: 1
## Network stats: elapsed time=170ms (0ms mobile, 0ms wifi, 170ms not connected)
Can anyone tell me how to call this activity?
This was a breaking change in Xamarin Android 5.0
Android Callable Wrapper Naming
The name mangling scheme for Android Callable Wrappers is changing. Previously, the Android Callable Wrapper package name was constructed by lowercasing the namespace name, which would result in packaging failures if more than one assembly contained a type with the same fully-qualified name.
With the 5.0 release, the default package names for Android Callable Wrappers will be based on the MD5SUM of the assembly-qualified name of the type being exported. This allows the same fully-qualified name to be provided from two different assemblies and not get a packaging error.
https://developer.xamarin.com/releases/android/xamarin.android_5/xamarin.android_5.1/#Android_Callable_Wrapper_Naming
You can override that for your Activity by specifying the name in the [Activity] attribute:
[Activity(Name = "fr.company.demeat_android.MainActivity")]
public class MainActivity : Activity {
/* ... */
}
Well who knew? I needed to grub around in my manifest.xml to discover that xamarin is appending a hash as a namespace in front of my activity name. So the adb call that works looks like this...
C:\Program Files (x86)\Android\android-sdk\platform-tools>adb -d shell am start -n fr.company.DematAEAT_Android/md5abda05033ab0415fc7a776c5d9734c74.BrowsableActivity
Starting: Intent { cmp=fr.company.DematAEAT_Android/md5abda05033ab0415fc7a776c5d9734c74.BrowsableActivity }
The story continues here. This will likely be an issue for anyone trying to start a xamarin activity via adb shell am, or trying to start a xamarin activity with an intent, or an intent url.
I would like to use the apitrace project on android. I followed the instructions from the readme file.
But get no trace where created.
I run this command
adb shell TRACE_FILE=/data/test.trace LD_PRELOAD=/data/egltrace.so am start -n APP_NAME
How can I make it work?
I tried following the instructions in Dalvik.markdown of the original distribution of apitrace, but without success.
The instructions say to set two properties: wrap._process_name_ and debug.apitrace.procname. The former has to be set, according to those instructions, to LD_PRELOAD=/data/egltrace.so. When launching the application I still wouldn't get any trace generated nor any apitrace-related message in the logcat.
I had more success by putting the LD_PRELOAD instruction in a script and using that as the wrapper. This is the script that I use, called /data/apitrace.sh:
LD_PRELOAD=/data/egltrace.so exec $#
You can also set the TRACE_FILE environment variable to specify the path to which the trace file should be written to. Otherwise it will be _/data/app_process.trace_. For example:
TRACE_FILE=/data/apitraces/mytrace.trace LD_PRELOAD=/data/egltrace.so exec $#
I believe apitrace takes care of adding numbers to the filename to prevent overwriting existing ones. So you'll have mytrace.trace, mytrace.1.trace, and so on.
So with this script in place I set the properties like so:
adb shell setprop wrap._process_name_ /data/apitrace.sh
adb shell setprop debug.apitrace.procname _process_name_
And then I launch the application. I see in the logcat something like the following:
I/dalvikvm( 5980): Exec: /system/bin/sh -c /data/apitrace.sh /system/bin/app_process /system/bin --application '--nice-name=_process_name_' com.android.internal.os.WrapperInit 25 17 'android.app.ActivityThread'
D/apitrace( 5991): apitrace: loaded
D/apitrace( 5991): apitrace[5991]: enabled for _process_name_
D/apitrace( 5991): apitrace: tracing to /data/app_process.trace
I'm using CyanogenMod 10.1.3, which is based on Android 4.2.2.
test.py script content:
import ....
device = MonkeyRunner.waitForConnection(10,sys.argv[1])
device.startActivity(component='package/activity')
'''
some monkeyrunner events
'''
I have two device , labled device1-id and device2-id
run the monkeyrunner test.py device1-id &
run the monkeyrunner test.py device2-id &
I found some events in device2-id were sent to device1-id. I don't know why ?
I noticed some tutorials , they said , if run monkeyrunner on more devices, could write the script like below:
device1 = MonkeyRunner.waitForConnection(10,device1-id)
device2 = MonkeyRunner.waitForConnection(10,device2-id)
device1.actions
device2.actions
but this wasn't what I need. Anybody know why the monkeyrunner behaves this ?
What I need is that , I have one script , would run the same script on multi device simultaneously .
You have to specify the monkey port so you may want to use a command line argument like so
# Imports the monkeyrunner modules used by this program
from com.android.monkeyrunner import MonkeyRunner, MonkeyDevice
import sys
# Connects to the current device, returning a MonkeyDevice object
device = MonkeyRunner.waitForConnection(timeOut,"emulator-"+ sys.argv[1])
MONKEYRunner Actions . . . .
NOTE: sys.arv[0] is always the test file
Call by entering the following on the command line:
monkeyrunner test.py PortNumber
I believe that Monkeyrunner is not thread safe.
To test this, create 2 scripts, hardcoding the deviceId into each.
Start each script:
In windows, use the "start script1" and then "start script2"
In Unix use "script1 &; script2 &"
Notice that script1 fails with errors after it looks like it started working just fine. and that SCript2 also fails to do what it was intended to do because it gets commands from both windows.
i created an empty file an named it something.py, and then i just copied the lines of code from the android developer website. However, if i try to run it, i get an
ImportError: No module named com.android.monkeyrunner
Is there something i am missing? There doesn't seem to be anything at the android developer website that addresses this issue. Here are the lines of code
from com.android.monkeyrunner import MonkeyRunner, MonkeyDevice
device = MonkeyRunner.waitForConnection()
device.installPackage('myproject/bin/Stamp_Client.apk')
package = 'com.example.main'
activity = 'com.example.Stamp_Client'
runComponent = package + '/' + activity
device.startActivity(component=runComponent)
device.press('KEYCODE_BUTTON_SELECT','DOWN_AND_UP')
device.press('KEYCODE_U','DOWN_AND_UP')
device.press('KEYCODE_S','DOWN_AND_UP')
device.press('KEYCODE_E','DOWN_AND_UP')
device.press('KEYCODE_R','DOWN_AND_UP')
device.press('KEYCODE_ENTER','DOWN_AND_UP')
device.press('KEYCODE_P','DOWN_AND_UP')
device.press('KEYCODE_A','DOWN_AND_UP')
device.press('KEYCODE_S','DOWN_AND_UP')
device.press('KEYCODE_S','DOWN_AND_UP')
device.press('KEYCODE_ENTER','DOWN_AND_UP')
device.press('KEYCODE_ENTER','DOWN_AND_UP')
Make sure you run:
$ monkeyrunner yourfile.py
instead of:
$ python yourfile.py
I guess you are missing the shebang:
#! /usr/bin/env monkeyrunner
that is if you are using Linux or OSX, for Windows you probably have to create a batch file.
I am working in Ubuntu.
I have a bunch of commands (say 10 commands like cmd1, cmd2, cmd3..............cmd10)
I want to write a python script, which can achieve the following:
It should traverse through the directory structure and apply a command
at particular directory path.
The location and the commands are already known to me.
Here is the example how, I want the script to operate.
/local/mnt/myspace/sample1$ cmd1
/local/mnt/myspace/sample2$ cmd2
/local/mnt/myspace$ cmd3
/local/mnt$cmd4
/local/mnt/myspace/sample9$ cmd 8
/local/mnt/myspace/sample3$ cmd10
can someone please help on this.
Maybe something like this:
import subprocess
import os
jobs=[
('/local/mnt/myspace/sample1', 'cmd1'),
('/local/mnt/myspace/sample2', 'cmd2'),
('/local/mnt/myspace', 'cmd3'),
('/local/mnt', 'cmd4'),
('/local/mnt/myspace/sample9', 'cmd', '8'),
('/local/mnt/myspace/sample3', 'cmd10'),
]
for job in jobs:
print "In", job[0], "executing", job[1:]
os.chdir(job[0])
subprocess.Popen(job[1:]).wait()
(just a quick shot)
Look how I have "abused" the apparent mistake at cmd 8 to show how to call programs which take parameters.
import os
pathCommands = {r'C:\Windows':'dir', r'C:\test':'cd..' }
for path, command in pathCommands.items():
os.chdir(path)
os.system(command)
Just use os.chdir(path).
Something like:
import os
from itertools import izip
paths = ('/local/mnt/myspace/sample1', '../sample2',
'../', '../', 'myspace/sample9/', '../sample3']
commands = (func1, func2, func3, func4, func5, func6)
for path, command in izip(paths, commands):
os.chdir(path)
command()
And just put each command in a function.
Edit: I thought it was different Python commands you wanted to run in different directories. If it's different external programs, use:
commands = (['cmd1', 'arg1'], ['cmd2', 'arg2'], ...)
for path, command in izip(paths, commands):
os.chdir(path)
subprocess.call(command)
No reason to use Popen and wait when this is specifically what call is for.