appium-webdriveragent 16.12.3 → 16.12.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,15 @@
1
+ ## [16.12.5](https://github.com/appium/WebDriverAgent/compare/v16.12.4...v16.12.5) (2026-09-07)
2
+
3
+ ### Bug Fixes
4
+
5
+ * touch and scroll related view issue in IntegrationApp ([#1253](https://github.com/appium/WebDriverAgent/issues/1253)) ([34859e9](https://github.com/appium/WebDriverAgent/commit/34859e9b443c184505206576b3b531d85d2afbcf))
6
+
7
+ ## [16.12.4](https://github.com/appium/WebDriverAgent/compare/v16.12.3...v16.12.4) (2026-09-06)
8
+
9
+ ### Miscellaneous Chores
10
+
11
+ * add coordinate screen in the integration app ([#1251](https://github.com/appium/WebDriverAgent/issues/1251)) ([de6acac](https://github.com/appium/WebDriverAgent/commit/de6acac7ebbaf70915f0c09093e3a12623efcea2))
12
+
1
13
  ## [16.12.3](https://github.com/appium/WebDriverAgent/compare/v16.12.2...v16.12.3) (2026-09-04)
2
14
 
3
15
  ### Bug Fixes
@@ -932,6 +932,7 @@
932
932
  BEA2FA45BED17FE03010FECD /* FBFindElementCommands.h in Headers */ = {isa = PBXBuildFile; fileRef = EE9AB7581CAEDF0C008C271F /* FBFindElementCommands.h */; };
933
933
  BF9B191D841681A571BAFED1 /* _XCTestObservationPrivate-Protocol.h in Headers */ = {isa = PBXBuildFile; fileRef = C840A8703A7C8D48897E158A /* _XCTestObservationPrivate-Protocol.h */; settings = {ATTRIBUTES = (Public, ); }; };
934
934
  BFF5D9B9446DD542E5D6017D /* XCTTagSelection.h in Headers */ = {isa = PBXBuildFile; fileRef = 8E2092D85A7C691F157B1971 /* XCTTagSelection.h */; settings = {ATTRIBUTES = (Public, ); }; };
935
+ C01249000000000000000003 /* FBCoordinateProbeViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C01249000000000000000002 /* FBCoordinateProbeViewController.m */; };
935
936
  C040AE5F2E3B934E8EEAEE0F /* XCUIApplicationProcessDelegate-Protocol.h in Headers */ = {isa = PBXBuildFile; fileRef = 43FCB89739438814F43BCA24 /* XCUIApplicationProcessDelegate-Protocol.h */; settings = {ATTRIBUTES = (Public, ); }; };
936
937
  C07F140AF96143A0A5CAA2B0 /* XCTestCaseDiscoveryUIAutomationDelegate-Protocol.h in Headers */ = {isa = PBXBuildFile; fileRef = E29888B75A756D1CCD21604C /* XCTestCaseDiscoveryUIAutomationDelegate-Protocol.h */; settings = {ATTRIBUTES = (Public, ); }; };
937
938
  C1414C29C836902466C4D6DB /* XCTestCastMethodNamesUIAutomationDelegate-Protocol.h in Headers */ = {isa = PBXBuildFile; fileRef = A80A1C12FA9899367D316E8C /* XCTestCastMethodNamesUIAutomationDelegate-Protocol.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -1269,6 +1270,10 @@
1269
1270
  FEC3A97A4929115A192F947A /* XCUIDeviceEventAndStateInterface-Protocol.h in Headers */ = {isa = PBXBuildFile; fileRef = 003AAAB9CB5FB38E45E05F6F /* XCUIDeviceEventAndStateInterface-Protocol.h */; settings = {ATTRIBUTES = (Public, ); }; };
1270
1271
  FFA7672B731B57AB9283DD40 /* FBXCElementSnapshotWrapper.h in Headers */ = {isa = PBXBuildFile; fileRef = 13DE7A53287CA1EC003243C6 /* FBXCElementSnapshotWrapper.h */; };
1271
1272
  FFD70914E6D8CE5D4FED4B69 /* XCUIAXNotificationHandling-Protocol.h in Headers */ = {isa = PBXBuildFile; fileRef = EA96C2FEDE73CB5148BA4949 /* XCUIAXNotificationHandling-Protocol.h */; };
1273
+ 6C07E44E139D41D6BA092F39 /* FBTouchableViewTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 1D04760558C64B8EB69380E0 /* FBTouchableViewTests.m */; };
1274
+ C15E49E6B6924191BAAD9FDF /* FBIntegrationAppTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 27B518E261C14E29B943AB9B /* FBIntegrationAppTests.m */; };
1275
+ 81E462B8A75F497CBFC6FD8B /* TouchableView.m in Sources */ = {isa = PBXBuildFile; fileRef = 315A15002518CB8700A3A064 /* TouchableView.m */; };
1276
+ B6DE70BFF27148BDAC72F80C /* TouchSpotView.m in Sources */ = {isa = PBXBuildFile; fileRef = 315A15062518CC2800A3A064 /* TouchSpotView.m */; };
1272
1277
  /* End PBXBuildFile section */
1273
1278
 
1274
1279
  /* Begin PBXContainerItemProxy section */
@@ -1748,6 +1753,8 @@
1748
1753
  B8A163261EFA440E42CA6AC1 /* XCTRunnerDaemonSessionUIAutomationDelegate-Protocol.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "XCTRunnerDaemonSessionUIAutomationDelegate-Protocol.h"; sourceTree = "<group>"; };
1749
1754
  B98A9F937EF98D6359FCCC7A /* XCTRuntimeIssueDetectionPolicy.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = XCTRuntimeIssueDetectionPolicy.h; sourceTree = "<group>"; };
1750
1755
  BCED63DFD03326F6351165FE /* WDAFindIntegrationTests.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = WDAFindIntegrationTests.swift; sourceTree = "<group>"; };
1756
+ C01249000000000000000001 /* FBCoordinateProbeViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FBCoordinateProbeViewController.h; sourceTree = "<group>"; };
1757
+ C01249000000000000000002 /* FBCoordinateProbeViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FBCoordinateProbeViewController.m; sourceTree = "<group>"; };
1751
1758
  C840A8703A7C8D48897E158A /* _XCTestObservationPrivate-Protocol.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "_XCTestObservationPrivate-Protocol.h"; sourceTree = "<group>"; };
1752
1759
  C878996F07A9B26E66FC4EAC /* WDAClickIntegrationTests.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = WDAClickIntegrationTests.swift; sourceTree = "<group>"; };
1753
1760
  C8FB547322D3949C00B69954 /* LSApplicationWorkspace.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LSApplicationWorkspace.h; sourceTree = "<group>"; };
@@ -1959,6 +1966,8 @@
1959
1966
  FCD1815F2BF21CA0936B04E1 /* XCTMessagingRole_SiriAutomation-Protocol.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "XCTMessagingRole_SiriAutomation-Protocol.h"; sourceTree = "<group>"; };
1960
1967
  FDB15E393EA0850C004D26B2 /* XCTScreenCapturePolicy.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = XCTScreenCapturePolicy.h; sourceTree = "<group>"; };
1961
1968
  FF8E3B470FC9639D5F18E2EA /* Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
1969
+ 1D04760558C64B8EB69380E0 /* FBTouchableViewTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FBTouchableViewTests.m; sourceTree = "<group>"; };
1970
+ 27B518E261C14E29B943AB9B /* FBIntegrationAppTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FBIntegrationAppTests.m; sourceTree = "<group>"; };
1962
1971
  /* End PBXFileReference section */
1963
1972
 
1964
1973
  /* Begin PBXFrameworksBuildPhase section */
@@ -2629,6 +2638,7 @@
2629
2638
  EE9B76541CF7987300275851 /* IntegrationTests */ = {
2630
2639
  isa = PBXGroup;
2631
2640
  children = (
2641
+ 27B518E261C14E29B943AB9B /* FBIntegrationAppTests.m */,
2632
2642
  EE9B76991CF799F400275851 /* FBAlertTests.m */,
2633
2643
  719CD8FE2126C90200C7D0C2 /* FBAutoAlertsHandlerTests.m */,
2634
2644
  EE26409C1D0EBA25009BE6B0 /* FBElementAttributeTests.m */,
@@ -2672,6 +2682,7 @@
2672
2682
  EE9B76561CF7987300275851 /* UnitTests */ = {
2673
2683
  isa = PBXGroup;
2674
2684
  children = (
2685
+ 1D04760558C64B8EB69380E0 /* FBTouchableViewTests.m */,
2675
2686
  ADBC39951D07840300327304 /* Doubles */,
2676
2687
  71A7EAFB1E229302001DA4F2 /* FBClassChainTests.m */,
2677
2688
  EEE16E961D33A25500172525 /* FBConfigurationTests.m */,
@@ -2732,6 +2743,8 @@
2732
2743
  EE55B3231D1D5388003AAAEC /* FBTableDataSource.m */,
2733
2744
  EE9B76841CF7997600275851 /* ViewController.h */,
2734
2745
  EE9B76851CF7997600275851 /* ViewController.m */,
2746
+ C01249000000000000000001 /* FBCoordinateProbeViewController.h */,
2747
+ C01249000000000000000002 /* FBCoordinateProbeViewController.m */,
2735
2748
  315A14FF2518CB8700A3A064 /* TouchableView.h */,
2736
2749
  315A15002518CB8700A3A064 /* TouchableView.m */,
2737
2750
  315A15052518CC2800A3A064 /* TouchSpotView.h */,
@@ -4809,6 +4822,9 @@
4809
4822
  isa = PBXSourcesBuildPhase;
4810
4823
  buildActionMask = 2147483647;
4811
4824
  files = (
4825
+ B6DE70BFF27148BDAC72F80C /* TouchSpotView.m in Sources */,
4826
+ 81E462B8A75F497CBFC6FD8B /* TouchableView.m in Sources */,
4827
+ 6C07E44E139D41D6BA092F39 /* FBTouchableViewTests.m in Sources */,
4812
4828
  713352FD26CEF31D00523CBC /* FBLRUCacheTests.m in Sources */,
4813
4829
  EE3F8CFE1D08AA17006F02CE /* FBRunLoopSpinnerTests.m in Sources */,
4814
4830
  A09D847635CA4C155583B967 /* FBXCAXClientProxyTests.m in Sources */,
@@ -4851,6 +4867,7 @@
4851
4867
  315A15072518CC2800A3A064 /* TouchSpotView.m in Sources */,
4852
4868
  EE9B76911CF7997600275851 /* main.m in Sources */,
4853
4869
  EE9B768F1CF7997600275851 /* ViewController.m in Sources */,
4870
+ C01249000000000000000003 /* FBCoordinateProbeViewController.m in Sources */,
4854
4871
  315A15012518CB8700A3A064 /* TouchableView.m in Sources */,
4855
4872
  315A150A2518D6F400A3A064 /* TouchViewController.m in Sources */,
4856
4873
  ADDA07241D6BB2BF001700AC /* FBScrollViewController.m in Sources */,
@@ -4863,6 +4880,7 @@
4863
4880
  isa = PBXSourcesBuildPhase;
4864
4881
  buildActionMask = 2147483647;
4865
4882
  files = (
4883
+ C15E49E6B6924191BAAD9FDF /* FBIntegrationAppTests.m in Sources */,
4866
4884
  EE26409D1D0EBA25009BE6B0 /* FBElementAttributeTests.m in Sources */,
4867
4885
  7119E1EC1E891F8600D0B125 /* FBPickerWheelSelectTests.m in Sources */,
4868
4886
  71ACF5B8242F2FDC00F0AAD4 /* FBSafariAlertTests.m in Sources */,
@@ -46,6 +46,7 @@
46
46
  BuildableIdentifier = "primary"
47
47
  BlueprintIdentifier = "9D6B02D8FC050BAF7159284F"
48
48
  BuildableName = "IntegrationApp_watchOS.app"
49
+ BlueprintName = "IntegrationApp_watchOS"
49
50
  ReferencedContainer = "container:WebDriverAgent.xcodeproj">
50
51
  </BuildableReference>
51
52
  </BuildableProductRunnable>
@@ -62,6 +63,7 @@
62
63
  BuildableIdentifier = "primary"
63
64
  BlueprintIdentifier = "9D6B02D8FC050BAF7159284F"
64
65
  BuildableName = "IntegrationApp_watchOS.app"
66
+ BlueprintName = "IntegrationApp_watchOS"
65
67
  ReferencedContainer = "container:WebDriverAgent.xcodeproj">
66
68
  </BuildableReference>
67
69
  </BuildableProductRunnable>
@@ -15,11 +15,11 @@
15
15
  <key>CFBundlePackageType</key>
16
16
  <string>FMWK</string>
17
17
  <key>CFBundleShortVersionString</key>
18
- <string>16.12.3</string>
18
+ <string>16.12.5</string>
19
19
  <key>CFBundleSignature</key>
20
20
  <string>????</string>
21
21
  <key>CFBundleVersion</key>
22
- <string>16.12.3</string>
22
+ <string>16.12.5</string>
23
23
  <key>NSPrincipalClass</key>
24
24
  <string/>
25
25
  </dict>
@@ -0,0 +1,50 @@
1
+ # Coordinate probe
2
+
3
+ Open **Coordinate Probe** below **DeepHierarchy** on the IntegrationApp home screen.
4
+ Use the standard Back button to return to the existing fixtures. Opening the probe
5
+ creates a fresh measurement session.
6
+
7
+ The **Touch** canvas records actual `UITouch.locationInView:` coordinates rather
8
+ than assuming that a gesture succeeded because it hit a large button. **Scroll**
9
+ shows 80 numbered rows, each 44 points high.
10
+
11
+ ## Automation identifiers
12
+
13
+ | Identifier | Purpose |
14
+ | --- | --- |
15
+ | `coordinate-probe` | Home screen button that opens the probe |
16
+ | `probe-status` | Label containing the measurement JSON |
17
+ | `coordinate-canvas` | Touch target |
18
+ | `probe-mode` | Touch/Scroll segmented control |
19
+ | `probe-table` | Scrollable table |
20
+ | `probe-row-0` through `probe-row-79` | Individual table rows |
21
+
22
+ The `probe-status` label exposes `start`, `last`, `phase`, and `count` after a
23
+ touch. `start` and `last` are **canvas-local app points**. It also exposes
24
+ `canvasBounds`, `canvasWindowRect`, `windowSize`, `screenSize`, and `scrollY`.
25
+ Geometry is refreshed when the view lays out, including after rotation or window
26
+ resizing. Touch-related fields are absent before the first touch.
27
+
28
+ For example, locate `coordinate-probe` by accessibility ID and click it. Then
29
+ locate `coordinate-canvas`, send an element-relative action, and read the JSON
30
+ from `probe-status`. Check that `count` increased and compare `start`/`last` with
31
+ the expected canvas-local point within a suitable tolerance. Derive test offsets
32
+ from the current element rectangle rather than hard-coding a device size.
33
+
34
+ ## Native and compatibility builds
35
+
36
+ The screen uses the same source for both configurations. Keep the IntegrationApp
37
+ scheme and set the build's `TARGETED_DEVICE_FAMILY`:
38
+
39
+ - `1,2`: native support for iPhone and iPad (the existing default).
40
+ - `1`: iPhone-only; install on iPad to exercise iPhone compatibility mode.
41
+
42
+ These are build settings, not a switch within the running app. Verify the actual
43
+ window and element frames before interpreting results. An iPad-native app can
44
+ also run in a resized window; maximize it when testing a full-screen native case.
45
+ For the compatibility case, compare app and SpringBoard window sizes and the
46
+ reported element rectangles with the recorded probe geometry.
47
+
48
+ If keeping both builds installed at once, give them distinct bundle IDs. This
49
+ change does not add another app target or alter the existing bundle ID or signing
50
+ configuration.
@@ -0,0 +1,4 @@
1
+ #import <UIKit/UIKit.h>
2
+
3
+ @interface FBCoordinateProbeViewController : UIViewController
4
+ @end
@@ -0,0 +1,176 @@
1
+ #import "FBCoordinateProbeViewController.h"
2
+
3
+ @interface FBCoordinateProbeCanvas : UIView
4
+ @property (nonatomic, copy) void (^onTouch)(NSString *phase, CGPoint point);
5
+ @end
6
+
7
+ @implementation FBCoordinateProbeCanvas
8
+
9
+ - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
10
+ {
11
+ self.onTouch(@"began", [touches.anyObject locationInView:self]);
12
+ }
13
+
14
+ - (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
15
+ {
16
+ self.onTouch(@"moved", [touches.anyObject locationInView:self]);
17
+ }
18
+
19
+ - (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
20
+ {
21
+ self.onTouch(@"ended", [touches.anyObject locationInView:self]);
22
+ }
23
+
24
+ - (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
25
+ {
26
+ self.onTouch(@"cancelled", [touches.anyObject locationInView:self]);
27
+ }
28
+
29
+ - (void)drawRect:(CGRect)rect
30
+ {
31
+ CGContextRef context = UIGraphicsGetCurrentContext();
32
+ CGContextSetStrokeColorWithColor(context, UIColor.whiteColor.CGColor);
33
+ for (NSInteger i = 1; i < 4; i++) {
34
+ CGFloat x = CGRectGetWidth(self.bounds) * i / 4.0;
35
+ CGFloat y = CGRectGetHeight(self.bounds) * i / 4.0;
36
+ CGContextMoveToPoint(context, x, 0);
37
+ CGContextAddLineToPoint(context, x, CGRectGetHeight(self.bounds));
38
+ CGContextMoveToPoint(context, 0, y);
39
+ CGContextAddLineToPoint(context, CGRectGetWidth(self.bounds), y);
40
+ }
41
+ CGContextStrokePath(context);
42
+ }
43
+
44
+ @end
45
+
46
+ @interface FBCoordinateProbeViewController () <UITableViewDataSource, UITableViewDelegate>
47
+ @property (nonatomic, strong) UILabel *statusLabel;
48
+ @property (nonatomic, strong) UISegmentedControl *modeControl;
49
+ @property (nonatomic, strong) FBCoordinateProbeCanvas *canvas;
50
+ @property (nonatomic, strong) UITableView *table;
51
+ @property (nonatomic, strong) NSMutableDictionary<NSString *, id> *measurement;
52
+ @property (nonatomic) NSUInteger touchCount;
53
+ @end
54
+
55
+ @implementation FBCoordinateProbeViewController
56
+
57
+ - (void)viewDidLoad
58
+ {
59
+ [super viewDidLoad];
60
+ self.title = @"Coordinate Probe";
61
+ self.view.backgroundColor = UIColor.systemBackgroundColor;
62
+ self.measurement = [NSMutableDictionary dictionary];
63
+
64
+ self.statusLabel = [UILabel new];
65
+ self.statusLabel.accessibilityIdentifier = @"probe-status";
66
+ self.statusLabel.font = [UIFont monospacedSystemFontOfSize:10 weight:UIFontWeightRegular];
67
+ self.statusLabel.numberOfLines = 0;
68
+ [self.view addSubview:self.statusLabel];
69
+
70
+ self.modeControl = [[UISegmentedControl alloc] initWithItems:@[@"Touch", @"Scroll"]];
71
+ self.modeControl.accessibilityIdentifier = @"probe-mode";
72
+ self.modeControl.selectedSegmentIndex = 0;
73
+ [self.modeControl addTarget:self action:@selector(modeChanged) forControlEvents:UIControlEventValueChanged];
74
+ [self.view addSubview:self.modeControl];
75
+
76
+ self.canvas = [FBCoordinateProbeCanvas new];
77
+ self.canvas.backgroundColor = UIColor.systemBlueColor;
78
+ self.canvas.isAccessibilityElement = YES;
79
+ self.canvas.accessibilityIdentifier = @"coordinate-canvas";
80
+ self.canvas.accessibilityLabel = @"Coordinate canvas";
81
+ self.canvas.accessibilityTraits = UIAccessibilityTraitAllowsDirectInteraction;
82
+ self.canvas.contentMode = UIViewContentModeRedraw;
83
+ __weak typeof(self) weakSelf = self;
84
+ self.canvas.onTouch = ^(NSString *phase, CGPoint point) {
85
+ FBCoordinateProbeViewController *controller = weakSelf;
86
+ if (nil == controller) {
87
+ return;
88
+ }
89
+ if ([phase isEqualToString:@"began"]) {
90
+ controller.touchCount++;
91
+ controller.measurement[@"start"] = @[@(point.x), @(point.y)];
92
+ }
93
+ controller.measurement[@"last"] = @[@(point.x), @(point.y)];
94
+ controller.measurement[@"phase"] = phase;
95
+ controller.measurement[@"count"] = @(controller.touchCount);
96
+ [controller publishMeasurement];
97
+ };
98
+ [self.view addSubview:self.canvas];
99
+
100
+ self.table = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain];
101
+ self.table.accessibilityIdentifier = @"probe-table";
102
+ self.table.rowHeight = 44;
103
+ self.table.dataSource = self;
104
+ self.table.delegate = self;
105
+ self.table.hidden = YES;
106
+ [self.view addSubview:self.table];
107
+ }
108
+
109
+ - (void)viewDidLayoutSubviews
110
+ {
111
+ [super viewDidLayoutSubviews];
112
+ // Use the app's actual available area, including navigation bars and resized iPad windows.
113
+ CGRect safeFrame = self.view.safeAreaLayoutGuide.layoutFrame;
114
+ CGFloat width = MAX(0, CGRectGetWidth(safeFrame) - 40);
115
+ CGFloat left = CGRectGetMinX(safeFrame) + 20;
116
+ CGFloat top = CGRectGetMinY(safeFrame) + 8;
117
+ self.statusLabel.frame = CGRectMake(left, top, width, 96);
118
+ self.modeControl.frame = CGRectMake(left, top + 104, width, 30);
119
+ CGRect contentFrame = CGRectMake(left, top + 146, width,
120
+ MAX(0, CGRectGetMaxY(safeFrame) - top - 166));
121
+ self.canvas.frame = contentFrame;
122
+ self.table.frame = contentFrame;
123
+ [self publishMeasurement];
124
+ }
125
+
126
+ - (void)publishMeasurement
127
+ {
128
+ UIWindow *window = self.view.window;
129
+ if (nil == window) {
130
+ return;
131
+ }
132
+ CGRect bounds = self.canvas.bounds;
133
+ CGRect frame = [self.canvas convertRect:bounds toView:window];
134
+ // Touch coordinates are local to the canvas. Window geometry lets tests compare
135
+ // those measurements with WDA's element rectangles without assuming a screen size.
136
+ self.measurement[@"canvasBounds"] = @[@(bounds.size.width), @(bounds.size.height)];
137
+ self.measurement[@"canvasWindowRect"] = @[@(frame.origin.x), @(frame.origin.y),
138
+ @(frame.size.width), @(frame.size.height)];
139
+ self.measurement[@"windowSize"] = @[@(window.bounds.size.width), @(window.bounds.size.height)];
140
+ self.measurement[@"screenSize"] = @[@(window.screen.bounds.size.width), @(window.screen.bounds.size.height)];
141
+ self.measurement[@"scrollY"] = @(self.table.contentOffset.y);
142
+ NSData *data = [NSJSONSerialization dataWithJSONObject:self.measurement
143
+ options:NSJSONWritingSortedKeys
144
+ error:nil];
145
+ self.statusLabel.text = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
146
+ }
147
+
148
+ - (void)modeChanged
149
+ {
150
+ self.canvas.hidden = self.modeControl.selectedSegmentIndex == 1;
151
+ self.table.hidden = !self.canvas.hidden;
152
+ [self publishMeasurement];
153
+ }
154
+
155
+ - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
156
+ {
157
+ return 80;
158
+ }
159
+
160
+ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
161
+ {
162
+ UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"probe-row"];
163
+ if (nil == cell) {
164
+ cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"probe-row"];
165
+ }
166
+ cell.textLabel.text = [NSString stringWithFormat:@"Probe row %ld", (long)indexPath.row];
167
+ cell.accessibilityIdentifier = [NSString stringWithFormat:@"probe-row-%ld", (long)indexPath.row];
168
+ return cell;
169
+ }
170
+
171
+ - (void)scrollViewDidScroll:(UIScrollView *)scrollView
172
+ {
173
+ [self publishMeasurement];
174
+ }
175
+
176
+ @end
@@ -15,6 +15,7 @@ static const CGFloat FBSubviewHeight = 40.0;
15
15
  @interface FBScrollViewController ()
16
16
  @property (nonatomic, weak) IBOutlet UIScrollView *scrollView;
17
17
  @property (nonatomic, strong) IBOutlet FBTableDataSource *dataSource;
18
+ @property (nonatomic, copy) NSArray<UILabel *> *rowLabels;
18
19
  @end
19
20
 
20
21
  @implementation FBScrollViewController
@@ -22,18 +23,30 @@ static const CGFloat FBSubviewHeight = 40.0;
22
23
  - (void)viewDidLoad {
23
24
  [super viewDidLoad];
24
25
  [self setupLabelViews];
25
- self.scrollView.contentSize = CGSizeMake(CGRectGetWidth(self.view.frame), self.dataSource.count * FBSubviewHeight);
26
+ }
27
+
28
+ - (void)viewDidLayoutSubviews
29
+ {
30
+ [super viewDidLayoutSubviews];
31
+ CGFloat width = CGRectGetWidth(self.scrollView.bounds);
32
+ [self.rowLabels enumerateObjectsUsingBlock:^(UILabel *label, NSUInteger index, BOOL *stop) {
33
+ label.frame = CGRectMake(0, index * FBSubviewHeight, width, FBSubviewHeight);
34
+ }];
35
+ self.scrollView.contentSize = CGSizeMake(width, self.rowLabels.count * FBSubviewHeight);
26
36
  }
27
37
 
28
38
  - (void)setupLabelViews
29
39
  {
30
40
  NSUInteger count = self.dataSource.count;
41
+ NSMutableArray<UILabel *> *labels = [NSMutableArray arrayWithCapacity:count];
31
42
  for (NSInteger i = 0 ; i < count ; i++) {
32
- UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, i * FBSubviewHeight, CGRectGetWidth(self.view.frame), FBSubviewHeight)];
43
+ UILabel *label = [UILabel new];
33
44
  label.text = [self.dataSource textForElementAtIndex:i];
34
45
  label.textAlignment = NSTextAlignmentCenter;
35
46
  [self.scrollView addSubview:label];
47
+ [labels addObject:label];
36
48
  }
49
+ self.rowLabels = labels;
37
50
  }
38
51
 
39
52
  @end
@@ -11,7 +11,7 @@
11
11
 
12
12
  NS_ASSUME_NONNULL_BEGIN
13
13
 
14
- @interface TouchViewController : UIViewController
14
+ @interface TouchViewController : UIViewController <TouchableViewDelegate>
15
15
 
16
16
  @property (weak, nonatomic) IBOutlet TouchableView *touchable;
17
17
  @property (weak, nonatomic) IBOutlet UILabel *numberOfTapsLabel;
@@ -21,8 +21,9 @@ NS_ASSUME_NONNULL_BEGIN
21
21
  @interface TouchableView : UIView
22
22
 
23
23
  @property (nonatomic) NSMutableDictionary<NSNumber*, TouchSpotView*> *touchViews;
24
+ // Cumulative completed contacts; cancelled contacts are excluded.
24
25
  @property (nonatomic) int numberOFTaps;
25
- @property (nonatomic) id delegate;
26
+ @property (nonatomic, weak, nullable) id<TouchableViewDelegate> delegate;
26
27
 
27
28
  @end
28
29
 
@@ -34,12 +34,11 @@
34
34
 
35
35
  - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
36
36
  {
37
- self.numberOFTaps += 1;
38
- [self.delegate shouldHandleTouchesNumber:(int)touches.count];
39
37
  for (UITouch *touch in touches)
40
38
  {
41
39
  [self createViewForTouch:touch];
42
40
  }
41
+ [self.delegate shouldHandleTouchesNumber:(int)self.touchViews.count];
43
42
  }
44
43
 
45
44
  - (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
@@ -56,8 +55,13 @@
56
55
  {
57
56
  for (UITouch *touch in touches)
58
57
  {
58
+ // Count completed contacts, independently of how UIKit batches callbacks.
59
+ if ([self viewForTouch:touch] != nil) {
60
+ self.numberOFTaps += 1;
61
+ }
59
62
  [self removeViewForTouch:touch];
60
63
  }
64
+ [self.delegate shouldHandleTouchesNumber:(int)self.touchViews.count];
61
65
  [self.delegate shouldHandleTapsNumber:self.numberOFTaps];
62
66
  }
63
67
 
@@ -67,6 +71,7 @@
67
71
  {
68
72
  [self removeViewForTouch:touch];
69
73
  }
74
+ [self.delegate shouldHandleTouchesNumber:(int)self.touchViews.count];
70
75
  }
71
76
 
72
77
  - (void)createViewForTouch:(UITouch *)touch
@@ -7,6 +7,7 @@
7
7
  */
8
8
 
9
9
  #import "ViewController.h"
10
+ #import "FBCoordinateProbeViewController.h"
10
11
 
11
12
  @interface ViewController ()
12
13
  @property (weak, nonatomic) IBOutlet UILabel *orentationLabel;
@@ -30,6 +31,11 @@
30
31
  self.button.accessibilityCustomActions = @[action1, action2];
31
32
  }
32
33
 
34
+ - (IBAction)showCoordinateProbe:(id)sender
35
+ {
36
+ [self.navigationController pushViewController:[FBCoordinateProbeViewController new] animated:NO];
37
+ }
38
+
33
39
  - (BOOL)handleCustomAction:(UIAccessibilityCustomAction *)action
34
40
  {
35
41
  // Custom action handler - just return YES to indicate success
@@ -57,13 +63,13 @@
57
63
  // lay out. This page exists purely as a fixture for exercising element
58
64
  // lookups (e.g. class chain locators) against a deep accessibility tree.
59
65
  UIViewController *deepHierarchyViewController = [UIViewController new];
60
- deepHierarchyViewController.view.backgroundColor = UIColor.whiteColor;
66
+ deepHierarchyViewController.view.backgroundColor = UIColor.systemBackgroundColor;
61
67
  deepHierarchyViewController.view.accessibilityIdentifier = @"DeepHierarchyPage";
62
68
 
63
69
  NSInteger depth = 70;
64
70
  // A plain UILabel sibling, not part of the nested chain below, so the
65
71
  // fixture stays recognizable to a human glancing at the simulator instead
66
- // of showing a blank white screen.
72
+ // of showing a blank screen.
67
73
  UILabel *titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, 60, CGRectGetWidth(UIScreen.mainScreen.bounds) - 40, 60)];
68
74
  titleLabel.text = [NSString stringWithFormat:@"Deep Hierarchy\n%ld nested elements", (long)depth];
69
75
  titleLabel.numberOfLines = 2;
@@ -30,8 +30,6 @@
30
30
  <string>Yo Yo</string>
31
31
  <key>NSPhotoLibraryUsageDescription</key>
32
32
  <string>Yo Yo</string>
33
- <key>UILaunchStoryboardName</key>
34
- <string>LaunchScreen</string>
35
33
  <key>UIApplicationSceneManifest</key>
36
34
  <dict>
37
35
  <key>UIApplicationSupportsMultipleScenes</key>
@@ -49,6 +47,8 @@
49
47
  </array>
50
48
  </dict>
51
49
  </dict>
50
+ <key>UILaunchStoryboardName</key>
51
+ <string>LaunchScreen</string>
52
52
  <key>UIRequiredDeviceCapabilities</key>
53
53
  <array>
54
54
  <string>armv7</string>
@@ -4,6 +4,7 @@
4
4
  <dependencies>
5
5
  <deployment identifier="iOS"/>
6
6
  <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23721"/>
7
+ <capability name="Safe area layout guides" minToolsVersion="9.0"/>
7
8
  <capability name="System colors in document resources" minToolsVersion="11.0"/>
8
9
  <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
9
10
  </dependencies>
@@ -83,8 +84,19 @@
83
84
  <action selector="goToDeepHierarchy:" destination="BYZ-38-t0r" eventType="touchUpInside" id="dHi-03-Act"/>
84
85
  </connections>
85
86
  </button>
87
+ <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="cPr-01-Btn">
88
+ <rect key="frame" x="139" y="418" width="136" height="30"/>
89
+ <accessibility key="accessibilityConfiguration" identifier="coordinate-probe"/>
90
+ <constraints>
91
+ <constraint firstAttribute="height" constant="30" id="cPr-02-Hgt"/>
92
+ </constraints>
93
+ <state key="normal" title="Coordinate Probe"/>
94
+ <connections>
95
+ <action selector="showCoordinateProbe:" destination="BYZ-38-t0r" eventType="touchUpInside" id="cPr-03-Act"/>
96
+ </connections>
97
+ </button>
86
98
  </subviews>
87
- <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
99
+ <color key="backgroundColor" systemColor="systemBackgroundColor"/>
88
100
  <accessibility key="accessibilityConfiguration" label="MainView"/>
89
101
  <constraints>
90
102
  <constraint firstItem="YgP-SF-TkS" firstAttribute="centerX" secondItem="8bC-Xf-vdC" secondAttribute="centerX" id="41Q-cm-l5K"/>
@@ -101,6 +113,8 @@
101
113
  <constraint firstItem="M2N-Yn-ytb" firstAttribute="top" secondItem="YgP-SF-TkS" secondAttribute="bottom" constant="8" id="tMN-gl-smg"/>
102
114
  <constraint firstItem="dHi-01-Btn" firstAttribute="centerX" secondItem="8bC-Xf-vdC" secondAttribute="centerX" id="dHi-04-Cnt"/>
103
115
  <constraint firstItem="dHi-01-Btn" firstAttribute="top" secondItem="1Ht-AF-MGW" secondAttribute="bottom" constant="8" id="dHi-05-Top"/>
116
+ <constraint firstItem="cPr-01-Btn" firstAttribute="centerX" secondItem="8bC-Xf-vdC" secondAttribute="centerX" id="cPr-04-Cnt"/>
117
+ <constraint firstItem="cPr-01-Btn" firstAttribute="top" secondItem="dHi-01-Btn" secondAttribute="bottom" constant="8" id="cPr-05-Top"/>
104
118
  </constraints>
105
119
  </view>
106
120
  <navigationItem key="navigationItem" id="dmu-Fe-aoT"/>
@@ -129,7 +143,7 @@
129
143
  <color key="backgroundColor" systemColor="systemBackgroundColor"/>
130
144
  <accessibility key="accessibilityConfiguration" identifier="touchableView"/>
131
145
  <constraints>
132
- <constraint firstAttribute="width" secondItem="C6B-Wo-jWm" secondAttribute="height" multiplier="288:269" id="LeW-u7-tWl"/>
146
+ <constraint firstAttribute="width" secondItem="C6B-Wo-jWm" secondAttribute="height" multiplier="288:269" priority="749" id="LeW-u7-tWl"/>
133
147
  </constraints>
134
148
  </view>
135
149
  <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Taps" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="IV8-Ak-Z8e">
@@ -147,17 +161,19 @@
147
161
  <nil key="highlightedColor"/>
148
162
  </label>
149
163
  </subviews>
164
+ <viewLayoutGuide key="safeArea" id="tch-sa-Area"/>
150
165
  <color key="backgroundColor" systemColor="systemBackgroundColor"/>
151
166
  <constraints>
152
- <constraint firstItem="C6B-Wo-jWm" firstAttribute="top" secondItem="gEY-Ha-hqz" secondAttribute="bottom" constant="8" id="1PW-tn-oTF"/>
153
- <constraint firstAttribute="trailing" secondItem="IV8-Ak-Z8e" secondAttribute="trailing" constant="144" id="5Tn-XG-5OD"/>
154
- <constraint firstAttribute="trailing" secondItem="Q4X-EY-aSL" secondAttribute="trailing" constant="130" id="6Rr-L0-eoR"/>
155
- <constraint firstItem="IV8-Ak-Z8e" firstAttribute="firstBaseline" secondItem="C6B-Wo-jWm" secondAttribute="baseline" constant="24.5" symbolType="layoutAnchor" id="77y-Kf-c0Y"/>
156
- <constraint firstAttribute="trailing" secondItem="C6B-Wo-jWm" secondAttribute="trailing" constant="16" id="CaC-dk-dbo"/>
157
- <constraint firstItem="Q4X-EY-aSL" firstAttribute="leading" secondItem="aEY-AK-0k9" secondAttribute="leading" constant="125" id="Ych-oZ-hmA"/>
158
- <constraint firstItem="Q4X-EY-aSL" firstAttribute="top" secondItem="IV8-Ak-Z8e" secondAttribute="bottom" constant="7.5" id="ktv-kW-VWI"/>
159
- <constraint firstItem="C6B-Wo-jWm" firstAttribute="leading" secondItem="aEY-AK-0k9" secondAttribute="leading" constant="16" id="pI7-Ds-hXG"/>
160
- <constraint firstItem="IV8-Ak-Z8e" firstAttribute="leading" secondItem="aEY-AK-0k9" secondAttribute="leading" constant="139" id="vbu-wn-Qvc"/>
167
+ <constraint firstItem="C6B-Wo-jWm" firstAttribute="top" secondItem="tch-sa-Area" secondAttribute="top" constant="8" id="1PW-tn-oTF"/>
168
+ <constraint firstItem="C6B-Wo-jWm" firstAttribute="leading" secondItem="tch-sa-Area" secondAttribute="leading" constant="16" id="pI7-Ds-hXG"/>
169
+ <constraint firstItem="tch-sa-Area" firstAttribute="trailing" secondItem="C6B-Wo-jWm" secondAttribute="trailing" constant="16" id="CaC-dk-dbo"/>
170
+ <constraint firstItem="IV8-Ak-Z8e" firstAttribute="top" secondItem="C6B-Wo-jWm" secondAttribute="bottom" constant="8" id="77y-Kf-c0Y"/>
171
+ <constraint firstItem="IV8-Ak-Z8e" firstAttribute="leading" secondItem="C6B-Wo-jWm" secondAttribute="leading" id="vbu-wn-Qvc"/>
172
+ <constraint firstItem="IV8-Ak-Z8e" firstAttribute="trailing" secondItem="C6B-Wo-jWm" secondAttribute="trailing" id="5Tn-XG-5OD"/>
173
+ <constraint firstItem="Q4X-EY-aSL" firstAttribute="top" secondItem="IV8-Ak-Z8e" secondAttribute="bottom" constant="8" id="ktv-kW-VWI"/>
174
+ <constraint firstItem="Q4X-EY-aSL" firstAttribute="leading" secondItem="C6B-Wo-jWm" secondAttribute="leading" id="Ych-oZ-hmA"/>
175
+ <constraint firstItem="Q4X-EY-aSL" firstAttribute="trailing" secondItem="C6B-Wo-jWm" secondAttribute="trailing" id="6Rr-L0-eoR"/>
176
+ <constraint firstItem="tch-sa-Area" firstAttribute="bottom" relation="greaterThanOrEqual" secondItem="Q4X-EY-aSL" secondAttribute="bottom" constant="8" id="tch-btm-Fit"/>
161
177
  </constraints>
162
178
  </view>
163
179
  <navigationItem key="navigationItem" id="fDl-EC-1lc"/>
@@ -237,7 +253,7 @@
237
253
  <constraint firstAttribute="height" constant="21" id="VBZ-ac-GvI"/>
238
254
  </constraints>
239
255
  <fontDescription key="fontDescription" type="system" pointSize="17"/>
240
- <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
256
+ <color key="textColor" systemColor="labelColor"/>
241
257
  <nil key="highlightedColor"/>
242
258
  </label>
243
259
  <segmentedControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="0" translatesAutoresizingMaskIntoConstraints="NO" id="Wim-fT-xNl">
@@ -282,7 +298,7 @@
282
298
  <constraint firstAttribute="height" constant="21" id="664-Z3-V7W"/>
283
299
  </constraints>
284
300
  <fontDescription key="fontDescription" type="system" pointSize="17"/>
285
- <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
301
+ <color key="textColor" systemColor="labelColor"/>
286
302
  <nil key="highlightedColor"/>
287
303
  </label>
288
304
  <label hidden="YES" opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="hidden_invisible" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="vt6-b1-U0h">
@@ -291,7 +307,7 @@
291
307
  <constraint firstAttribute="height" constant="21" id="51j-sl-XYd"/>
292
308
  </constraints>
293
309
  <fontDescription key="fontDescription" type="system" pointSize="17"/>
294
- <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
310
+ <color key="textColor" systemColor="labelColor"/>
295
311
  <nil key="highlightedColor"/>
296
312
  </label>
297
313
  <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="GsS-jO-scK">
@@ -319,7 +335,7 @@
319
335
  <textInputTraits key="textInputTraits" autocorrectionType="no" spellCheckingType="no"/>
320
336
  </textField>
321
337
  </subviews>
322
- <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
338
+ <color key="backgroundColor" systemColor="systemBackgroundColor"/>
323
339
  <constraints>
324
340
  <constraint firstItem="GsS-jO-scK" firstAttribute="leading" secondItem="Ucg-Ag-VpP" secondAttribute="leadingMargin" constant="154" id="1RA-Fx-3Jh"/>
325
341
  <constraint firstItem="SjL-dx-Zsi" firstAttribute="top" secondItem="U7D-NR-20N" secondAttribute="bottom" constant="8" id="3NW-Hc-tPr"/>
@@ -445,7 +461,7 @@
445
461
  <constraint firstAttribute="height" constant="21" id="2qA-NT-ddc"/>
446
462
  </constraints>
447
463
  <fontDescription key="fontDescription" type="system" pointSize="17"/>
448
- <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
464
+ <color key="textColor" systemColor="labelColor"/>
449
465
  <nil key="highlightedColor"/>
450
466
  </label>
451
467
  <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="3Zk-wE-jwj">
@@ -466,7 +482,7 @@
466
482
  <state key="normal" title="Create Alert (Force Touch)"/>
467
483
  </button>
468
484
  </subviews>
469
- <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
485
+ <color key="backgroundColor" systemColor="systemBackgroundColor"/>
470
486
  <constraints>
471
487
  <constraint firstItem="3Zk-wE-jwj" firstAttribute="centerX" secondItem="JWE-cA-TW0" secondAttribute="centerX" id="83u-1W-xLt"/>
472
488
  <constraint firstItem="D7g-22-s49" firstAttribute="centerX" secondItem="JWE-cA-TW0" secondAttribute="centerX" id="9nT-k0-9gf"/>
@@ -527,7 +543,7 @@
527
543
  </connections>
528
544
  </button>
529
545
  </subviews>
530
- <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
546
+ <color key="backgroundColor" systemColor="systemBackgroundColor"/>
531
547
  <constraints>
532
548
  <constraint firstItem="vYb-QB-vwU" firstAttribute="centerX" secondItem="55R-aH-x4M" secondAttribute="centerX" id="0MT-Eq-8dG"/>
533
549
  <constraint firstItem="vYb-QB-vwU" firstAttribute="top" secondItem="yvD-8P-ibI" secondAttribute="bottom" constant="20" id="c3y-G3-HCj"/>
@@ -548,7 +564,7 @@
548
564
  <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="28" sectionFooterHeight="28" id="jo0-3M-nUd">
549
565
  <rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
550
566
  <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
551
- <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
567
+ <color key="backgroundColor" systemColor="systemBackgroundColor"/>
552
568
  <prototypes>
553
569
  <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="Cell" textLabel="2mC-E2-VxB" style="IBUITableViewCellStyleDefault" id="wCs-18-PFf">
554
570
  <rect key="frame" x="0.0" y="50" width="414" height="44"/>
@@ -561,7 +577,7 @@
561
577
  <rect key="frame" x="20" y="0.0" width="374" height="44"/>
562
578
  <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
563
579
  <fontDescription key="fontDescription" type="system" pointSize="16"/>
564
- <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
580
+ <color key="textColor" systemColor="labelColor"/>
565
581
  <nil key="highlightedColor"/>
566
582
  </label>
567
583
  </subviews>
@@ -603,7 +619,7 @@
603
619
  </userDefinedRuntimeAttributes>
604
620
  </scrollView>
605
621
  </subviews>
606
- <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
622
+ <color key="backgroundColor" systemColor="systemBackgroundColor"/>
607
623
  <constraints>
608
624
  <constraint firstItem="xEQ-MI-a2g" firstAttribute="top" secondItem="KLL-RT-L40" secondAttribute="top" id="Bep-no-nwg"/>
609
625
  <constraint firstAttribute="trailing" secondItem="xEQ-MI-a2g" secondAttribute="trailing" id="akP-zz-jsv"/>
@@ -624,6 +640,9 @@
624
640
  </scene>
625
641
  </scenes>
626
642
  <resources>
643
+ <systemColor name="labelColor">
644
+ <color white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
645
+ </systemColor>
627
646
  <systemColor name="systemBackgroundColor">
628
647
  <color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
629
648
  </systemColor>
@@ -21,14 +21,10 @@
21
21
 
22
22
  @implementation FBConfigurationTests
23
23
 
24
- - (void)setUp
24
+ - (void)testReduceMotion
25
25
  {
26
- [super setUp];
27
26
  [self launchApplication];
28
- }
29
27
 
30
- - (void)testReduceMotion
31
- {
32
28
  BOOL defaultReduceMotionEnabled = FBConfiguration.sharedInstance.reduceMotionEnabled;
33
29
 
34
30
  FBConfiguration.sharedInstance.reduceMotionEnabled = YES;
@@ -44,6 +40,9 @@
44
40
  XCTSkip(@"Deliberately freezes the app for several seconds, too slow/flaky for CI");
45
41
  }
46
42
 
43
+ // Launch only after the CI skip so a skipped test cannot time out in app startup.
44
+ [self launchApplication];
45
+
47
46
  NSTimeInterval previousDeadline = FBConfiguration.sharedInstance.accessibilityDeadline;
48
47
  // Also bounds any snapshot-based wait -tap itself may perform once the app is stuck.
49
48
  FBConfiguration.sharedInstance.accessibilityDeadline = 3.0;
@@ -13,6 +13,7 @@
13
13
  #import "FBTestMacros.h"
14
14
  #import "FBXCodeCompatibility.h"
15
15
  #import "XCUIElement+FBIsVisible.h"
16
+ #import "XCUIElement+FBUtilities.h"
16
17
 
17
18
  @interface FBElementVisibilityTests : FBIntegrationTestCase
18
19
  @end
@@ -26,14 +27,15 @@
26
27
  }
27
28
  [self launchApplication];
28
29
  [self goToSpringBoardFirstPage];
30
+ [self.springboard fb_waitUntilStable];
29
31
 
30
- // Check Icons on first screen
31
- // Note: Calender app exits 2 (an app icon + a widget) exist on the home screen
32
- // on iOS 15+. The firstMatch is for it.
33
- XCTAssertTrue(self.springboard.icons[@"Calendar"].firstMatch.fb_isVisible);
34
- XCTAssertTrue(self.springboard.icons[@"Reminders"].fb_isVisible);
32
+ // Calendar can match both its app icon and a widget on iOS 15+.
33
+ FBAssertWaitTillBecomesTrue(self.springboard.icons[@"Calendar"].firstMatch.fb_isVisible);
34
+ // Safari is in the dock; Reminders is not reliably visible on the first page
35
+ // of CI simulators. Wait for the Home transition before checking visibility.
36
+ FBAssertWaitTillBecomesTrue(self.springboard.icons[@"Safari"].firstMatch.fb_isVisible);
35
37
 
36
- // Check Icons on second screen screen
38
+ // Check the fixture icon on another page.
37
39
  XCTAssertFalse(self.springboard.icons[@"IntegrationApp"].firstMatch.fb_isVisible);
38
40
  }
39
41
 
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Copyright (c) 2015-present, Facebook, Inc.
3
+ * All rights reserved.
4
+ *
5
+ * This source code is licensed under the BSD-style license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ */
8
+
9
+ #import "FBIntegrationTestCase.h"
10
+ #import "FBTestMacros.h"
11
+ #import "XCUIDevice+FBRotation.h"
12
+ #import "XCUIElement+FBUtilities.h"
13
+
14
+ @interface FBIntegrationAppTests : FBIntegrationTestCase
15
+ @end
16
+
17
+ @implementation FBIntegrationAppTests
18
+
19
+ - (void)setUp
20
+ {
21
+ [super setUp];
22
+ [self resetOrientation];
23
+ [self launchApplication];
24
+ }
25
+
26
+ - (void)tearDown
27
+ {
28
+ [self resetOrientation];
29
+ [super tearDown];
30
+ }
31
+
32
+ - (void)rotateTo:(UIDeviceOrientation)orientation
33
+ {
34
+ XCTAssertTrue([[XCUIDevice sharedDevice] fb_setDeviceInterfaceOrientation:orientation]);
35
+ [self.testedApplication fb_waitUntilStable];
36
+ }
37
+
38
+ - (void)testTouchControlsRemainOnScreenAfterRotation
39
+ {
40
+ [self goToTouchPage];
41
+ XCUIElement *canvas = [self.testedApplication descendantsMatchingType:XCUIElementTypeAny][@"touchableView"];
42
+ XCUIElement *taps = self.testedApplication.staticTexts[FBTapsCountLabelIdentifier];
43
+ XCUIElement *touches = self.testedApplication.staticTexts[FBTouchesCountLabelIdentifier];
44
+ NSArray<NSNumber *> *orientations = @[@(UIDeviceOrientationLandscapeLeft),
45
+ @(UIDeviceOrientationLandscapeRight),
46
+ @(UIDeviceOrientationPortrait)];
47
+ NSUInteger count = 0;
48
+ for (NSNumber *orientation in orientations) {
49
+ [self rotateTo:orientation.integerValue];
50
+ CGRect screen = self.testedApplication.frame;
51
+ XCTAssertTrue(CGRectContainsRect(screen, canvas.frame));
52
+ XCTAssertTrue(CGRectContainsRect(screen, taps.frame));
53
+ XCTAssertTrue(CGRectContainsRect(screen, touches.frame));
54
+ XCTAssertGreaterThan(CGRectGetHeight(canvas.frame), 0);
55
+ [canvas tap];
56
+ NSString *expectedTaps = [NSString stringWithFormat:@"%lu", (unsigned long)++count];
57
+ FBAssertWaitTillBecomesTrue([taps.label isEqualToString:expectedTaps]);
58
+ XCTAssertEqualObjects(touches.label, @"0");
59
+ }
60
+ }
61
+
62
+ - (void)testScrollRowsResizeWhenRotatingInBothDirections
63
+ {
64
+ [self rotateTo:UIDeviceOrientationLandscapeLeft];
65
+ [self goToScrollPageWithCells:NO];
66
+ XCUIElement *scroll = self.testedApplication.scrollViews[@"scrollView"];
67
+ XCUIElement *row = scroll.staticTexts[@"3"];
68
+ NSArray<NSNumber *> *orientations = @[@(UIDeviceOrientationPortrait),
69
+ @(UIDeviceOrientationLandscapeRight)];
70
+ for (NSNumber *orientation in orientations) {
71
+ [self rotateTo:orientation.integerValue];
72
+ XCTAssertEqualWithAccuracy(CGRectGetWidth(row.frame), CGRectGetWidth(scroll.frame), 1);
73
+ XCTAssertEqualWithAccuracy(CGRectGetMidX(row.frame), CGRectGetMidX(scroll.frame), 1);
74
+ XCTAssertTrue(row.hittable);
75
+ }
76
+ }
77
+
78
+ @end
@@ -34,6 +34,7 @@ NSArray<NSString *> *const FBMainViewButtonLabels = @[
34
34
  @"Scrolling",
35
35
  @"Touch",
36
36
  @"DeepHierarchy",
37
+ @"Coordinate Probe",
37
38
  ];
38
39
 
39
40
  @interface FBIntegrationTestCase ()
@@ -0,0 +1,121 @@
1
+ /**
2
+ * Copyright (c) 2015-present, Facebook, Inc.
3
+ * All rights reserved.
4
+ *
5
+ * This source code is licensed under the BSD-style license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ */
8
+
9
+ #import <XCTest/XCTest.h>
10
+
11
+ #import "../IntegrationApp/Classes/TouchableView.h"
12
+
13
+ // Only the location and identity are needed to replay UIKit's touch callbacks.
14
+ @interface FBFixtureTouchDouble : NSObject
15
+ @end
16
+
17
+ @implementation FBFixtureTouchDouble
18
+ - (CGPoint)locationInView:(UIView *)view
19
+ {
20
+ return CGPointMake(50, 50);
21
+ }
22
+ @end
23
+
24
+ @interface FBTouchableViewTests : XCTestCase <TouchableViewDelegate>
25
+ @property (nonatomic, strong) TouchableView *touchable;
26
+ @property (nonatomic) int reportedTouches;
27
+ @property (nonatomic) int reportedTaps;
28
+ @end
29
+
30
+ @implementation FBTouchableViewTests
31
+
32
+ - (void)setUp
33
+ {
34
+ [super setUp];
35
+ self.reportedTouches = 0;
36
+ self.reportedTaps = 0;
37
+ self.touchable = [[TouchableView alloc] initWithFrame:CGRectMake(0, 0, 200, 200)];
38
+ self.touchable.delegate = self;
39
+ }
40
+
41
+ - (void)tearDown
42
+ {
43
+ self.touchable.delegate = nil;
44
+ self.touchable = nil;
45
+ [super tearDown];
46
+ }
47
+
48
+ - (void)shouldHandleTouchesNumber:(int)touchesCount
49
+ {
50
+ self.reportedTouches = touchesCount;
51
+ }
52
+
53
+ - (void)shouldHandleTapsNumber:(int)numberOfTaps
54
+ {
55
+ self.reportedTaps = numberOfTaps;
56
+ }
57
+
58
+ - (UITouch *)newTouch
59
+ {
60
+ return (UITouch *)[FBFixtureTouchDouble new];
61
+ }
62
+
63
+ - (void)testStaggeredTouchesTrackActiveFingers
64
+ {
65
+ NSSet *first = [NSSet setWithObject:[self newTouch]];
66
+ NSSet *second = [NSSet setWithObject:[self newTouch]];
67
+ [self.touchable touchesBegan:first withEvent:nil];
68
+ XCTAssertEqual(self.reportedTouches, 1);
69
+ [self.touchable touchesBegan:second withEvent:nil];
70
+ XCTAssertEqual(self.reportedTouches, 2);
71
+ XCTAssertEqual(self.reportedTaps, 0);
72
+
73
+ [self.touchable touchesEnded:first withEvent:nil];
74
+ XCTAssertEqual(self.reportedTouches, 1);
75
+ XCTAssertEqual(self.reportedTaps, 1);
76
+ [self.touchable touchesEnded:second withEvent:nil];
77
+ XCTAssertEqual(self.reportedTouches, 0);
78
+ XCTAssertEqual(self.reportedTaps, 2);
79
+ }
80
+
81
+ - (void)testSimultaneousContactsCountIndependentlyOfCallbackBatching
82
+ {
83
+ NSSet *touches = [NSSet setWithObjects:[self newTouch], [self newTouch], nil];
84
+ [self.touchable touchesBegan:touches withEvent:nil];
85
+ XCTAssertEqual(self.reportedTouches, 2);
86
+ [self.touchable touchesEnded:touches withEvent:nil];
87
+ XCTAssertEqual(self.reportedTouches, 0);
88
+ XCTAssertEqual(self.reportedTaps, 2);
89
+ }
90
+
91
+ - (void)testCancelledContactsDoNotCarryOverIntoNextTap
92
+ {
93
+ NSSet *first = [NSSet setWithObject:[self newTouch]];
94
+ NSSet *second = [NSSet setWithObject:[self newTouch]];
95
+ [self.touchable touchesBegan:first withEvent:nil];
96
+ [self.touchable touchesBegan:second withEvent:nil];
97
+ [self.touchable touchesCancelled:[first setByAddingObjectsFromSet:second] withEvent:nil];
98
+ XCTAssertEqual(self.reportedTouches, 0);
99
+ XCTAssertEqual(self.reportedTaps, 0);
100
+
101
+ NSSet *next = [NSSet setWithObject:[self newTouch]];
102
+ [self.touchable touchesBegan:next withEvent:nil];
103
+ [self.touchable touchesEnded:next withEvent:nil];
104
+ XCTAssertEqual(self.reportedTouches, 0);
105
+ XCTAssertEqual(self.reportedTaps, 1);
106
+ }
107
+
108
+ - (void)testCancellingOneFingerPreservesTheOtherContact
109
+ {
110
+ NSSet *first = [NSSet setWithObject:[self newTouch]];
111
+ NSSet *second = [NSSet setWithObject:[self newTouch]];
112
+ [self.touchable touchesBegan:[first setByAddingObjectsFromSet:second] withEvent:nil];
113
+ [self.touchable touchesCancelled:first withEvent:nil];
114
+ XCTAssertEqual(self.reportedTouches, 1);
115
+ XCTAssertEqual(self.reportedTaps, 0);
116
+ [self.touchable touchesEnded:second withEvent:nil];
117
+ XCTAssertEqual(self.reportedTouches, 0);
118
+ XCTAssertEqual(self.reportedTaps, 1);
119
+ }
120
+
121
+ @end
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "appium-webdriveragent",
3
- "version": "16.12.3",
3
+ "version": "16.12.5",
4
4
  "description": "Package bundling WebDriverAgent",
5
5
  "keywords": [
6
6
  "Appium",