Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
dfd4147c
Unverified
Commit
dfd4147c
authored
Aug 28, 2023
by
Justin McCandless
Committed by
GitHub
Aug 28, 2023
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Fix stuck predictive back platform channel calls (#133368)
Fix a Google test flakiness increase.
parent
69f61a28
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
117 additions
and
23 deletions
+117
-23
app.dart
packages/flutter/lib/src/widgets/app.dart
+12
-5
tab_scaffold_test.dart
packages/flutter/test/cupertino/tab_scaffold_test.dart
+7
-6
app_test.dart
packages/flutter/test/widgets/app_test.dart
+84
-0
navigator_test.dart
packages/flutter/test/widgets/navigator_test.dart
+7
-6
pop_scope_test.dart
packages/flutter/test/widgets/pop_scope_test.dart
+7
-6
No files found.
packages/flutter/lib/src/widgets/app.dart
View file @
dfd4147c
...
@@ -1346,12 +1346,18 @@ class _WidgetsAppState extends State<WidgetsApp> with WidgetsBindingObserver {
...
@@ -1346,12 +1346,18 @@ class _WidgetsAppState extends State<WidgetsApp> with WidgetsBindingObserver {
/// the platform with [NavigationNotification.canHandlePop] and stops
/// the platform with [NavigationNotification.canHandlePop] and stops
/// bubbling.
/// bubbling.
bool
_defaultOnNavigationNotification
(
NavigationNotification
notification
)
{
bool
_defaultOnNavigationNotification
(
NavigationNotification
notification
)
{
// Don't do anything with navigation notifications if there is no engine
switch
(
_appLifecycleState
)
{
// attached.
case
null
:
if
(
_appLifecycleState
!=
AppLifecycleState
.
detached
)
{
case
AppLifecycleState
.
detached
:
SystemNavigator
.
setFrameworkHandlesBack
(
notification
.
canHandlePop
);
case
AppLifecycleState
.
inactive
:
// Avoid updating the engine when the app isn't ready.
return
true
;
case
AppLifecycleState
.
resumed
:
case
AppLifecycleState
.
hidden
:
case
AppLifecycleState
.
paused
:
SystemNavigator
.
setFrameworkHandlesBack
(
notification
.
canHandlePop
);
return
true
;
}
}
return
true
;
}
}
@override
@override
...
@@ -1366,6 +1372,7 @@ class _WidgetsAppState extends State<WidgetsApp> with WidgetsBindingObserver {
...
@@ -1366,6 +1372,7 @@ class _WidgetsAppState extends State<WidgetsApp> with WidgetsBindingObserver {
_updateRouting
();
_updateRouting
();
_locale
=
_resolveLocales
(
WidgetsBinding
.
instance
.
platformDispatcher
.
locales
,
widget
.
supportedLocales
);
_locale
=
_resolveLocales
(
WidgetsBinding
.
instance
.
platformDispatcher
.
locales
,
widget
.
supportedLocales
);
WidgetsBinding
.
instance
.
addObserver
(
this
);
WidgetsBinding
.
instance
.
addObserver
(
this
);
_appLifecycleState
=
WidgetsBinding
.
instance
.
lifecycleState
;
}
}
@override
@override
...
...
packages/flutter/test/cupertino/tab_scaffold_test.dart
View file @
dfd4147c
...
@@ -1219,11 +1219,7 @@ void main() {
...
@@ -1219,11 +1219,7 @@ void main() {
group
(
'Android Predictive Back'
,
()
{
group
(
'Android Predictive Back'
,
()
{
bool
?
lastFrameworkHandlesBack
;
bool
?
lastFrameworkHandlesBack
;
setUp
(()
{
setUp
(()
async
{
// Initialize to false. Because this uses a static boolean internally, it
// is not reset between tests or calls to pumpWidget. Explicitly setting
// it to false before each test makes them behave deterministically.
SystemNavigator
.
setFrameworkHandlesBack
(
false
);
lastFrameworkHandlesBack
=
null
;
lastFrameworkHandlesBack
=
null
;
TestDefaultBinaryMessengerBinding
.
instance
.
defaultBinaryMessenger
TestDefaultBinaryMessengerBinding
.
instance
.
defaultBinaryMessenger
.
setMockMethodCallHandler
(
SystemChannels
.
platform
,
(
MethodCall
methodCall
)
async
{
.
setMockMethodCallHandler
(
SystemChannels
.
platform
,
(
MethodCall
methodCall
)
async
{
...
@@ -1233,12 +1229,17 @@ void main() {
...
@@ -1233,12 +1229,17 @@ void main() {
}
}
return
;
return
;
});
});
await
TestDefaultBinaryMessengerBinding
.
instance
.
defaultBinaryMessenger
.
handlePlatformMessage
(
'flutter/lifecycle'
,
const
StringCodec
().
encodeMessage
(
AppLifecycleState
.
resumed
.
toString
()),
(
ByteData
?
data
)
{},
);
});
});
tearDown
(()
{
tearDown
(()
{
TestDefaultBinaryMessengerBinding
.
instance
.
defaultBinaryMessenger
TestDefaultBinaryMessengerBinding
.
instance
.
defaultBinaryMessenger
.
setMockMethodCallHandler
(
SystemChannels
.
platform
,
null
);
.
setMockMethodCallHandler
(
SystemChannels
.
platform
,
null
);
SystemNavigator
.
setFrameworkHandlesBack
(
true
);
});
});
testWidgets
(
'System back navigation inside of tabs'
,
(
WidgetTester
tester
)
async
{
testWidgets
(
'System back navigation inside of tabs'
,
(
WidgetTester
tester
)
async
{
...
...
packages/flutter/test/widgets/app_test.dart
View file @
dfd4147c
...
@@ -683,6 +683,90 @@ void main() {
...
@@ -683,6 +683,90 @@ void main() {
expect
(
copySpy
.
invoked
,
isTrue
);
expect
(
copySpy
.
invoked
,
isTrue
);
expect
(
pasteSpy
.
invoked
,
isTrue
);
expect
(
pasteSpy
.
invoked
,
isTrue
);
},
variant:
const
TargetPlatformVariant
(<
TargetPlatform
>{
TargetPlatform
.
iOS
,
TargetPlatform
.
macOS
}));
},
variant:
const
TargetPlatformVariant
(<
TargetPlatform
>{
TargetPlatform
.
iOS
,
TargetPlatform
.
macOS
}));
group
(
'Android Predictive Back'
,
()
{
Future
<
void
>
setAppLifeCycleState
(
AppLifecycleState
state
)
async
{
final
ByteData
?
message
=
const
StringCodec
().
encodeMessage
(
state
.
toString
());
await
TestDefaultBinaryMessengerBinding
.
instance
.
defaultBinaryMessenger
.
handlePlatformMessage
(
'flutter/lifecycle'
,
message
,
(
ByteData
?
data
)
{});
}
final
List
<
bool
>
frameworkHandlesBacks
=
<
bool
>[];
setUp
(()
async
{
frameworkHandlesBacks
.
clear
();
TestDefaultBinaryMessengerBinding
.
instance
.
defaultBinaryMessenger
.
setMockMethodCallHandler
(
SystemChannels
.
platform
,
(
MethodCall
methodCall
)
async
{
if
(
methodCall
.
method
==
'SystemNavigator.setFrameworkHandlesBack'
)
{
expect
(
methodCall
.
arguments
,
isA
<
bool
>());
frameworkHandlesBacks
.
add
(
methodCall
.
arguments
as
bool
);
}
return
;
});
});
tearDown
(()
async
{
TestDefaultBinaryMessengerBinding
.
instance
.
defaultBinaryMessenger
.
setMockMethodCallHandler
(
SystemChannels
.
platform
,
null
);
await
setAppLifeCycleState
(
AppLifecycleState
.
resumed
);
});
testWidgets
(
'WidgetsApp calls setFrameworkHandlesBack only when app is ready'
,
(
WidgetTester
tester
)
async
{
// Start in the `resumed` state, where setFrameworkHandlesBack should be
// called like normal.
await
setAppLifeCycleState
(
AppLifecycleState
.
resumed
);
late
BuildContext
currentContext
;
await
tester
.
pumpWidget
(
WidgetsApp
(
color:
const
Color
(
0xFF123456
),
builder:
(
BuildContext
context
,
Widget
?
child
)
{
currentContext
=
context
;
return
const
Placeholder
();
},
),
);
expect
(
frameworkHandlesBacks
,
isEmpty
);
const
NavigationNotification
(
canHandlePop:
true
).
dispatch
(
currentContext
);
await
tester
.
pumpAndSettle
();
expect
(
frameworkHandlesBacks
,
isNotEmpty
);
expect
(
frameworkHandlesBacks
.
last
,
isTrue
);
const
NavigationNotification
(
canHandlePop:
false
).
dispatch
(
currentContext
);
await
tester
.
pumpAndSettle
();
expect
(
frameworkHandlesBacks
.
last
,
isFalse
);
// Set the app state to inactive, where setFrameworkHandlesBack shouldn't
// be called.
await
setAppLifeCycleState
(
AppLifecycleState
.
inactive
);
final
int
finalCallsLength
=
frameworkHandlesBacks
.
length
;
const
NavigationNotification
(
canHandlePop:
true
).
dispatch
(
currentContext
);
await
tester
.
pumpAndSettle
();
expect
(
frameworkHandlesBacks
,
hasLength
(
finalCallsLength
));
const
NavigationNotification
(
canHandlePop:
false
).
dispatch
(
currentContext
);
await
tester
.
pumpAndSettle
();
expect
(
frameworkHandlesBacks
,
hasLength
(
finalCallsLength
));
// Set the app state to detached, which also shouldn't call
// setFrameworkHandlesBack. Must go to paused, then detached.
await
setAppLifeCycleState
(
AppLifecycleState
.
paused
);
await
setAppLifeCycleState
(
AppLifecycleState
.
detached
);
const
NavigationNotification
(
canHandlePop:
true
).
dispatch
(
currentContext
);
await
tester
.
pumpAndSettle
();
expect
(
frameworkHandlesBacks
,
hasLength
(
finalCallsLength
));
const
NavigationNotification
(
canHandlePop:
false
).
dispatch
(
currentContext
);
await
tester
.
pumpAndSettle
();
expect
(
frameworkHandlesBacks
,
hasLength
(
finalCallsLength
));
},
skip:
kIsWeb
,
// [intended] predictive back is only native Android.
variant:
const
TargetPlatformVariant
(<
TargetPlatform
>{
TargetPlatform
.
android
})
);
});
}
}
typedef
SimpleRouterDelegateBuilder
=
Widget
Function
(
BuildContext
,
RouteInformation
);
typedef
SimpleRouterDelegateBuilder
=
Widget
Function
(
BuildContext
,
RouteInformation
);
...
...
packages/flutter/test/widgets/navigator_test.dart
View file @
dfd4147c
...
@@ -4159,11 +4159,7 @@ void main() {
...
@@ -4159,11 +4159,7 @@ void main() {
group
(
'Android Predictive Back'
,
()
{
group
(
'Android Predictive Back'
,
()
{
bool
?
lastFrameworkHandlesBack
;
bool
?
lastFrameworkHandlesBack
;
setUp
(()
{
setUp
(()
async
{
// Initialize to false. Because this uses a static boolean internally, it
// is not reset between tests or calls to pumpWidget. Explicitly setting
// it to false before each test makes them behave deterministically.
SystemNavigator
.
setFrameworkHandlesBack
(
false
);
lastFrameworkHandlesBack
=
null
;
lastFrameworkHandlesBack
=
null
;
TestDefaultBinaryMessengerBinding
.
instance
.
defaultBinaryMessenger
TestDefaultBinaryMessengerBinding
.
instance
.
defaultBinaryMessenger
.
setMockMethodCallHandler
(
SystemChannels
.
platform
,
(
MethodCall
methodCall
)
async
{
.
setMockMethodCallHandler
(
SystemChannels
.
platform
,
(
MethodCall
methodCall
)
async
{
...
@@ -4173,12 +4169,17 @@ void main() {
...
@@ -4173,12 +4169,17 @@ void main() {
}
}
return
;
return
;
});
});
await
TestDefaultBinaryMessengerBinding
.
instance
.
defaultBinaryMessenger
.
handlePlatformMessage
(
'flutter/lifecycle'
,
const
StringCodec
().
encodeMessage
(
AppLifecycleState
.
resumed
.
toString
()),
(
ByteData
?
data
)
{},
);
});
});
tearDown
(()
{
tearDown
(()
{
TestDefaultBinaryMessengerBinding
.
instance
.
defaultBinaryMessenger
TestDefaultBinaryMessengerBinding
.
instance
.
defaultBinaryMessenger
.
setMockMethodCallHandler
(
SystemChannels
.
platform
,
null
);
.
setMockMethodCallHandler
(
SystemChannels
.
platform
,
null
);
SystemNavigator
.
setFrameworkHandlesBack
(
true
);
});
});
testWidgets
(
'a single route is already defaulted to false'
,
(
WidgetTester
tester
)
async
{
testWidgets
(
'a single route is already defaulted to false'
,
(
WidgetTester
tester
)
async
{
...
...
packages/flutter/test/widgets/pop_scope_test.dart
View file @
dfd4147c
...
@@ -11,11 +11,7 @@ import 'navigator_utils.dart';
...
@@ -11,11 +11,7 @@ import 'navigator_utils.dart';
void
main
(
)
{
void
main
(
)
{
bool
?
lastFrameworkHandlesBack
;
bool
?
lastFrameworkHandlesBack
;
setUp
(()
{
setUp
(()
async
{
// Initialize to false. Because this uses a static boolean internally, it
// is not reset between tests or calls to pumpWidget. Explicitly setting
// it to false before each test makes them behave deterministically.
SystemNavigator
.
setFrameworkHandlesBack
(
false
);
lastFrameworkHandlesBack
=
null
;
lastFrameworkHandlesBack
=
null
;
TestDefaultBinaryMessengerBinding
.
instance
.
defaultBinaryMessenger
TestDefaultBinaryMessengerBinding
.
instance
.
defaultBinaryMessenger
.
setMockMethodCallHandler
(
SystemChannels
.
platform
,
(
MethodCall
methodCall
)
async
{
.
setMockMethodCallHandler
(
SystemChannels
.
platform
,
(
MethodCall
methodCall
)
async
{
...
@@ -25,12 +21,17 @@ void main() {
...
@@ -25,12 +21,17 @@ void main() {
}
}
return
;
return
;
});
});
await
TestDefaultBinaryMessengerBinding
.
instance
.
defaultBinaryMessenger
.
handlePlatformMessage
(
'flutter/lifecycle'
,
const
StringCodec
().
encodeMessage
(
AppLifecycleState
.
resumed
.
toString
()),
(
ByteData
?
data
)
{},
);
});
});
tearDown
(()
{
tearDown
(()
{
TestDefaultBinaryMessengerBinding
.
instance
.
defaultBinaryMessenger
TestDefaultBinaryMessengerBinding
.
instance
.
defaultBinaryMessenger
.
setMockMethodCallHandler
(
SystemChannels
.
platform
,
null
);
.
setMockMethodCallHandler
(
SystemChannels
.
platform
,
null
);
SystemNavigator
.
setFrameworkHandlesBack
(
true
);
});
});
testWidgets
(
'toggling canPop on root route allows/prevents backs'
,
(
WidgetTester
tester
)
async
{
testWidgets
(
'toggling canPop on root route allows/prevents backs'
,
(
WidgetTester
tester
)
async
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment