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
ab23233f
Unverified
Commit
ab23233f
authored
Aug 12, 2022
by
stuartmorgan
Committed by
GitHub
Aug 12, 2022
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Reland: Fix Android platform view creation flow (#109405)
parent
b79c2168
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
183 additions
and
40 deletions
+183
-40
platform_view.dart
packages/flutter/lib/src/rendering/platform_view.dart
+3
-11
platform_views.dart
packages/flutter/lib/src/services/platform_views.dart
+52
-22
platform_view.dart
packages/flutter/lib/src/widgets/platform_view.dart
+10
-4
fake_platform_views.dart
packages/flutter/test/services/fake_platform_views.dart
+13
-2
platform_view_test.dart
packages/flutter/test/widgets/platform_view_test.dart
+105
-1
No files found.
packages/flutter/lib/src/rendering/platform_view.dart
View file @
ab23233f
...
...
@@ -179,17 +179,9 @@ class RenderAndroidView extends PlatformViewRenderBox {
Size
targetSize
;
do
{
targetSize
=
size
;
if
(
_viewController
.
isCreated
)
{
_currentTextureSize
=
await
_viewController
.
setSize
(
targetSize
);
if
(
_isDisposed
)
{
return
;
}
}
else
{
await
_viewController
.
create
(
size:
targetSize
);
if
(
_isDisposed
)
{
return
;
}
_currentTextureSize
=
targetSize
;
_currentTextureSize
=
await
_viewController
.
setSize
(
targetSize
);
if
(
_isDisposed
)
{
return
;
}
// We've resized the platform view to targetSize, but it is possible that
// while we were resizing the render object's size was changed again.
...
...
packages/flutter/lib/src/services/platform_views.dart
View file @
ab23233f
...
...
@@ -763,16 +763,35 @@ abstract class AndroidViewController extends PlatformViewController {
/// Sends the message to dispose the platform view.
Future
<
void
>
_sendDisposeMessage
();
/// True if [_sendCreateMessage] can only be called with a non-null size.
bool
get
_createRequiresSize
;
/// Sends the message to create the platform view with an initial [size].
Future
<
void
>
_sendCreateMessage
({
Size
?
size
});
///
/// If [_createRequiresSize] is true, `size` is non-nullable, and the call
/// should instead be deferred until the size is available.
Future
<
void
>
_sendCreateMessage
({
required
covariant
Size
?
size
});
/// Sends the message to resize the platform view to [size].
Future
<
Size
>
_sendResizeMessage
(
Size
size
);
@override
bool
get
awaitingCreation
=>
_state
==
_AndroidViewState
.
waitingForSize
;
@override
Future
<
void
>
create
({
Size
?
size
})
async
{
assert
(
_state
!=
_AndroidViewState
.
disposed
,
'trying to create a disposed Android view'
);
assert
(
_state
==
_AndroidViewState
.
waitingForSize
,
'Android view is already sized. View id:
$viewId
'
);
await
_sendCreateMessage
(
size:
size
);
if
(
_createRequiresSize
&&
size
==
null
)
{
// Wait for a setSize call.
return
;
}
_state
=
_AndroidViewState
.
creating
;
await
_sendCreateMessage
(
size:
size
);
_state
=
_AndroidViewState
.
created
;
for
(
final
PlatformViewCreatedCallback
callback
in
_platformViewCreatedCallbacks
)
{
callback
(
viewId
);
}
...
...
@@ -792,7 +811,17 @@ abstract class AndroidViewController extends PlatformViewController {
///
/// As a result, consumers are expected to clip the texture using [size], while using
/// the return value to size the texture.
Future
<
Size
>
setSize
(
Size
size
);
Future
<
Size
>
setSize
(
Size
size
)
async
{
assert
(
_state
!=
_AndroidViewState
.
disposed
,
'Android view is disposed. View id:
$viewId
'
);
if
(
_state
==
_AndroidViewState
.
waitingForSize
)
{
// Either `create` hasn't been called, or it couldn't run due to missing
// size information, so create the view now.
await
create
(
size:
size
);
return
size
;
}
else
{
return
_sendResizeMessage
(
size
);
}
}
/// Sets the offset of the platform view.
///
...
...
@@ -972,7 +1001,10 @@ class ExpensiveAndroidViewController extends AndroidViewController {
})
:
super
.
_
();
@override
Future
<
void
>
_sendCreateMessage
({
Size
?
size
})
{
bool
get
_createRequiresSize
=>
false
;
@override
Future
<
void
>
_sendCreateMessage
({
required
Size
?
size
})
async
{
final
Map
<
String
,
dynamic
>
args
=
<
String
,
dynamic
>{
'id'
:
viewId
,
'viewType'
:
_viewType
,
...
...
@@ -988,7 +1020,7 @@ class ExpensiveAndroidViewController extends AndroidViewController {
paramsByteData
.
lengthInBytes
,
);
}
return
SystemChannels
.
platform_views
.
invokeMethod
<
void
>(
'create'
,
args
);
await
SystemChannels
.
platform_views
.
invokeMethod
<
void
>(
'create'
,
args
);
}
@override
...
...
@@ -1005,7 +1037,7 @@ class ExpensiveAndroidViewController extends AndroidViewController {
}
@override
Future
<
Size
>
setSiz
e
(
Size
size
)
{
Future
<
Size
>
_sendResizeMessag
e
(
Size
size
)
{
throw
UnimplementedError
(
'Not supported for
$SurfaceAndroidViewController
.'
);
}
...
...
@@ -1044,8 +1076,7 @@ class TextureAndroidViewController extends AndroidViewController {
Offset
_off
=
Offset
.
zero
;
@override
Future
<
Size
>
setSize
(
Size
size
)
async
{
assert
(
_state
!=
_AndroidViewState
.
disposed
,
'Android view is disposed. View id:
$viewId
'
);
Future
<
Size
>
_sendResizeMessage
(
Size
size
)
async
{
assert
(
_state
!=
_AndroidViewState
.
waitingForSize
,
'Android view must have an initial size. View id:
$viewId
'
);
assert
(
size
!=
null
);
assert
(!
size
.
isEmpty
);
...
...
@@ -1064,16 +1095,6 @@ class TextureAndroidViewController extends AndroidViewController {
return
Size
(
meta
![
'width'
]!
as
double
,
meta
[
'height'
]!
as
double
);
}
@override
Future
<
void
>
create
({
Size
?
size
})
async
{
if
(
size
==
null
)
{
return
;
}
assert
(
_state
==
_AndroidViewState
.
waitingForSize
,
'Android view is already sized. View id:
$viewId
'
);
assert
(!
size
.
isEmpty
);
return
super
.
create
(
size:
size
);
}
@override
Future
<
void
>
setOffset
(
Offset
off
)
async
{
if
(
off
==
_off
)
{
...
...
@@ -1100,11 +1121,11 @@ class TextureAndroidViewController extends AndroidViewController {
}
@override
Future
<
void
>
_sendCreateMessage
({
Size
?
size
})
async
{
if
(
size
==
null
)
{
return
;
}
bool
get
_createRequiresSize
=>
true
;
@override
// Size is non-nullable due to _createRequiresSize returning true.
Future
<
void
>
_sendCreateMessage
({
required
Size
size
})
async
{
assert
(!
size
.
isEmpty
,
'trying to create
$TextureAndroidViewController
without setting a valid size.'
);
final
Map
<
String
,
dynamic
>
args
=
<
String
,
dynamic
>{
...
...
@@ -1219,6 +1240,15 @@ abstract class PlatformViewController {
/// * [PlatformViewsRegistry], which is a helper for managing platform view IDs.
int
get
viewId
;
/// True if [create] has not been successfully called the platform view.
///
/// This can indicate either that [create] was never called, or that [create]
/// was deferred for implementation-specific reasons.
///
/// A `false` return value does not necessarily indicate that the [Future]
/// returned by [create] has completed, only that creation has been started.
bool
get
awaitingCreation
=>
false
;
/// Dispatches the `event` to the platform view.
Future
<
void
>
dispatchPointerEvent
(
PointerEvent
event
);
...
...
packages/flutter/lib/src/widgets/platform_view.dart
View file @
ab23233f
...
...
@@ -871,14 +871,20 @@ class _PlatformViewLinkState extends State<PlatformViewLink> {
@override
Widget
build
(
BuildContext
context
)
{
if
(
_controller
==
null
)
{
final
PlatformViewController
?
controller
=
_controller
;
if
(
controller
==
null
)
{
return
const
SizedBox
.
expand
();
}
if
(!
_platformViewCreated
)
{
// Depending on the platform, the initial size can be used to size the platform view.
return
_PlatformViewPlaceHolder
(
onLayout:
(
Size
size
)
=>
_controller
!.
create
(
size:
size
));
// Depending on the implementation, the initial size can be used to size
// the platform view.
return
_PlatformViewPlaceHolder
(
onLayout:
(
Size
size
)
{
if
(
controller
.
awaitingCreation
)
{
controller
.
create
(
size:
size
);
}
});
}
_surface
??=
widget
.
_surfaceFactory
(
context
,
_controller
!
);
_surface
??=
widget
.
_surfaceFactory
(
context
,
controller
);
return
Focus
(
focusNode:
_focusNode
,
onFocusChange:
_handleFrameworkFocusChanged
,
...
...
packages/flutter/test/services/fake_platform_views.dart
View file @
ab23233f
...
...
@@ -45,11 +45,16 @@ class FakePlatformViewController extends PlatformViewController {
}
class
FakeAndroidViewController
implements
AndroidViewController
{
FakeAndroidViewController
(
this
.
viewId
);
FakeAndroidViewController
(
this
.
viewId
,
{
this
.
requiresSize
=
false
}
);
bool
disposed
=
false
;
bool
focusCleared
=
false
;
bool
created
=
false
;
// If true, [create] won't be considered to have been called successfully
// unless it includes a size.
bool
requiresSize
;
bool
_createCalledSuccessfully
=
false
;
/// Events that are dispatched.
List
<
PointerEvent
>
dispatchedPointerEvents
=
<
PointerEvent
>[];
...
...
@@ -92,6 +97,9 @@ class FakeAndroidViewController implements AndroidViewController {
@override
int
get
textureId
=>
0
;
@override
bool
get
awaitingCreation
=>
!
_createCalledSuccessfully
;
@override
bool
get
isCreated
=>
created
;
...
...
@@ -114,7 +122,10 @@ class FakeAndroidViewController implements AndroidViewController {
}
@override
Future
<
void
>
create
({
Size
?
size
})
async
{}
Future
<
void
>
create
({
Size
?
size
})
async
{
assert
(!
_createCalledSuccessfully
);
_createCalledSuccessfully
=
size
!=
null
||
!
requiresSize
;
}
@override
List
<
PlatformViewCreatedCallback
>
get
createdCallbacks
=>
<
PlatformViewCreatedCallback
>[];
...
...
packages/flutter/test/widgets/platform_view_test.dart
View file @
ab23233f
...
...
@@ -1026,6 +1026,7 @@ void main() {
containerFocusNode
.
requestFocus
();
viewsController
.
createCompleter
!.
complete
();
await
tester
.
pump
();
expect
(
containerFocusNode
.
hasFocus
,
isTrue
);
...
...
@@ -2423,7 +2424,110 @@ void main() {
onCreatePlatformView:
(
PlatformViewCreationParams
params
)
{
onPlatformViewCreatedCallBack
=
params
.
onPlatformViewCreated
;
createdPlatformViewId
=
params
.
id
;
return
FakePlatformViewController
(
params
.
id
);
return
FakePlatformViewController
(
params
.
id
)..
create
();
},
surfaceFactory:
(
BuildContext
context
,
PlatformViewController
controller
)
{
return
PlatformViewSurface
(
gestureRecognizers:
const
<
Factory
<
OneSequenceGestureRecognizer
>>{},
controller:
controller
,
hitTestBehavior:
PlatformViewHitTestBehavior
.
opaque
,
);
},
);
await
tester
.
pumpWidget
(
platformViewLink
);
expect
(
tester
.
allWidgets
.
map
((
Widget
widget
)
=>
widget
.
runtimeType
.
toString
()).
toList
(),
equals
(<
String
>[
'PlatformViewLink'
,
'_PlatformViewPlaceHolder'
]),
);
onPlatformViewCreatedCallBack
(
createdPlatformViewId
);
await
tester
.
pump
();
expect
(
tester
.
allWidgets
.
map
((
Widget
widget
)
=>
widget
.
runtimeType
.
toString
()).
toList
(),
equals
(<
String
>[
'PlatformViewLink'
,
'Focus'
,
'_FocusMarker'
,
'Semantics'
,
'PlatformViewSurface'
]),
);
expect
(
createdPlatformViewId
,
currentViewId
+
1
);
},
);
testWidgets
(
'PlatformViewLink calls create when needed for Android texture display modes'
,
(
WidgetTester
tester
)
async
{
final
int
currentViewId
=
platformViewsRegistry
.
getNextPlatformViewId
();
late
int
createdPlatformViewId
;
late
PlatformViewCreatedCallback
onPlatformViewCreatedCallBack
;
late
PlatformViewController
controller
;
final
PlatformViewLink
platformViewLink
=
PlatformViewLink
(
viewType:
'webview'
,
onCreatePlatformView:
(
PlatformViewCreationParams
params
)
{
onPlatformViewCreatedCallBack
=
params
.
onPlatformViewCreated
;
createdPlatformViewId
=
params
.
id
;
controller
=
FakeAndroidViewController
(
params
.
id
,
requiresSize:
true
);
controller
.
create
();
// This test should be simulating one of the texture-based display
// modes, where `create` is a no-op when not provided a size, and
// creation is triggered via a later call to setSize, or to `create`
// with a size.
expect
(
controller
.
awaitingCreation
,
true
);
return
controller
;
},
surfaceFactory:
(
BuildContext
context
,
PlatformViewController
controller
)
{
return
PlatformViewSurface
(
gestureRecognizers:
const
<
Factory
<
OneSequenceGestureRecognizer
>>{},
controller:
controller
,
hitTestBehavior:
PlatformViewHitTestBehavior
.
opaque
,
);
},
);
await
tester
.
pumpWidget
(
platformViewLink
);
expect
(
tester
.
allWidgets
.
map
((
Widget
widget
)
=>
widget
.
runtimeType
.
toString
()).
toList
(),
equals
(<
String
>[
'PlatformViewLink'
,
'_PlatformViewPlaceHolder'
]),
);
onPlatformViewCreatedCallBack
(
createdPlatformViewId
);
await
tester
.
pump
();
expect
(
tester
.
allWidgets
.
map
((
Widget
widget
)
=>
widget
.
runtimeType
.
toString
()).
toList
(),
equals
(<
String
>[
'PlatformViewLink'
,
'Focus'
,
'_FocusMarker'
,
'Semantics'
,
'PlatformViewSurface'
]),
);
expect
(
createdPlatformViewId
,
currentViewId
+
1
);
expect
(
controller
.
awaitingCreation
,
false
);
},
);
testWidgets
(
'PlatformViewLink does not double-call create for Android Hybrid Composition'
,
(
WidgetTester
tester
)
async
{
final
int
currentViewId
=
platformViewsRegistry
.
getNextPlatformViewId
();
late
int
createdPlatformViewId
;
late
PlatformViewCreatedCallback
onPlatformViewCreatedCallBack
;
late
PlatformViewController
controller
;
final
PlatformViewLink
platformViewLink
=
PlatformViewLink
(
viewType:
'webview'
,
onCreatePlatformView:
(
PlatformViewCreationParams
params
)
{
onPlatformViewCreatedCallBack
=
params
.
onPlatformViewCreated
;
createdPlatformViewId
=
params
.
id
;
controller
=
FakeAndroidViewController
(
params
.
id
);
controller
.
create
();
// This test should be simulating Hybrid Composition mode, where
// `create` takes effect immidately.
expect
(
controller
.
awaitingCreation
,
false
);
return
controller
;
},
surfaceFactory:
(
BuildContext
context
,
PlatformViewController
controller
)
{
return
PlatformViewSurface
(
...
...
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