Implement Shared UIA Element Channel #97
Merged
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
With iOS 8 there seems to be a race condition between UIAutomation and Calabash when writing to the shared preferences (NSUserDefaults). This means that occasionally we experience a missed read or write to the preferences from one of: the Preferences-based UIA channel, the UI Automation process itself or from the application itself writing to preferences (see, e.g.: calabash/calabash-ios#585).
With this pull request, a new type of Channel for communicating with UIAutomation from the Calabash Server is defined. The channel is called "Shared Element" because it consists of an UIKit object (LPSharedUIATextField) which is accessible to both UIAutomation and the CalabashServer (LPUIASharedElementChannel).
The main benefits are
The trick that is used is to create a synchronized UITextField visible to UIAutomation and LPUIASharedElementChannel. When Calabash wants to send a command to UIAutomation, the setText method is called. When UIAutomation wants to send the reply back setValue is also called on the corresponding UIATextField object.
At first I did not like this solution (it has been discussed before) because in order for UIAutomation to get a reference to the UIATextField, it must be in the view hiearchy (potentially messing with the application view). Also calling
setValue
on a text field from UIAutomation would cause the keyboard to appear.However, I realized that we can detach the UITextField from the key window as soon as LPUIASharedElementChannel and UIAutomation has made an initial handshake. After the handshake the textfield is a secret shared object that is not accessible to the application. Also if we set the textfield as
enabled = 'NO'
then the keyboard doesn't appear.The high-level process is:
[LPSharedUIATextField synchronizeWithUIAutomation]
and await [LPSharedUIATextField isSynchronized]). Also, setup LPUIASharedElementChannel as the delegate of LPSharedUIATextField (the delegate will receive responses from UIAutomation) via a call-back (when [LPSharedUIATextField setText] is called).[LPSharedUIATextField setText:]
method. It then asynchronously awaits a response.setValue
method of UIAutomation.setValue
method on UIA eventually triggers thesetText:
method of LPSharedUIATextField which parses the JSON can calls the delegate.I've not done comprehensive testing but the initial results look good.
NOTE
Requires
run_loop 1.1.1.pre4
and using the new:uia_strategy: :shared_element
.