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
bc994c7f
Unverified
Commit
bc994c7f
authored
Sep 21, 2022
by
stuartmorgan
Committed by
GitHub
Sep 21, 2022
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Allow Hybrid Composition fallback for Android platform views (#109161)
parent
de517093
Changes
5
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
547 additions
and
121 deletions
+547
-121
platform_views.dart
packages/flutter/lib/src/services/platform_views.dart
+273
-81
platform_view.dart
packages/flutter/lib/src/widgets/platform_view.dart
+90
-11
fake_platform_views.dart
packages/flutter/test/services/fake_platform_views.dart
+45
-10
platform_views_test.dart
packages/flutter/test/services/platform_views_test.dart
+81
-8
platform_view_test.dart
packages/flutter/test/widgets/platform_view_test.dart
+58
-11
No files found.
packages/flutter/lib/src/services/platform_views.dart
View file @
bc994c7f
...
...
@@ -107,6 +107,10 @@ class PlatformViewsService {
/// The `id, `viewType, and `layoutDirection` parameters must not be null.
/// If `creationParams` is non null then `creationParamsCodec` must not be null.
/// {@endtemplate}
///
/// This attempts to use the newest and most efficient platform view
/// implementation when possible. In cases where that is not supported, it
/// falls back to using Virtual Display.
static
AndroidViewController
initAndroidView
({
required
int
id
,
required
String
viewType
,
...
...
@@ -134,9 +138,10 @@ class PlatformViewsService {
/// {@macro flutter.services.PlatformViewsService.initAndroidView}
///
/// Alias for [initAndroidView].
/// This factory is provided for backward compatibility purposes.
/// In the future, this method will be deprecated.
/// This attempts to use the newest and most efficient platform view
/// implementation when possible. In cases where that is not supported, it
/// falls back to using Hybrid Composition, which is the mode used by
/// [initExpensiveAndroidView].
static
SurfaceAndroidViewController
initSurfaceAndroidView
({
required
int
id
,
required
String
viewType
,
...
...
@@ -163,11 +168,12 @@ class PlatformViewsService {
/// {@macro flutter.services.PlatformViewsService.initAndroidView}
///
/// When this factory is used, the Android view and Flutter widgets are composed at the
/// Android view hierarchy level.
/// This is only useful if the view is a Android SurfaceView. However, using this method
/// has a performance cost on devices that run below 10, or underpowered devices.
/// In most situations, you should use [initAndroidView].
/// When this factory is used, the Android view and Flutter widgets are
/// composed at the Android view hierarchy level.
///
/// Using this method has a performance cost on devices running Android 9 or
/// earlier, or on underpowered devices. In most situations, you should use
/// [initAndroidView] or [initSurfaceAndroidView] instead.
static
ExpensiveAndroidViewController
initExpensiveAndroidView
({
required
int
id
,
required
String
viewType
,
...
...
@@ -668,6 +674,12 @@ class _AndroidMotionEventConverter {
event
is
!
PointerDownEvent
&&
event
is
!
PointerUpEvent
;
}
class
_CreationParams
{
const
_CreationParams
(
this
.
data
,
this
.
codec
);
final
dynamic
data
;
final
MessageCodec
<
dynamic
>
codec
;
}
/// Controls an Android view that is composed using a GL texture.
///
/// Typically created with [PlatformViewsService.initAndroidView].
...
...
@@ -685,8 +697,7 @@ abstract class AndroidViewController extends PlatformViewController {
assert
(
creationParams
==
null
||
creationParamsCodec
!=
null
),
_viewType
=
viewType
,
_layoutDirection
=
layoutDirection
,
_creationParams
=
creationParams
,
_creationParamsCodec
=
creationParamsCodec
;
_creationParams
=
creationParams
==
null
?
null
:
_CreationParams
(
creationParams
,
creationParamsCodec
!);
/// Action code for when a primary pointer touched the screen.
///
...
...
@@ -738,9 +749,7 @@ abstract class AndroidViewController extends PlatformViewController {
_AndroidViewState
_state
=
_AndroidViewState
.
waitingForSize
;
final
dynamic
_creationParams
;
final
MessageCodec
<
dynamic
>?
_creationParamsCodec
;
final
_CreationParams
?
_creationParams
;
final
List
<
PlatformViewCreatedCallback
>
_platformViewCreatedCallbacks
=
<
PlatformViewCreatedCallback
>[];
...
...
@@ -833,10 +842,17 @@ abstract class AndroidViewController extends PlatformViewController {
/// Returns the texture entry id that the Android view is rendering into.
///
/// Returns null if the Android view has not been successfully created,
or
if it has been
/// disposed.
/// Returns null if the Android view has not been successfully created, if it has been
/// disposed
, or if the implementation does not use textures
.
int
?
get
textureId
;
/// True if the view requires native view composition rather than using a
/// texture to render.
///
/// This value may change during [create], but will not change after that
/// call's future has completed.
bool
get
requiresViewComposition
=>
false
;
/// Sends an Android [MotionEvent](https://developer.android.com/reference/android/view/MotionEvent)
/// to the view.
///
...
...
@@ -979,7 +995,7 @@ abstract class AndroidViewController extends PlatformViewController {
/// Controls an Android view that is composed using a GL texture.
/// This controller is created from the [PlatformViewsService.initSurfaceAndroidView] factory,
/// and is defined for backward compatibility.
class
SurfaceAndroidViewController
extends
TextureAndroidViewController
{
class
SurfaceAndroidViewController
extends
AndroidViewController
{
SurfaceAndroidViewController
.
_
({
required
super
.
viewId
,
required
super
.
viewType
,
...
...
@@ -987,6 +1003,60 @@ class SurfaceAndroidViewController extends TextureAndroidViewController{
super
.
creationParams
,
super
.
creationParamsCodec
,
})
:
super
.
_
();
// By default, assume the implementation will be texture-based.
_AndroidViewControllerInternals
_internals
=
_TextureAndroidViewControllerInternals
();
@override
bool
get
_createRequiresSize
=>
true
;
@override
Future
<
bool
>
_sendCreateMessage
({
required
Size
size
})
async
{
assert
(!
size
.
isEmpty
,
'trying to create
$TextureAndroidViewController
without setting a valid size.'
);
final
dynamic
response
=
await
_AndroidViewControllerInternals
.
sendCreateMessage
(
viewId:
viewId
,
viewType:
_viewType
,
hybrid:
false
,
hybridFallback:
true
,
layoutDirection:
_layoutDirection
,
creationParams:
_creationParams
,
size:
size
,
);
if
(
response
is
int
)
{
(
_internals
as
_TextureAndroidViewControllerInternals
).
textureId
=
response
;
}
else
{
// A null response indicates fallback to Hybrid Composition, so swap out
// the implementation.
_internals
=
_HybridAndroidViewControllerInternals
();
}
return
true
;
}
@override
int
?
get
textureId
{
return
_internals
.
textureId
;
}
@override
bool
get
requiresViewComposition
{
return
_internals
.
requiresViewComposition
;
}
@override
Future
<
void
>
_sendDisposeMessage
()
{
return
_internals
.
sendDisposeMessage
(
viewId:
viewId
);
}
@override
Future
<
Size
>
_sendResizeMessage
(
Size
size
)
{
return
_internals
.
setSize
(
size
,
viewId:
viewId
,
viewState:
_state
);
}
@override
Future
<
void
>
setOffset
(
Offset
off
)
{
return
_internals
.
setOffset
(
off
,
viewId:
viewId
,
viewState:
_state
);
}
}
/// Controls an Android view that is composed using the Android view hierarchy.
...
...
@@ -1000,50 +1070,45 @@ class ExpensiveAndroidViewController extends AndroidViewController {
super
.
creationParamsCodec
,
})
:
super
.
_
();
final
_AndroidViewControllerInternals
_internals
=
_HybridAndroidViewControllerInternals
();
@override
bool
get
_createRequiresSize
=>
false
;
@override
Future
<
void
>
_sendCreateMessage
({
required
Size
?
size
})
async
{
final
Map
<
String
,
dynamic
>
args
=
<
String
,
dynamic
>{
'id'
:
viewId
,
'viewType'
:
_viewType
,
'direction'
:
AndroidViewController
.
_getAndroidDirection
(
_layoutDirection
),
'hybrid'
:
true
,
};
if
(
_creationParams
!=
null
)
{
final
ByteData
paramsByteData
=
_creationParamsCodec
!.
encodeMessage
(
_creationParams
)!;
args
[
'params'
]
=
Uint8List
.
view
(
paramsByteData
.
buffer
,
0
,
paramsByteData
.
lengthInBytes
,
await
_AndroidViewControllerInternals
.
sendCreateMessage
(
viewId:
viewId
,
viewType:
_viewType
,
hybrid:
true
,
layoutDirection:
_layoutDirection
,
creationParams:
_creationParams
,
);
}
await
SystemChannels
.
platform_views
.
invokeMethod
<
void
>(
'create'
,
args
);
@override
int
?
get
textureId
{
return
_internals
.
textureId
;
}
@override
int
get
textureId
{
throw
UnimplementedError
(
'Not supported for
$SurfaceAndroidViewController
.'
)
;
bool
get
requiresViewComposition
{
return
_internals
.
requiresViewComposition
;
}
@override
Future
<
void
>
_sendDisposeMessage
()
{
return
SystemChannels
.
platform_views
.
invokeMethod
<
void
>(
'dispose'
,
<
String
,
dynamic
>{
'id'
:
viewId
,
'hybrid'
:
true
,
});
return
_internals
.
sendDisposeMessage
(
viewId:
viewId
);
}
@override
Future
<
Size
>
_sendResizeMessage
(
Size
size
)
{
throw
UnimplementedError
(
'Not supported for
$SurfaceAndroidViewController
.'
);
return
_internals
.
setSize
(
size
,
viewId:
viewId
,
viewState:
_state
);
}
@override
Future
<
void
>
setOffset
(
Offset
off
)
{
throw
UnimplementedError
(
'Not supported for
$SurfaceAndroidViewController
.'
);
return
_internals
.
setOffset
(
off
,
viewId:
viewId
,
viewState:
_state
);
}
}
...
...
@@ -1062,23 +1127,132 @@ class TextureAndroidViewController extends AndroidViewController {
super
.
creationParamsCodec
,
})
:
super
.
_
();
/// The texture entry id into which the Android view is rendered.
int
?
_textureId
;
final
_TextureAndroidViewControllerInternals
_internals
=
_TextureAndroidViewControllerInternals
();
/// Returns the texture entry id that the Android view is rendering into.
///
/// Returns null if the Android view has not been successfully created, or if it has been
/// disposed.
@override
int
?
get
textureId
=>
_textureId
;
bool
get
_createRequiresSize
=>
true
;
@override
Future
<
void
>
_sendCreateMessage
({
required
Size
size
})
async
{
assert
(!
size
.
isEmpty
,
'trying to create
$TextureAndroidViewController
without setting a valid size.'
);
_internals
.
textureId
=
await
_AndroidViewControllerInternals
.
sendCreateMessage
(
viewId:
viewId
,
viewType:
_viewType
,
hybrid:
false
,
layoutDirection:
_layoutDirection
,
creationParams:
_creationParams
,
size:
size
,
)
as
int
;
}
@override
int
?
get
textureId
{
return
_internals
.
textureId
;
}
@override
bool
get
requiresViewComposition
{
return
_internals
.
requiresViewComposition
;
}
@override
Future
<
void
>
_sendDisposeMessage
()
{
return
_internals
.
sendDisposeMessage
(
viewId:
viewId
);
}
@override
Future
<
Size
>
_sendResizeMessage
(
Size
size
)
{
return
_internals
.
setSize
(
size
,
viewId:
viewId
,
viewState:
_state
);
}
@override
Future
<
void
>
setOffset
(
Offset
off
)
{
return
_internals
.
setOffset
(
off
,
viewId:
viewId
,
viewState:
_state
);
}
}
// The base class for an implementation of AndroidViewController.
//
// Subclasses should correspond to different rendering modes for platform
// views, and match different mode logic on the engine side.
abstract
class
_AndroidViewControllerInternals
{
// Sends a create message with the given parameters, and returns the result
// if any.
//
// This uses a dynamic return because depending on the mode that is selected
// on the native side, the return type is different. Callers should cast
// depending on the possible return types for their arguments.
static
Future
<
dynamic
>
sendCreateMessage
({
required
int
viewId
,
required
String
viewType
,
required
TextDirection
layoutDirection
,
required
bool
hybrid
,
bool
hybridFallback
=
false
,
_CreationParams
?
creationParams
,
Size
?
size
})
{
final
Map
<
String
,
dynamic
>
args
=
<
String
,
dynamic
>{
'id'
:
viewId
,
'viewType'
:
viewType
,
'direction'
:
AndroidViewController
.
_getAndroidDirection
(
layoutDirection
),
if
(
hybrid
==
true
)
'hybrid'
:
hybrid
,
if
(
size
!=
null
)
'width'
:
size
.
width
,
if
(
size
!=
null
)
'height'
:
size
.
height
,
if
(
hybridFallback
==
true
)
'hybridFallback'
:
hybridFallback
,
};
if
(
creationParams
!=
null
)
{
final
ByteData
paramsByteData
=
creationParams
.
codec
.
encodeMessage
(
creationParams
.
data
)!;
args
[
'params'
]
=
Uint8List
.
view
(
paramsByteData
.
buffer
,
0
,
paramsByteData
.
lengthInBytes
,
);
}
return
SystemChannels
.
platform_views
.
invokeMethod
<
dynamic
>(
'create'
,
args
);
}
int
?
get
textureId
;
bool
get
requiresViewComposition
;
Future
<
Size
>
setSize
(
Size
size
,
{
required
int
viewId
,
required
_AndroidViewState
viewState
,
});
Future
<
void
>
setOffset
(
Offset
offset
,
{
required
int
viewId
,
required
_AndroidViewState
viewState
,
});
Future
<
void
>
sendDisposeMessage
({
required
int
viewId
});
}
// An AndroidViewController implementation for views whose contents are
// displayed via a texture rather than directly in a native view.
//
// This is used for both Virtual Display and Texture Layer Hybrid Composition.
class
_TextureAndroidViewControllerInternals
extends
_AndroidViewControllerInternals
{
_TextureAndroidViewControllerInternals
();
/// The current offset of the platform view.
Offset
_off
=
Offset
.
zero
;
Offset
_off
set
=
Offset
.
zero
;
@override
Future
<
Size
>
_sendResizeMessage
(
Size
size
)
async
{
assert
(
_state
!=
_AndroidViewState
.
waitingForSize
,
'Android view must have an initial size. View id:
$viewId
'
);
assert
(
size
!=
null
);
int
?
textureId
;
@override
bool
get
requiresViewComposition
=>
false
;
@override
Future
<
Size
>
setSize
(
Size
size
,
{
required
int
viewId
,
required
_AndroidViewState
viewState
,
})
async
{
assert
(
viewState
!=
_AndroidViewState
.
waitingForSize
,
'Android view must have an initial size. View id:
$viewId
'
);
assert
(!
size
.
isEmpty
);
final
Map
<
Object
?,
Object
?>?
meta
=
await
SystemChannels
.
platform_views
.
invokeMapMethod
<
Object
?,
Object
?>(
...
...
@@ -1096,62 +1270,80 @@ class TextureAndroidViewController extends AndroidViewController {
}
@override
Future
<
void
>
setOffset
(
Offset
off
)
async
{
if
(
off
==
_off
)
{
Future
<
void
>
setOffset
(
Offset
offset
,
{
required
int
viewId
,
required
_AndroidViewState
viewState
,
})
async
{
if
(
offset
==
_offset
)
{
return
;
}
// Don't set the offset unless the Android view has been created.
// The implementation of this method channel throws if the Android view for this viewId
// isn't addressable.
if
(
_s
tate
!=
_AndroidViewState
.
created
)
{
if
(
viewS
tate
!=
_AndroidViewState
.
created
)
{
return
;
}
_off
=
off
;
_off
set
=
offset
;
await
SystemChannels
.
platform_views
.
invokeMethod
<
void
>(
'offset'
,
<
String
,
dynamic
>{
'id'
:
viewId
,
'top'
:
off
.
dy
,
'left'
:
off
.
dx
,
'top'
:
off
set
.
dy
,
'left'
:
off
set
.
dx
,
},
);
}
@override
bool
get
_createRequiresSize
=>
true
;
Future
<
void
>
sendDisposeMessage
({
required
int
viewId
})
{
return
SystemChannels
.
platform_views
.
invokeMethod
<
void
>(
'dispose'
,
<
String
,
dynamic
>{
'id'
:
viewId
,
'hybrid'
:
false
,
});
}
}
// An AndroidViewController implementation for views whose contents are
// displayed directly in a native view.
//
// This is used for Hybrid Composition.
class
_HybridAndroidViewControllerInternals
extends
_AndroidViewControllerInternals
{
@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.'
);
int
get
textureId
{
throw
UnimplementedError
(
'Not supported for hybrid composition.'
);
}
final
Map
<
String
,
dynamic
>
args
=
<
String
,
dynamic
>{
'id'
:
viewId
,
'viewType'
:
_viewType
,
'width'
:
size
.
width
,
'height'
:
size
.
height
,
'direction'
:
AndroidViewController
.
_getAndroidDirection
(
_layoutDirection
),
};
if
(
_creationParams
!=
null
)
{
final
ByteData
paramsByteData
=
_creationParamsCodec
!.
encodeMessage
(
_creationParams
)!;
args
[
'params'
]
=
Uint8List
.
view
(
paramsByteData
.
buffer
,
0
,
paramsByteData
.
lengthInBytes
,
);
@override
bool
get
requiresViewComposition
=>
true
;
@override
Future
<
Size
>
setSize
(
Size
size
,
{
required
int
viewId
,
required
_AndroidViewState
viewState
,
})
{
throw
UnimplementedError
(
'Not supported for hybrid composition.'
);
}
_textureId
=
await
SystemChannels
.
platform_views
.
invokeMethod
<
int
>(
'create'
,
args
);
@override
Future
<
void
>
setOffset
(
Offset
offset
,
{
required
int
viewId
,
required
_AndroidViewState
viewState
,
})
{
throw
UnimplementedError
(
'Not supported for hybrid composition.'
);
}
@override
Future
<
void
>
_sendDisposeMessage
()
{
return
SystemChannels
.
platform_views
.
invokeMethod
<
void
>(
'dispose'
,
<
String
,
dynamic
>{
Future
<
void
>
sendDisposeMessage
({
required
int
viewId
})
{
return
SystemChannels
.
platform_views
.
invokeMethod
<
void
>(
'dispose'
,
<
String
,
dynamic
>{
'id'
:
viewId
,
'hybrid'
:
fals
e
,
'hybrid'
:
tru
e
,
});
}
}
...
...
packages/flutter/lib/src/widgets/platform_view.dart
View file @
bc994c7f
...
...
@@ -1070,10 +1070,79 @@ class PlatformViewSurface extends LeafRenderObjectWidget {
///
/// * [AndroidView] which embeds an Android platform view in the widget hierarchy.
/// * [UiKitView] which embeds an iOS platform view in the widget hierarchy.
class
AndroidViewSurface
extends
PlatformViewSurface
{
class
AndroidViewSurface
extends
StatefulWidget
{
/// Construct an `AndroidPlatformViewSurface`.
const
AndroidViewSurface
({
super
.
key
,
required
this
.
controller
,
required
this
.
hitTestBehavior
,
required
this
.
gestureRecognizers
,
})
:
assert
(
controller
!=
null
),
assert
(
hitTestBehavior
!=
null
),
assert
(
gestureRecognizers
!=
null
);
/// The controller for the platform view integrated by this [AndroidViewSurface].
///
/// See [PlatformViewSurface.controller] for details.
final
AndroidViewController
controller
;
/// Which gestures should be forwarded to the PlatformView.
///
/// See [PlatformViewSurface.gestureRecognizers] for details.
final
Set
<
Factory
<
OneSequenceGestureRecognizer
>>
gestureRecognizers
;
/// {@macro flutter.widgets.AndroidView.hitTestBehavior}
final
PlatformViewHitTestBehavior
hitTestBehavior
;
@override
State
<
StatefulWidget
>
createState
()
{
return
_AndroidViewSurfaceState
();
}
}
class
_AndroidViewSurfaceState
extends
State
<
AndroidViewSurface
>
{
@override
void
initState
()
{
super
.
initState
();
if
(!
widget
.
controller
.
isCreated
)
{
// Schedule a rebuild once creation is complete and the final dislay
// type is known.
widget
.
controller
.
addOnPlatformViewCreatedListener
(
_onPlatformViewCreated
);
}
}
@override
void
dispose
()
{
widget
.
controller
.
removeOnPlatformViewCreatedListener
(
_onPlatformViewCreated
);
super
.
dispose
();
}
@override
Widget
build
(
BuildContext
context
)
{
if
(
widget
.
controller
.
requiresViewComposition
)
{
return
_PlatformLayerBasedAndroidViewSurface
(
controller:
widget
.
controller
,
hitTestBehavior:
widget
.
hitTestBehavior
,
gestureRecognizers:
widget
.
gestureRecognizers
,
);
}
else
{
return
_TextureBasedAndroidViewSurface
(
controller:
widget
.
controller
,
hitTestBehavior:
widget
.
hitTestBehavior
,
gestureRecognizers:
widget
.
gestureRecognizers
,
);
}
}
void
_onPlatformViewCreated
(
int
_
)
{
// Trigger a re-build based on the current controller state.
setState
(()
{});
}
}
// Displays an Android platform view via GL texture.
class
_TextureBasedAndroidViewSurface
extends
PlatformViewSurface
{
const
_TextureBasedAndroidViewSurface
({
required
AndroidViewController
super
.
controller
,
required
super
.
hitTestBehavior
,
required
super
.
gestureRecognizers
,
...
...
@@ -1084,16 +1153,6 @@ class AndroidViewSurface extends PlatformViewSurface {
@override
RenderObject
createRenderObject
(
BuildContext
context
)
{
final
AndroidViewController
viewController
=
controller
as
AndroidViewController
;
// Compose using the Android view hierarchy.
// This is useful when embedding a SurfaceView into a Flutter app.
// SurfaceViews cannot be composed using GL textures.
if
(
viewController
is
ExpensiveAndroidViewController
)
{
final
PlatformViewRenderBox
renderBox
=
super
.
createRenderObject
(
context
)
as
PlatformViewRenderBox
;
viewController
.
pointTransformer
=
(
Offset
position
)
=>
renderBox
.
globalToLocal
(
position
);
return
renderBox
;
}
// Use GL texture based composition.
// App should use GL texture unless they require to embed a SurfaceView.
final
RenderAndroidView
renderBox
=
RenderAndroidView
(
...
...
@@ -1107,6 +1166,26 @@ class AndroidViewSurface extends PlatformViewSurface {
}
}
class
_PlatformLayerBasedAndroidViewSurface
extends
PlatformViewSurface
{
const
_PlatformLayerBasedAndroidViewSurface
({
required
AndroidViewController
super
.
controller
,
required
super
.
hitTestBehavior
,
required
super
.
gestureRecognizers
,
})
:
assert
(
controller
!=
null
),
assert
(
hitTestBehavior
!=
null
),
assert
(
gestureRecognizers
!=
null
);
@override
RenderObject
createRenderObject
(
BuildContext
context
)
{
final
AndroidViewController
viewController
=
controller
as
AndroidViewController
;
final
PlatformViewRenderBox
renderBox
=
super
.
createRenderObject
(
context
)
as
PlatformViewRenderBox
;
viewController
.
pointTransformer
=
(
Offset
position
)
=>
renderBox
.
globalToLocal
(
position
);
return
renderBox
;
}
}
/// A callback used to notify the size of the platform view placeholder.
/// This size is the initial size of the platform view.
typedef
_OnLayoutCallback
=
void
Function
(
Size
size
);
...
...
packages/flutter/test/services/fake_platform_views.dart
View file @
bc994c7f
...
...
@@ -45,7 +45,11 @@ class FakePlatformViewController extends PlatformViewController {
}
class
FakeAndroidViewController
implements
AndroidViewController
{
FakeAndroidViewController
(
this
.
viewId
,
{
this
.
requiresSize
=
false
});
FakeAndroidViewController
(
this
.
viewId
,
{
this
.
requiresSize
=
false
,
this
.
requiresViewComposition
=
false
,
});
bool
disposed
=
false
;
bool
focusCleared
=
false
;
...
...
@@ -56,6 +60,8 @@ class FakeAndroidViewController implements AndroidViewController {
bool
_createCalledSuccessfully
=
false
;
final
List
<
PlatformViewCreatedCallback
>
_createdCallbacks
=
<
PlatformViewCreatedCallback
>[];
/// Events that are dispatched.
List
<
PointerEvent
>
dispatchedPointerEvents
=
<
PointerEvent
>[];
...
...
@@ -106,10 +112,13 @@ class FakeAndroidViewController implements AndroidViewController {
@override
void
addOnPlatformViewCreatedListener
(
PlatformViewCreatedCallback
listener
)
{
created
=
true
;
createdCallbacks
.
add
(
listener
);
}
@override
void
removeOnPlatformViewCreatedListener
(
PlatformViewCreatedCallback
listener
)
{}
void
removeOnPlatformViewCreatedListener
(
PlatformViewCreatedCallback
listener
)
{
createdCallbacks
.
remove
(
listener
);
}
@override
Future
<
void
>
sendMotionEvent
(
AndroidMotionEvent
event
)
{
...
...
@@ -128,7 +137,10 @@ class FakeAndroidViewController implements AndroidViewController {
}
@override
List
<
PlatformViewCreatedCallback
>
get
createdCallbacks
=>
<
PlatformViewCreatedCallback
>[];
List
<
PlatformViewCreatedCallback
>
get
createdCallbacks
=>
_createdCallbacks
;
@override
bool
requiresViewComposition
;
}
class
FakeAndroidPlatformViewsController
{
...
...
@@ -153,6 +165,11 @@ class FakeAndroidPlatformViewsController {
Map
<
int
,
Offset
>
offsets
=
<
int
,
Offset
>{};
/// True if Texture Layer Hybrid Composition mode should be enabled.
///
/// When false, `create` will simulate the engine's fallback mode.
bool
allowTextureLayerMode
=
true
;
void
registerViewType
(
String
viewType
)
{
_registeredViewTypes
.
add
(
viewType
);
}
...
...
@@ -192,6 +209,7 @@ class FakeAndroidPlatformViewsController {
final
double
?
height
=
args
[
'height'
]
as
double
?;
final
int
layoutDirection
=
args
[
'direction'
]
as
int
;
final
bool
?
hybrid
=
args
[
'hybrid'
]
as
bool
?;
final
bool
?
hybridFallback
=
args
[
'hybridFallback'
]
as
bool
?;
final
Uint8List
?
creationParams
=
args
[
'params'
]
as
Uint8List
?;
if
(
_views
.
containsKey
(
id
))
{
...
...
@@ -215,11 +233,21 @@ class FakeAndroidPlatformViewsController {
_views
[
id
]
=
FakeAndroidPlatformView
(
id
,
viewType
,
width
!=
null
&&
height
!=
null
?
Size
(
width
,
height
)
:
null
,
layoutDirection
,
hybrid
,
creationParams
,
hybrid:
hybrid
,
hybridFallback:
hybridFallback
,
creationParams:
creationParams
,
);
// Return a hybrid result (null rather than a texture ID) if:
final
bool
hybridResult
=
// hybrid was explicitly requested, or
(
hybrid
??
false
)
||
// hybrid fallback was requested and simulated.
(!
allowTextureLayerMode
&&
(
hybridFallback
??
false
));
if
(
hybridResult
)
{
return
Future
<
void
>.
value
();
}
final
int
textureId
=
_textureCounter
++;
return
Future
<
int
>.
sync
(()
=>
textureId
);
return
Future
<
int
>.
value
(
textureId
);
}
Future
<
dynamic
>
_dispose
(
MethodCall
call
)
{
...
...
@@ -506,7 +534,8 @@ class FakeHtmlPlatformViewsController {
@immutable
class
FakeAndroidPlatformView
{
const
FakeAndroidPlatformView
(
this
.
id
,
this
.
type
,
this
.
size
,
this
.
layoutDirection
,
this
.
hybrid
,
[
this
.
creationParams
]);
const
FakeAndroidPlatformView
(
this
.
id
,
this
.
type
,
this
.
size
,
this
.
layoutDirection
,
{
this
.
hybrid
,
this
.
hybridFallback
,
this
.
creationParams
});
final
int
id
;
final
String
type
;
...
...
@@ -514,14 +543,16 @@ class FakeAndroidPlatformView {
final
Size
?
size
;
final
int
layoutDirection
;
final
bool
?
hybrid
;
final
bool
?
hybridFallback
;
FakeAndroidPlatformView
copyWith
({
Size
?
size
,
int
?
layoutDirection
})
=>
FakeAndroidPlatformView
(
id
,
type
,
size
??
this
.
size
,
layoutDirection
??
this
.
layoutDirection
,
hybrid
,
creationParams
,
hybrid:
hybrid
,
hybridFallback:
hybridFallback
,
creationParams:
creationParams
,
);
@override
...
...
@@ -535,6 +566,7 @@ class FakeAndroidPlatformView {
&&
listEquals
<
int
>(
other
.
creationParams
,
creationParams
)
&&
other
.
size
==
size
&&
other
.
hybrid
==
hybrid
&&
other
.
hybridFallback
==
hybridFallback
&&
other
.
layoutDirection
==
layoutDirection
;
}
...
...
@@ -546,11 +578,14 @@ class FakeAndroidPlatformView {
size
,
layoutDirection
,
hybrid
,
hybridFallback
,
);
@override
String
toString
()
{
return
'FakeAndroidPlatformView(id:
$id
, type:
$type
, size:
$size
, layoutDirection:
$layoutDirection
, hybrid:
$hybrid
, creationParams:
$creationParams
)'
;
return
'FakeAndroidPlatformView(id:
$id
, type:
$type
, size:
$size
, '
'layoutDirection:
$layoutDirection
, hybrid:
$hybrid
, '
'hybridFallback:
$hybridFallback
, creationParams:
$creationParams
)'
;
}
}
...
...
packages/flutter/test/services/platform_views_test.dart
View file @
bc994c7f
...
...
@@ -48,7 +48,7 @@ void main() {
}
});
test
(
'create Android views'
,
()
async
{
test
(
'create
VD-fallback
Android views'
,
()
async
{
viewsController
.
registerViewType
(
'webview'
);
await
PlatformViewsService
.
initAndroidView
(
id:
0
,
viewType:
'webview'
,
layoutDirection:
TextDirection
.
ltr
)
.
create
(
size:
const
Size
(
100.0
,
100.0
));
...
...
@@ -57,12 +57,85 @@ void main() {
expect
(
viewsController
.
views
,
unorderedEquals
(<
FakeAndroidPlatformView
>[
const
FakeAndroidPlatformView
(
0
,
'webview'
,
Size
(
100.0
,
100.0
),
AndroidViewController
.
kAndroidLayoutDirectionLtr
,
null
),
const
FakeAndroidPlatformView
(
1
,
'webview'
,
Size
(
200.0
,
300.0
),
AndroidViewController
.
kAndroidLayoutDirectionRtl
,
null
),
const
FakeAndroidPlatformView
(
0
,
'webview'
,
Size
(
100.0
,
100.0
),
AndroidViewController
.
kAndroidLayoutDirectionLtr
),
const
FakeAndroidPlatformView
(
1
,
'webview'
,
Size
(
200.0
,
300.0
),
AndroidViewController
.
kAndroidLayoutDirectionRtl
),
]),
);
});
test
(
'create HC-fallback Android views'
,
()
async
{
viewsController
.
registerViewType
(
'webview'
);
await
PlatformViewsService
.
initSurfaceAndroidView
(
id:
0
,
viewType:
'webview'
,
layoutDirection:
TextDirection
.
ltr
)
.
create
(
size:
const
Size
(
100.0
,
100.0
));
await
PlatformViewsService
.
initSurfaceAndroidView
(
id:
1
,
viewType:
'webview'
,
layoutDirection:
TextDirection
.
rtl
)
.
create
(
size:
const
Size
(
200.0
,
300.0
));
expect
(
viewsController
.
views
,
unorderedEquals
(<
FakeAndroidPlatformView
>[
const
FakeAndroidPlatformView
(
0
,
'webview'
,
Size
(
100.0
,
100.0
),
AndroidViewController
.
kAndroidLayoutDirectionLtr
,
hybridFallback:
true
),
const
FakeAndroidPlatformView
(
1
,
'webview'
,
Size
(
200.0
,
300.0
),
AndroidViewController
.
kAndroidLayoutDirectionRtl
,
hybridFallback:
true
),
]),
);
});
test
(
'create HC-only Android views'
,
()
async
{
viewsController
.
registerViewType
(
'webview'
);
await
PlatformViewsService
.
initExpensiveAndroidView
(
id:
0
,
viewType:
'webview'
,
layoutDirection:
TextDirection
.
ltr
)
.
create
(
size:
const
Size
(
100.0
,
100.0
));
await
PlatformViewsService
.
initExpensiveAndroidView
(
id:
1
,
viewType:
'webview'
,
layoutDirection:
TextDirection
.
rtl
)
.
create
(
size:
const
Size
(
200.0
,
300.0
));
expect
(
viewsController
.
views
,
unorderedEquals
(<
FakeAndroidPlatformView
>[
const
FakeAndroidPlatformView
(
0
,
'webview'
,
null
,
AndroidViewController
.
kAndroidLayoutDirectionLtr
,
hybrid:
true
),
const
FakeAndroidPlatformView
(
1
,
'webview'
,
null
,
AndroidViewController
.
kAndroidLayoutDirectionRtl
,
hybrid:
true
),
]),
);
});
test
(
'default view does not use view composition by default'
,
()
async
{
viewsController
.
registerViewType
(
'webview'
);
final
AndroidViewController
controller
=
PlatformViewsService
.
initAndroidView
(
id:
0
,
viewType:
'webview'
,
layoutDirection:
TextDirection
.
ltr
);
await
controller
.
create
(
size:
const
Size
(
100.0
,
100.0
));
expect
(
controller
.
requiresViewComposition
,
false
);
});
test
(
'default view does not use view composition in fallback mode'
,
()
async
{
viewsController
.
registerViewType
(
'webview'
);
viewsController
.
allowTextureLayerMode
=
false
;
final
AndroidViewController
controller
=
PlatformViewsService
.
initAndroidView
(
id:
0
,
viewType:
'webview'
,
layoutDirection:
TextDirection
.
ltr
);
await
controller
.
create
(
size:
const
Size
(
100.0
,
100.0
));
viewsController
.
allowTextureLayerMode
=
true
;
expect
(
controller
.
requiresViewComposition
,
false
);
});
test
(
'surface view does not use view composition by default'
,
()
async
{
viewsController
.
registerViewType
(
'webview'
);
final
AndroidViewController
controller
=
PlatformViewsService
.
initSurfaceAndroidView
(
id:
0
,
viewType:
'webview'
,
layoutDirection:
TextDirection
.
ltr
);
await
controller
.
create
(
size:
const
Size
(
100.0
,
100.0
));
expect
(
controller
.
requiresViewComposition
,
false
);
});
test
(
'surface view does uses view composition in fallback mode'
,
()
async
{
viewsController
.
registerViewType
(
'webview'
);
viewsController
.
allowTextureLayerMode
=
false
;
final
AndroidViewController
controller
=
PlatformViewsService
.
initSurfaceAndroidView
(
id:
0
,
viewType:
'webview'
,
layoutDirection:
TextDirection
.
ltr
);
await
controller
.
create
(
size:
const
Size
(
100.0
,
100.0
));
viewsController
.
allowTextureLayerMode
=
true
;
expect
(
controller
.
requiresViewComposition
,
true
);
});
test
(
'expensive view uses view composition'
,
()
async
{
viewsController
.
registerViewType
(
'webview'
);
final
AndroidViewController
controller
=
PlatformViewsService
.
initExpensiveAndroidView
(
id:
0
,
viewType:
'webview'
,
layoutDirection:
TextDirection
.
ltr
);
await
controller
.
create
(
size:
const
Size
(
100.0
,
100.0
));
expect
(
controller
.
requiresViewComposition
,
true
);
});
test
(
'reuse Android view id'
,
()
async
{
viewsController
.
registerViewType
(
'webview'
);
final
AndroidViewController
controller
=
PlatformViewsService
.
initAndroidView
(
...
...
@@ -111,7 +184,7 @@ void main() {
expect
(
viewsController
.
views
,
unorderedEquals
(<
FakeAndroidPlatformView
>[
const
FakeAndroidPlatformView
(
0
,
'webview'
,
Size
(
100.0
,
100.0
),
AndroidViewController
.
kAndroidLayoutDirectionLtr
,
null
),
const
FakeAndroidPlatformView
(
0
,
'webview'
,
Size
(
100.0
,
100.0
),
AndroidViewController
.
kAndroidLayoutDirectionLtr
),
]),
);
});
...
...
@@ -164,8 +237,8 @@ void main() {
expect
(
viewsController
.
views
,
unorderedEquals
(<
FakeAndroidPlatformView
>[
const
FakeAndroidPlatformView
(
0
,
'webview'
,
Size
(
100.0
,
100.0
),
AndroidViewController
.
kAndroidLayoutDirectionLtr
,
null
),
const
FakeAndroidPlatformView
(
1
,
'webview'
,
Size
(
500.0
,
500.0
),
AndroidViewController
.
kAndroidLayoutDirectionLtr
,
null
),
const
FakeAndroidPlatformView
(
0
,
'webview'
,
Size
(
100.0
,
100.0
),
AndroidViewController
.
kAndroidLayoutDirectionLtr
),
const
FakeAndroidPlatformView
(
1
,
'webview'
,
Size
(
500.0
,
500.0
),
AndroidViewController
.
kAndroidLayoutDirectionLtr
),
]),
);
});
...
...
@@ -209,7 +282,7 @@ void main() {
expect
(
viewsController
.
views
,
unorderedEquals
(<
FakeAndroidPlatformView
>[
const
FakeAndroidPlatformView
(
0
,
'webview'
,
Size
(
100.0
,
100.0
),
AndroidViewController
.
kAndroidLayoutDirectionLtr
,
null
),
const
FakeAndroidPlatformView
(
0
,
'webview'
,
Size
(
100.0
,
100.0
),
AndroidViewController
.
kAndroidLayoutDirectionLtr
),
]),
);
});
...
...
@@ -226,7 +299,7 @@ void main() {
expect
(
viewsController
.
views
,
unorderedEquals
(<
FakeAndroidPlatformView
>[
const
FakeAndroidPlatformView
(
0
,
'webview'
,
Size
(
100.0
,
100.0
),
AndroidViewController
.
kAndroidLayoutDirectionRtl
,
null
),
const
FakeAndroidPlatformView
(
0
,
'webview'
,
Size
(
100.0
,
100.0
),
AndroidViewController
.
kAndroidLayoutDirectionRtl
),
]),
);
});
...
...
packages/flutter/test/widgets/platform_view_test.dart
View file @
bc994c7f
...
...
@@ -41,7 +41,6 @@ void main() {
'webview'
,
const
Size
(
200.0
,
100.0
),
AndroidViewController
.
kAndroidLayoutDirectionLtr
,
null
,
),
]),
);
...
...
@@ -85,8 +84,7 @@ void main() {
'webview'
,
const
Size
(
200.0
,
100.0
),
AndroidViewController
.
kAndroidLayoutDirectionLtr
,
null
,
fakeView
.
creationParams
,
creationParams:
fakeView
.
creationParams
,
),
]),
);
...
...
@@ -150,7 +148,6 @@ void main() {
'webview'
,
const
Size
(
200.0
,
100.0
),
AndroidViewController
.
kAndroidLayoutDirectionLtr
,
null
,
),
]),
);
...
...
@@ -166,7 +163,6 @@ void main() {
'webview'
,
const
Size
(
100.0
,
50.0
),
AndroidViewController
.
kAndroidLayoutDirectionLtr
,
null
,
),
]),
);
...
...
@@ -205,7 +201,6 @@ void main() {
'maps'
,
const
Size
(
200.0
,
100.0
),
AndroidViewController
.
kAndroidLayoutDirectionLtr
,
null
,
),
]),
);
...
...
@@ -272,7 +267,6 @@ void main() {
'webview'
,
const
Size
(
200.0
,
100.0
),
AndroidViewController
.
kAndroidLayoutDirectionLtr
,
null
,
),
]),
);
...
...
@@ -495,7 +489,6 @@ void main() {
'maps'
,
const
Size
(
200.0
,
100.0
),
AndroidViewController
.
kAndroidLayoutDirectionRtl
,
null
,
),
]),
);
...
...
@@ -518,7 +511,6 @@ void main() {
'maps'
,
const
Size
(
200.0
,
100.0
),
AndroidViewController
.
kAndroidLayoutDirectionLtr
,
null
,
),
]),
);
...
...
@@ -549,7 +541,6 @@ void main() {
'maps'
,
const
Size
(
200.0
,
100.0
),
AndroidViewController
.
kAndroidLayoutDirectionRtl
,
null
,
),
]),
);
...
...
@@ -575,7 +566,6 @@ void main() {
'maps'
,
const
Size
(
200.0
,
100.0
),
AndroidViewController
.
kAndroidLayoutDirectionLtr
,
null
,
),
]),
);
...
...
@@ -1257,6 +1247,63 @@ void main() {
await
tester
.
pumpWidget
(
surface
);
expect
(
controller
.
pointTransformer
,
isNotNull
);
});
testWidgets
(
'AndroidViewSurface defaults to texture-based rendering'
,
(
WidgetTester
tester
)
async
{
final
AndroidViewSurface
surface
=
AndroidViewSurface
(
controller:
controller
,
hitTestBehavior:
PlatformViewHitTestBehavior
.
opaque
,
gestureRecognizers:
const
<
Factory
<
OneSequenceGestureRecognizer
>>{},
);
await
tester
.
pumpWidget
(
surface
);
expect
(
find
.
byWidgetPredicate
(
(
Widget
widget
)
=>
widget
.
runtimeType
.
toString
()
==
'_TextureBasedAndroidViewSurface'
,
),
findsOneWidget
);
});
testWidgets
(
'AndroidViewSurface uses view-based rendering when initially required'
,
(
WidgetTester
tester
)
async
{
controller
.
requiresViewComposition
=
true
;
final
AndroidViewSurface
surface
=
AndroidViewSurface
(
controller:
controller
,
hitTestBehavior:
PlatformViewHitTestBehavior
.
opaque
,
gestureRecognizers:
const
<
Factory
<
OneSequenceGestureRecognizer
>>{},
);
await
tester
.
pumpWidget
(
surface
);
expect
(
find
.
byWidgetPredicate
(
(
Widget
widget
)
=>
widget
.
runtimeType
.
toString
()
==
'_PlatformLayerBasedAndroidViewSurface'
,
),
findsOneWidget
);
});
testWidgets
(
'AndroidViewSurface can switch to view-based rendering after creation'
,
(
WidgetTester
tester
)
async
{
final
AndroidViewSurface
surface
=
AndroidViewSurface
(
controller:
controller
,
hitTestBehavior:
PlatformViewHitTestBehavior
.
opaque
,
gestureRecognizers:
const
<
Factory
<
OneSequenceGestureRecognizer
>>{},
);
await
tester
.
pumpWidget
(
surface
);
expect
(
find
.
byWidgetPredicate
(
(
Widget
widget
)
=>
widget
.
runtimeType
.
toString
()
==
'_TextureBasedAndroidViewSurface'
,
),
findsOneWidget
);
expect
(
find
.
byWidgetPredicate
(
(
Widget
widget
)
=>
widget
.
runtimeType
.
toString
()
==
'_PlatformLayerBasedAndroidViewSurface'
,
),
findsNothing
);
// Simulate a creation-time switch to view composition.
controller
.
requiresViewComposition
=
true
;
for
(
final
PlatformViewCreatedCallback
callback
in
controller
.
createdCallbacks
)
{
callback
(
controller
.
viewId
);
}
await
tester
.
pumpWidget
(
surface
);
expect
(
find
.
byWidgetPredicate
(
(
Widget
widget
)
=>
widget
.
runtimeType
.
toString
()
==
'_TextureBasedAndroidViewSurface'
,
),
findsNothing
);
expect
(
find
.
byWidgetPredicate
(
(
Widget
widget
)
=>
widget
.
runtimeType
.
toString
()
==
'_PlatformLayerBasedAndroidViewSurface'
,
),
findsOneWidget
);
});
});
group
(
'UiKitView'
,
()
{
...
...
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