Skip to content

Commit

Permalink
Add and default to Hybrid composition on Android (#916)
Browse files Browse the repository at this point in the history
* Add and default to Hybrid composition on Android

* ran flutter format

* added example for handling hybrid composition

* fixed issue with android:exported

* fixed typo

Co-authored-by: Felix Horvat <felix.horvat@ocell.aero>
  • Loading branch information
yoavrofe and felix-ht committed Mar 16, 2022
1 parent 7075c3b commit b29092e
Show file tree
Hide file tree
Showing 7 changed files with 90 additions and 10 deletions.
2 changes: 1 addition & 1 deletion example/android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

<activity
android:name=".MainActivity"
android:exported="false"
android:exported="true"
android:launchMode="singleTop"
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density"
Expand Down
2 changes: 2 additions & 0 deletions example/lib/generated_plugin_registrant.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@
// ignore_for_file: directives_ordering
// ignore_for_file: lines_longer_than_80_chars

import 'package:device_info_plus_web/device_info_plus_web.dart';
import 'package:location_web/location_web.dart';
import 'package:mapbox_gl_web/mapbox_gl_web.dart';

import 'package:flutter_web_plugins/flutter_web_plugins.dart';

// ignore: public_member_api_docs
void registerPlugins(Registrar registrar) {
DeviceInfoPlusPlugin.registerWith(registrar);
LocationWebPlugin.registerWith(registrar);
MapboxMapPlugin.registerWith(registrar);
registrar.registerMessageHandler();
Expand Down
34 changes: 32 additions & 2 deletions example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
// 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/foundation.dart';
import 'package:flutter/material.dart';
import 'package:location/location.dart';
Expand All @@ -11,6 +13,7 @@ import 'package:mapbox_gl_example/offline_regions.dart';
import 'package:mapbox_gl_example/place_batch.dart';
import 'package:mapbox_gl_example/layer.dart';
import 'package:mapbox_gl_example/sources.dart';
import 'package:device_info_plus/device_info_plus.dart';

import 'animate_camera.dart';
import 'annotation_order_maps.dart';
Expand All @@ -26,6 +29,7 @@ import 'place_source.dart';
import 'place_symbol.dart';
import 'place_fill.dart';
import 'scrolling_map.dart';
import 'package:mapbox_gl/mapbox_gl.dart';

final List<ExamplePage> _allPages = <ExamplePage>[
MapUiPage(),
Expand All @@ -48,7 +52,7 @@ final List<ExamplePage> _allPages = <ExamplePage>[
Sources()
];

class MapsDemo extends StatelessWidget {
class MapsDemo extends StatefulWidget {
// FIXME: You need to pass in your access token via the command line argument
// --dart-define=ACCESS_TOKEN=ADD_YOUR_TOKEN_HERE
// It is also possible to pass it in while running the app via an IDE by
Expand All @@ -58,6 +62,31 @@ class MapsDemo extends StatelessWidget {
// in the following line with your access token directly.
static const String ACCESS_TOKEN = String.fromEnvironment("ACCESS_TOKEN");

@override
State<MapsDemo> createState() => _MapsDemoState();
}

class _MapsDemoState extends State<MapsDemo> {
@override
void initState() {
initHybridComposition();
super.initState();
}

/// Determine the android version of the phone and turn off HybridComposition
/// on older sdk versions to improve performance for these
Future<void> initHybridComposition() async {
if (!kIsWeb && Platform.isAndroid) {
final androidInfo = await DeviceInfoPlugin().androidInfo;
final sdkVersion = androidInfo.version.sdkInt;
if (sdkVersion != null && sdkVersion >= 29) {
MapboxMap.useHybridComposition = true;
} else {
MapboxMap.useHybridComposition = false;
}
}
}

void _pushPage(BuildContext context, ExamplePage page) async {
if (!kIsWeb) {
final location = Location();
Expand All @@ -77,7 +106,8 @@ class MapsDemo extends StatelessWidget {
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('MapboxMaps examples')),
body: ACCESS_TOKEN.isEmpty || ACCESS_TOKEN.contains("YOUR_TOKEN")
body: MapsDemo.ACCESS_TOKEN.isEmpty ||
MapsDemo.ACCESS_TOKEN.contains("YOUR_TOKEN")
? buildAccessTokenWarning()
: ListView.separated(
itemCount: _allPages.length,
Expand Down
1 change: 1 addition & 0 deletions example/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ dependencies:
path_provider: ^2.0.0
http: ^0.13.0
collection: ^1.0.0
device_info_plus: ^3.2.2

dependency_overrides:
mapbox_gl_platform_interface:
Expand Down
8 changes: 8 additions & 0 deletions lib/src/mapbox_map.dart
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,14 @@ class MapboxMap extends StatefulWidget {
/// * All fade/transition animations have completed
final OnMapIdleCallback? onMapIdle;

/// Set `MapboxMap.useHybridComposition` to `false` in order use Virtual-Display
/// (better for Android 9 and below but may result in errors on Android 12)
/// or leave it `true` (default) to use Hybrid composition (Slower on Android 9 and below).
static bool get useHybridComposition =>
MethodChannelMapboxGl.useHybridComposition;
static set useHybridComposition(bool useHybridComposition) =>
MethodChannelMapboxGl.useHybridComposition = useHybridComposition;

@override
State createState() => _MapboxMapState();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import 'dart:typed_data';
import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
import 'package:meta/meta.dart' show visibleForTesting;

Expand Down
52 changes: 45 additions & 7 deletions mapbox_gl_platform_interface/lib/src/method_channel_mapbox_gl.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ part of mapbox_gl_platform_interface;

class MethodChannelMapboxGl extends MapboxGlPlatform {
late MethodChannel _channel;
static bool useHybridComposition = true;

Future<dynamic> _handleMethodCall(MethodCall call) async {
switch (call.method) {
Expand Down Expand Up @@ -138,13 +139,50 @@ class MethodChannelMapboxGl extends MapboxGlPlatform {
OnPlatformViewCreatedCallback onPlatformViewCreated,
Set<Factory<OneSequenceGestureRecognizer>>? gestureRecognizers) {
if (defaultTargetPlatform == TargetPlatform.android) {
return AndroidView(
viewType: 'plugins.flutter.io/mapbox_gl',
onPlatformViewCreated: onPlatformViewCreated,
gestureRecognizers: gestureRecognizers,
creationParams: creationParams,
creationParamsCodec: const StandardMessageCodec(),
);
if (useHybridComposition) {
return PlatformViewLink(
viewType: 'plugins.flutter.io/mapbox_gl',
surfaceFactory: (
BuildContext context,
PlatformViewController controller,
) {
return AndroidViewSurface(
controller: controller as AndroidViewController,
gestureRecognizers: gestureRecognizers ??
const <Factory<OneSequenceGestureRecognizer>>{},
hitTestBehavior: PlatformViewHitTestBehavior.opaque,
);
},
onCreatePlatformView: (PlatformViewCreationParams params) {
final SurfaceAndroidViewController controller =
PlatformViewsService.initSurfaceAndroidView(
id: params.id,
viewType: 'plugins.flutter.io/mapbox_gl',
layoutDirection: TextDirection.ltr,
creationParams: creationParams,
creationParamsCodec: const StandardMessageCodec(),
onFocus: () => params.onFocusChanged(true),
);
controller.addOnPlatformViewCreatedListener(

This comment has been minimized.

Copy link
@AAverin

AAverin May 20, 2022

Contributor

Any particluar reason why we have two callbacks for onPlatformViewCreated here?
@felix-ht @yoavrofe
Could it be the reason onStyleLoaded is now triggered twice with Flutter 3 fixes?

This comment has been minimized.

Copy link
@AAverin

AAverin May 20, 2022

Contributor

Ignore that, looks to be a Flutter problem. onPlatformViewCreated gets called twice for some reason.

params.onPlatformViewCreated,
);
controller.addOnPlatformViewCreatedListener(
onPlatformViewCreated,
);

controller.create();
return controller;
},
);
} else {
return AndroidView(
viewType: 'plugins.flutter.io/mapbox_gl',
onPlatformViewCreated: onPlatformViewCreated,
gestureRecognizers: gestureRecognizers,
creationParams: creationParams,
creationParamsCodec: const StandardMessageCodec(),
);
}
} else if (defaultTargetPlatform == TargetPlatform.iOS) {
return UiKitView(
viewType: 'plugins.flutter.io/mapbox_gl',
Expand Down

0 comments on commit b29092e

Please sign in to comment.