| Flutter iOS Embedder |

VsyncWaiterIosTest.mm
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #import <OCMock/OCMock.h>
6 #import <XCTest/XCTest.h>
7
8 #include "flutter/fml/raster_thread_merger.h"
9 #include "flutter/fml/thread.h"
10
11 #import "flutter/shell/platform/darwin/common/framework/Headers/FlutterMacros.h"
12 #import "flutter/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.h"
13
14 FLUTTER_ASSERT_ARC
15 namespace {
16 fml::RefPtr<fml::TaskRunner> CreateNewThread(const std::string& name) {
17 auto thread = std::make_unique<fml::Thread>(name);
18 auto runner = thread->GetTaskRunner();
19 return runner;
20 }
21 } // namespace
22
23 @interface VSyncClient (Testing)
24
25 - (CADisplayLink*)getDisplayLink;
26 - (void)onDisplayLink:(CADisplayLink*)link;
27
28 @end
29
30 @interface VsyncWaiterIosTest : XCTestCase
31 @end
32
33 @implementation VsyncWaiterIosTest
34
35 - (void)testSetAllowPauseAfterVsyncCorrect {
36 auto thread_task_runner = CreateNewThread("VsyncWaiterIosTest");
37 VSyncClient* vsyncClient = [[VSyncClient alloc]
38 initWithTaskRunner:thread_task_runner
39 callback:[](std::unique_ptr<flutter::FrameTimingsRecorder> recorder) {}];
40 CADisplayLink* link = [vsyncClient getDisplayLink];
41 vsyncClient.allowPauseAfterVsync = NO;
42 [vsyncClient await];
43 [vsyncClient onDisplayLink:link];
44 XCTAssertFalse(link.isPaused);
45
46 vsyncClient.allowPauseAfterVsync = YES;
47 [vsyncClient await];
48 [vsyncClient onDisplayLink:link];
49 XCTAssertTrue(link.isPaused);
50 }
51
52 - (void)testSetCorrectVariableRefreshRates {
53 auto thread_task_runner = CreateNewThread("VsyncWaiterIosTest");
54 auto callback = [](std::unique_ptr<flutter::FrameTimingsRecorder> recorder) {};
55 id bundleMock = OCMPartialMock([NSBundle mainBundle]);
56 OCMStub([bundleMock objectForInfoDictionaryKey:kCADisableMinimumFrameDurationOnPhoneKey])
57 .andReturn(@YES);
58 id mockDisplayLinkManager = [OCMockObject mockForClass:[DisplayLinkManager class]];
59 double maxFrameRate = 120;
60 [[[mockDisplayLinkManager stub] andReturnValue:@(maxFrameRate)] displayRefreshRate];
61
62 VSyncClient* vsyncClient = [[VSyncClient alloc] initWithTaskRunner:thread_task_runner
63 callback:callback];
64 CADisplayLink* link = [vsyncClient getDisplayLink];
65 if (@available(iOS 15.0, *)) {
66 XCTAssertEqualWithAccuracy(link.preferredFrameRateRange.maximum, maxFrameRate, 0.1);
67 XCTAssertEqualWithAccuracy(link.preferredFrameRateRange.preferred, maxFrameRate, 0.1);
68 XCTAssertEqualWithAccuracy(link.preferredFrameRateRange.minimum, maxFrameRate / 2, 0.1);
69 } else {
70 XCTAssertEqualWithAccuracy(link.preferredFramesPerSecond, maxFrameRate, 0.1);
71 }
72 }
73
74 - (void)testDoNotSetVariableRefreshRatesIfCADisableMinimumFrameDurationOnPhoneIsNotOn {
75 auto thread_task_runner = CreateNewThread("VsyncWaiterIosTest");
76 auto callback = [](std::unique_ptr<flutter::FrameTimingsRecorder> recorder) {};
77 id bundleMock = OCMPartialMock([NSBundle mainBundle]);
78 OCMStub([bundleMock objectForInfoDictionaryKey:kCADisableMinimumFrameDurationOnPhoneKey])
79 .andReturn(@NO);
80 id mockDisplayLinkManager = [OCMockObject mockForClass:[DisplayLinkManager class]];
81 double maxFrameRate = 120;
82 [[[mockDisplayLinkManager stub] andReturnValue:@(maxFrameRate)] displayRefreshRate];
83
84 VSyncClient* vsyncClient = [[VSyncClient alloc] initWithTaskRunner:thread_task_runner
85 callback:callback];
86 CADisplayLink* link = [vsyncClient getDisplayLink];
87 if (@available(iOS 15.0, *)) {
88 XCTAssertEqualWithAccuracy(link.preferredFrameRateRange.maximum, 0, 0.1);
89 XCTAssertEqualWithAccuracy(link.preferredFrameRateRange.preferred, 0, 0.1);
90 XCTAssertEqualWithAccuracy(link.preferredFrameRateRange.minimum, 0, 0.1);
91 } else {
92 XCTAssertEqualWithAccuracy(link.preferredFramesPerSecond, 0, 0.1);
93 }
94 }
95
96 - (void)testDoNotSetVariableRefreshRatesIfCADisableMinimumFrameDurationOnPhoneIsNotSet {
97 auto thread_task_runner = CreateNewThread("VsyncWaiterIosTest");
98 auto callback = [](std::unique_ptr<flutter::FrameTimingsRecorder> recorder) {};
99 id mockDisplayLinkManager = [OCMockObject mockForClass:[DisplayLinkManager class]];
100 double maxFrameRate = 120;
101 [[[mockDisplayLinkManager stub] andReturnValue:@(maxFrameRate)] displayRefreshRate];
102 VSyncClient* vsyncClient = [[VSyncClient alloc] initWithTaskRunner:thread_task_runner
103 callback:callback];
104 CADisplayLink* link = [vsyncClient getDisplayLink];
105 if (@available(iOS 15.0, *)) {
106 XCTAssertEqualWithAccuracy(link.preferredFrameRateRange.maximum, 0, 0.1);
107 XCTAssertEqualWithAccuracy(link.preferredFrameRateRange.preferred, 0, 0.1);
108 XCTAssertEqualWithAccuracy(link.preferredFrameRateRange.minimum, 0, 0.1);
109 } else {
110 XCTAssertEqualWithAccuracy(link.preferredFramesPerSecond, 0, 0.1);
111 }
112 }
113
114 - (void)testAwaitAndPauseWillWorkCorrectly {
115 auto thread_task_runner = CreateNewThread("VsyncWaiterIosTest");
116 VSyncClient* vsyncClient = [[VSyncClient alloc]
117 initWithTaskRunner:thread_task_runner
118 callback:[](std::unique_ptr<flutter::FrameTimingsRecorder> recorder) {}];
119
120 CADisplayLink* link = [vsyncClient getDisplayLink];
121 XCTAssertTrue(link.isPaused);
122
123 [vsyncClient await];
124 XCTAssertFalse(link.isPaused);
125
126 [vsyncClient pause];
127 XCTAssertTrue(link.isPaused);
128 }
129
130 - (void)testReleasesLinkOnInvalidation {
131 __weak CADisplayLink* weakLink;
132 @autoreleasepool {
133 auto thread_task_runner = CreateNewThread("VsyncWaiterIosTest");
134 VSyncClient* vsyncClient = [[VSyncClient alloc]
135 initWithTaskRunner:thread_task_runner
136 callback:[](std::unique_ptr<flutter::FrameTimingsRecorder> recorder) {}];
137
138 weakLink = [vsyncClient getDisplayLink];
139 XCTAssertNotNil(weakLink);
140 [vsyncClient invalidate];
141 }
142 // VSyncClient has released the CADisplayLink.
143 XCTAssertNil(weakLink);
144 }
145
146 @end
FlutterMacros.h
VSyncClient(Testing)
Definition: FlutterViewControllerTest.mm:192
-[VSyncClient(Testing) getDisplayLink]
CADisplayLink * getDisplayLink()
DisplayLinkManager
Definition: FlutterMetalLayer.mm:18
VSyncClient
Definition: vsync_waiter_ios.h:48
-[VSyncClient await]
void await()
Definition: vsync_waiter_ios.mm:108
-[VSyncClient pause]
void pause()
Definition: vsync_waiter_ios.mm:112
VSyncClient::allowPauseAfterVsync
BOOL allowPauseAfterVsync
Default value is YES. Vsync client will pause vsync callback after receiving a vsync signal....
Definition: vsync_waiter_ios.h:57
-[VSyncClient invalidate]
void invalidate()
Call invalidate before releasing this object to remove from runloops.
Definition: vsync_waiter_ios.mm:139
VsyncWaiterIosTest
Definition: VsyncWaiterIosTest.mm:31
FLUTTER_ASSERT_ARC
Definition: FlutterChannelKeyResponder.mm:13
FLUTTER_ASSERT_ARC::CreateNewThread
fml::RefPtr< fml::TaskRunner > CreateNewThread(const std::string &name)
Definition: VsyncWaiterIosTest.mm:16
vsync_waiter_ios.h
kCADisableMinimumFrameDurationOnPhoneKey
NSString *const kCADisableMinimumFrameDurationOnPhoneKey
Info.plist key enabling the full range of ProMotion refresh rates for CADisplayLink callbacks and CAA...
Definition: vsync_waiter_ios.mm:21