| // Copyright 2014 The Flutter Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| import 'dart:io'; |
| |
| import 'package:flutter/material.dart'; |
| import 'package:flutter/services.dart'; |
| |
| import 'android_platform_view.dart'; |
| import 'future_data_handler.dart'; |
| import 'page.dart'; |
| |
| class NestedViewEventPage extends PageWidget { |
| const NestedViewEventPage({Key? key}) |
| : super('Nested View Event Tests', const ValueKey<String>('NestedViewEventTile'), key: key); |
| |
| @override |
| Widget build(BuildContext context) => const NestedViewEventBody(); |
| } |
| |
| class NestedViewEventBody extends StatefulWidget { |
| const NestedViewEventBody({super.key}); |
| |
| @override |
| State<NestedViewEventBody> createState() => NestedViewEventBodyState(); |
| } |
| |
| enum _LastTestStatus { |
| pending, |
| success, |
| error |
| } |
| |
| class NestedViewEventBodyState extends State<NestedViewEventBody> { |
| MethodChannel? viewChannel; |
| _LastTestStatus _lastTestStatus = _LastTestStatus.pending; |
| String? lastError; |
| int? id; |
| int nestedViewClickCount = 0; |
| bool showPlatformView = true; |
| bool useHybridComposition = false; |
| |
| @override |
| Widget build(BuildContext context) { |
| return Scaffold( |
| appBar: AppBar( |
| title: const Text('Nested view event'), |
| ), |
| body: Column( |
| children: <Widget>[ |
| SizedBox( |
| height: 300, |
| child: showPlatformView ? |
| AndroidPlatformView( |
| key: const ValueKey<String>('PlatformView'), |
| viewType: 'simple_view', |
| onPlatformViewCreated: onPlatformViewCreated, |
| useHybridComposition: useHybridComposition, |
| ) : null, |
| ), |
| if (_lastTestStatus != _LastTestStatus.pending) _statusWidget(), |
| if (viewChannel != null) ... <Widget>[ |
| Row( |
| children: <Widget>[ |
| Expanded( |
| child: ElevatedButton( |
| key: const ValueKey<String>('ShowAlertDialog'), |
| onPressed: onShowAlertDialogPressed, |
| child: const Text('SHOW ALERT DIALOG'), |
| ), |
| ), |
| Expanded( |
| child: ElevatedButton( |
| key: const ValueKey<String>('TogglePlatformView'), |
| onPressed: onTogglePlatformView, |
| child: const Text('TOGGLE PLATFORM VIEW'), |
| ), |
| ), |
| ], |
| ), |
| Row( |
| children: <Widget>[ |
| Expanded( |
| child: ElevatedButton( |
| key: const ValueKey<String>('ToggleHybridComposition'), |
| child: const Text('TOGGLE HC'), |
| onPressed: () { |
| setState(() { |
| useHybridComposition = !useHybridComposition; |
| }); |
| }, |
| ), |
| ), |
| Expanded( |
| child: ElevatedButton( |
| key: const ValueKey<String>('AddChildView'), |
| onPressed: onChildViewPressed, |
| child: const Text('ADD CHILD VIEW'), |
| ), |
| ), |
| Expanded( |
| child: ElevatedButton( |
| key: const ValueKey<String>('TapChildView'), |
| onPressed: onTapChildViewPressed, |
| child: const Text('TAP CHILD VIEW'), |
| ), |
| ), |
| ], |
| ), |
| if (nestedViewClickCount > 0) |
| Text( |
| 'Click count: $nestedViewClickCount', |
| key: const ValueKey<String>('NestedViewClickCount'), |
| ), |
| ], |
| ], |
| ), |
| ); |
| } |
| |
| Widget _statusWidget() { |
| assert(_lastTestStatus != _LastTestStatus.pending); |
| final String message = _lastTestStatus == _LastTestStatus.success ? 'Success' : lastError!; |
| return Container( |
| color: _lastTestStatus == _LastTestStatus.success ? Colors.green : Colors.red, |
| child: Text( |
| message, |
| key: const ValueKey<String>('Status'), |
| style: TextStyle( |
| color: _lastTestStatus == _LastTestStatus.error ? Colors.yellow : null, |
| ), |
| ), |
| ); |
| } |
| |
| Future<void> onShowAlertDialogPressed() async { |
| if (_lastTestStatus != _LastTestStatus.pending) { |
| setState(() { |
| _lastTestStatus = _LastTestStatus.pending; |
| }); |
| } |
| try { |
| await viewChannel!.invokeMethod<void>('showAndHideAlertDialog'); |
| setState(() { |
| _lastTestStatus = _LastTestStatus.success; |
| }); |
| } catch(e) { |
| setState(() { |
| _lastTestStatus = _LastTestStatus.error; |
| lastError = '$e'; |
| }); |
| } |
| } |
| |
| Future<void> onTogglePlatformView() async { |
| setState(() { |
| showPlatformView = !showPlatformView; |
| }); |
| } |
| |
| Future<void> onChildViewPressed() async { |
| try { |
| await viewChannel!.invokeMethod<void>('addChildViewAndWaitForClick'); |
| setState(() { |
| nestedViewClickCount++; |
| }); |
| } catch(e) { |
| setState(() { |
| _lastTestStatus = _LastTestStatus.error; |
| lastError = '$e'; |
| }); |
| } |
| } |
| |
| Future<void> onTapChildViewPressed() async { |
| await Future<void>.delayed(const Duration(seconds: 1)); |
| |
| // Dispatch a tap event on the child view inside the platform view. |
| // |
| // Android mutates `MotionEvent` instances, so in this case *do not* dispatch |
| // new instances as it won't cover the `MotionEventTracker` class in the embedding |
| // which tracks events. |
| // |
| // See the issue this prevents: https://github.com/flutter/flutter/issues/61169 |
| await Process.run('input', const <String>['tap', '250', '550']); |
| } |
| |
| void onPlatformViewCreated(int id) { |
| this.id = id; |
| setState(() { |
| viewChannel = MethodChannel('simple_view/$id'); |
| }); |
| driverDataHandler.registerHandler('hierarchy') |
| .complete(() async => (await channel.invokeMethod<String>('getViewHierarchy'))!); |
| } |
| } |