Waiting for multiple appWaitActivities not working

Hello there,
I’ve got an issue while testing an Android application which requires the user to select a certificate on app startup.
My setup:

  • Platform: Android
  • Appium 1.4.16
  • Android Emulator API 19
  • Java-Client 3.3.0
  • Mac OS X 10.10.5 Yosemite

Appium is able to launch the application using the capabilities appPackage=com.company.app and appActivity=.CertificateCheckActivity.
Because I had to set a lock screen PIN for the credential storage, Appium uses the Unlock.apk to give my app the main focus (the device says locked nonetheless).
However, when the emulator is started Android asks then for that PIN (that is com.android.settings.CredentialStorage).
If I don’t specify anything in appWaitPackage and appWaitActivity, Appium aborts the session creation, giving me an error that my application com.company.app.CertificateCheckActivity was never started.
If I specify appWaitPackage=com.android.settings and appWaitActivity=.CredentialStorage Appium creates the session and I can enter and submit the PIN (in the JUnit-setUp method), enabling the credential storage.
Now my app asks for the certificate and for that, Android displays com.android.keychain.KeyChainActivity, in which you can choose the proper certificate.
I am able to do so, but once I execute my test class again, Appium waits for the .CredentialStorage Activity to get focused, which of course doesn’t happen since the PIN got entered before.

I don’t like having to restart the emulator for each run, so is there any possibility to wait for multiple Activities?
I found something in the documentation, but that didn’t work for me.
I’ve tried:

caps.setCapability(MobileCapabilityType.APP_WAIT_PACKAGE, “com.android.settings”);
caps.setCapability(MobileCapabilityType.APP_WAIT_ACTIVITY, “.CredentialStorage”);

and

caps.setCapability(MobileCapabilityType.APP_WAIT_PACKAGE, “com.android.keychain”);
caps.setCapability(MobileCapabilityType.APP_WAIT_ACTIVITY, “.KeyChainActivity, com.android.settings.CredentialStorage”);

and almost all variations but it seems like appium just appends the waitActivity to the waitPackage capability.
It throws errors like this:

error: Failed to start an Appium session, err was: Error: com.android.keychain/.KeyChainActivity, com.android.settings.CredentialStorage never started. Current: com.android.settings/.CredentialStorage

However, using the capabilities above and having the PIN entered before, Appium creates the session successfully.

To summarize:

  • First run: app launch → com.android.settings.CredentialStorage → com.android.keychain.KeyChainActivity
  • all following runs in the same emulator: app launch → com.android.keychain.KeyChainActivity

So how do I wait for different activities to become visible?
Any help is kindly appreciated, if you need me to provide more info or logs let me know.

On an other note: Wouldn’t it make sense to make a server flag or capability which causes Appium NOT to unlock the screen? You could then send sendKeys-Commands which enter the lock screen PIN…

You should use explicit waits for this:

Thanks for your reply.
So I removed the appWaitPackage and appWaitActivity capabilities.
I were already using explicitly waits using code like this:

public MobileElement findElementOrNull(By by) {
try {
waitUntil(ExpectedConditions.visibilityOfElementLocated(by), 5);
return driver.findElement(by);
} catch (TimeoutException ex) {
return null;
}
}

public void waitUntil(Function<WebDriver, WebElement> isTrue, int timeoutSeconds) throws TimeoutException {
	WebDriverWait wait = new WebDriverWait(driver, timeoutSeconds);
	wait.until(isTrue);
}

with the param

By.id(“com.android.settings:id/old_password”)

which is the EditText control where you have to enter the PIN.

However, the outcome is very inconsistent.
After running this in a newly started emulator, the test passes.
In the second and third run in the same emulator Appium doesn’t create the session and the test fails, stating:

info: [debug] executing cmd: /Users/user/Android/sdk/platform-tools/adb -s emulator-5554 shell “am start -S -a android.intent.action.MAIN -c android.intent.category.LAUNCHER -f 0x10200000 -n com.company.app/.CertificateCheckActivity”
info: [debug] Waiting for pkg “com.company.app” and activity “.CertificateCheckActivity” to be focused
info: [debug] Getting focused package and activity
info: [debug] executing cmd: /Users/user/Android/sdk/platform-tools/adb -s emulator-5554 shell "dumpsys window windows”

23 more “dumpsys window windows” and finally:

error: com.company.app/.CertificateCheckActivity never started. Current: com.android.keychain/.KeyChainActivity

In a following run in a newly started emulator I set the wait timeout to 15 seconds, then the test passes in the first two runs, but fails in the third run.

Interesting. I can see that I may not have understood your initial question. Let me try and restate the problem:

Starting the Appium server is inconsistent. Usually the first run will work, but there is no guarantee that the second or third will run, and usually the third does fail.

This doesn’t seem test dependent from your description. In other words it doesn’t sound like you have a particular test that will guarantee this failure.

So are the tests running sequentially or are they running in parallel? I believe it is possible to run tests in such a way that you do not have to restart the app for every test, but a lot of that depends on your framework. I think you are running Java and I’m going to guess TestNg. If this is the case you may want to include more than one test in a file, using one setup, one before, and one after for the collection of tests.

Thanks for your reply.

I am using Java with JUnit 4.12. Currently there’s only one Test class.
I run the tests sequentially (there aren’t many).

My issue is, that Appium doesn’t wait for one of the declared appWaitActivites if I provide multiple.
As you can see from my initial post, I tried to declare multiple waitActivities using comma separated values as described in the documentation. To me it looks like Appium only concats the given appWaitPackage and appWaitActivity to one huge string.
If I declare the capabilities like this:

caps.setCapability(MobileCapabilityType.APP_WAIT_PACKAGE, “com.android.keychain,com.android.settings”);
caps.setCapability(MobileCapabilityType.APP_WAIT_ACTIVITY, “.KeyChainActivity,.CredentialStorage”);

It look for the focused app in the process of creating a new session:

info: [debug] Waiting for pkg “com.android.keychain,com.android.settings” and activity “.KeyChainActivity,.CredentialStorage” to be focused

It fails with the error:

error: com.android.keychain,com.android.settings/.KeyChainActivity,.CredentialStorage never started. Current: com.android.settings/.CredentialStorage

If I provide the activities in reversed order

info: [debug] Waiting for pkg “com.android.settings,com.android.keychain” and activity “.CredentialStorage,.KeyChainActivity” to be focused

if fails with the same error:

error: com.android.settings,com.android.keychain/.CredentialStorage,.KeyChainActivity never started. Current: com.android.settings/.CredentialStorage

If I provide the activities like this:

caps.setCapability(MobileCapabilityType.APP_WAIT_PACKAGE, “com.android.settings”);
caps.setCapability(MobileCapabilityType.APP_WAIT_ACTIVITY, “.CredentialStorage,com.android.keychain.KeyChainActivity”);

it establishes the session!

info: [debug] Waiting for pkg “com.android.settings” and activity “.CredentialStorage,com.android.keychain.KeyChainActivity” to be focused
info: [debug] Getting focused package and activity
info: [debug] executing cmd: /Users/maxs/Android/sdk/platform-tools/adb -s emulator-5554 shell “dumpsys window windows”
info: [debug] executing cmd: /Users/maxs/Android/sdk/platform-tools/adb -s emulator-5554 shell “getprop ro.build.version.release”
info: [debug] Device is at release version 4.3.1
info: [debug] Device launched! Ready for commands

however, if I then execute the test class again (not changing anything) it fails:

info: [debug] Waiting for pkg “com.android.settings” and activity “.CredentialStorage,com.android.keychain.KeyChainActivity” to be focused
[…]
error: com.android.settings/.CredentialStorage,com.android.keychain.KeyChainActivity never started. Current: com.android.keychain/.KeyChainActivity

So, the activity “.CredentialStorage” is only started once, in all following tests it isn’t (since the PIN to the credential storage was entered already), so it launches the “.KeyChainActivity” (for selecting the certificate).
The docs say that Appium DOES accept an array of possible activities which might be launched, but in fact, it doesn’t. Or am I doing that wrong?

I hope this makes things more clear.


Explanation of what Appium does while trying to create the session for the first time:

In the public static void setUp() method (annotated with BeforeClass) I initialise the capabilities and the driver.
Since my app requires a certificate, I had to set a lock screen PIN to protect the credential storage.
As you may know, Appium tries to “unlock” the device automatically on start up.
With that Unlock.apk my app is given the window focus. It does NOT unlock the device as a user would do by entering the PIN.
Because of that, Android displays a EditText in which you have to enter the PIN (that is the activity CredentialStorage from com.android.settings).
Because that is not the Package and activity I declared in the desired capabilities, Appium refuses to establish a session, since it looks for the focused package and activity before creating the session (it does something like adb dumpsys “window windows | grep mFocusedApp”)