feat(android): Add the keyboard height code
This commit is contained in:
		
							parent
							
								
									1852f2d198
								
							
						
					
					
						commit
						f949b008b3
					
				| @ -27,3 +27,7 @@ Thanks to [ekasetiawans](https://github.com/ekasetiawans) for [flutter_backgroun | |||||||
| was essentially the blueprint for the service and background service APIs. They were reimplemented | was essentially the blueprint for the service and background service APIs. They were reimplemented | ||||||
| to allow the root isolate to pass some additional data to the service, which `flutter_background_service` | to allow the root isolate to pass some additional data to the service, which `flutter_background_service` | ||||||
| did not support. | did not support. | ||||||
|  | 
 | ||||||
|  | Thanks to [nschairer](https://github.com/nschairer) for [flutter_keyboard_height](https://github.com/nschairer/keyboard_height_plugin), which was the base for keeping track of the keyboard height. | ||||||
|  | Due to having an issue with the height calculation if the Android device uses gesture navigation, I | ||||||
|  | [forked the package](https://git.polynom.me/moxxy/keyboard_height_plugin) and modified the height calculation. | ||||||
|  | |||||||
| @ -2,6 +2,9 @@ package org.moxxy.moxxy_native | |||||||
| 
 | 
 | ||||||
| const val TAG = "moxxy_native" | const val TAG = "moxxy_native" | ||||||
| 
 | 
 | ||||||
|  | // The event channel name for the keyboard height | ||||||
|  | const val KEYBOARD_HEIGHT_EVENT_CHANNEL_NAME = "org.moxxy.moxxyv2/notification_stream" | ||||||
|  | 
 | ||||||
| // The size of buffers to use for various operations | // The size of buffers to use for various operations | ||||||
| const val BUFFER_SIZE = 4096 | const val BUFFER_SIZE = 4096 | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -29,6 +29,7 @@ import org.moxxy.moxxy_native.notifications.NotificationsImplementation | |||||||
| import org.moxxy.moxxy_native.picker.FilePickerType | import org.moxxy.moxxy_native.picker.FilePickerType | ||||||
| import org.moxxy.moxxy_native.picker.MoxxyPickerApi | import org.moxxy.moxxy_native.picker.MoxxyPickerApi | ||||||
| import org.moxxy.moxxy_native.picker.PickerResultListener | import org.moxxy.moxxy_native.picker.PickerResultListener | ||||||
|  | import org.moxxy.moxxy_native.platform.KeyboardStreamHandler | ||||||
| import org.moxxy.moxxy_native.platform.MoxxyPlatformApi | import org.moxxy.moxxy_native.platform.MoxxyPlatformApi | ||||||
| import org.moxxy.moxxy_native.platform.PlatformImplementation | import org.moxxy.moxxy_native.platform.PlatformImplementation | ||||||
| import org.moxxy.moxxy_native.service.BackgroundService | import org.moxxy.moxxy_native.service.BackgroundService | ||||||
| @ -102,6 +103,10 @@ class MoxxyNativePlugin : FlutterPlugin, ActivityAware, ServiceAware, BroadcastR | |||||||
|             IntentFilter(SERVICE_FOREGROUND_METHOD_CHANNEL_KEY), |             IntentFilter(SERVICE_FOREGROUND_METHOD_CHANNEL_KEY), | ||||||
|         ) |         ) | ||||||
| 
 | 
 | ||||||
|  |         // Special handling for the keyboard height | ||||||
|  |         val keyboardChannel = EventChannel(flutterPluginBinding.getBinaryMessenger(), KEYBOARD_HEIGHT_EVENT_CHANNEL_NAME) | ||||||
|  |         keyboardChannel?.setStreamHandler(KeyboardStreamHandler) | ||||||
|  | 
 | ||||||
|         // Register the picker handler |         // Register the picker handler | ||||||
|         pickerListener = PickerResultListener(context!!) |         pickerListener = PickerResultListener(context!!) | ||||||
|         Log.d(TAG, "Attached to engine") |         Log.d(TAG, "Attached to engine") | ||||||
| @ -118,20 +123,24 @@ class MoxxyNativePlugin : FlutterPlugin, ActivityAware, ServiceAware, BroadcastR | |||||||
|     override fun onAttachedToActivity(binding: ActivityPluginBinding) { |     override fun onAttachedToActivity(binding: ActivityPluginBinding) { | ||||||
|         activity = binding.activity |         activity = binding.activity | ||||||
|         binding.addActivityResultListener(pickerListener) |         binding.addActivityResultListener(pickerListener) | ||||||
|  |         KeyboardStreamHandler.activity = activity | ||||||
|         Log.d(TAG, "Attached to activity") |         Log.d(TAG, "Attached to activity") | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     override fun onDetachedFromActivityForConfigChanges() { |     override fun onDetachedFromActivityForConfigChanges() { | ||||||
|         activity = null |         activity = null | ||||||
|  |         KeyboardStreamHandler.activity = null | ||||||
|         Log.d(TAG, "Detached from activity") |         Log.d(TAG, "Detached from activity") | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) { |     override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) { | ||||||
|         activity = binding.activity |         activity = binding.activity | ||||||
|  |         KeyboardStreamHandler.activity = activity | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     override fun onDetachedFromActivity() { |     override fun onDetachedFromActivity() { | ||||||
|         activity = null |         activity = null | ||||||
|  |         KeyboardStreamHandler.activity = null | ||||||
|         Log.d(TAG, "Detached from activity") |         Log.d(TAG, "Detached from activity") | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -164,7 +164,7 @@ class NotificationReceiver : BroadcastReceiver() { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fun handleTap(context: Context, intent: Intent) { |     private fun handleTap(context: Context, intent: Intent) { | ||||||
|         MoxxyEventChannels.notificationEventSink?.success( |         MoxxyEventChannels.notificationEventSink?.success( | ||||||
|             NotificationEvent( |             NotificationEvent( | ||||||
|                 intent.getLongExtra(NOTIFICATION_EXTRA_ID_KEY, -1), |                 intent.getLongExtra(NOTIFICATION_EXTRA_ID_KEY, -1), | ||||||
|  | |||||||
| @ -0,0 +1,73 @@ | |||||||
|  | package org.moxxy.moxxy_native.platform | ||||||
|  | 
 | ||||||
|  | import android.app.Activity | ||||||
|  | import android.graphics.Rect | ||||||
|  | import android.util.Log | ||||||
|  | import android.view.View | ||||||
|  | import android.view.ViewTreeObserver | ||||||
|  | import androidx.core.view.ViewCompat | ||||||
|  | import androidx.core.view.WindowInsetsCompat | ||||||
|  | import io.flutter.plugin.common.EventChannel | ||||||
|  | import org.moxxy.moxxy_native.MoxxyEventChannels | ||||||
|  | import org.moxxy.moxxy_native.TAG | ||||||
|  | 
 | ||||||
|  | object KeyboardStreamHandler : EventChannel.StreamHandler { | ||||||
|  |     // The currently active activity. Set by @MoxxyNativePlugin. | ||||||
|  |     var activity: Activity? = null | ||||||
|  | 
 | ||||||
|  |     // The current bottom inset. | ||||||
|  |     private var bottomInset: Int = 0 | ||||||
|  | 
 | ||||||
|  |     // The current event sink to use for sending events to the UI. | ||||||
|  |     private var sink: EventChannel.EventSink? = null | ||||||
|  | 
 | ||||||
|  |     private fun handleKeyboardHeightCheck(rootView: View?) { | ||||||
|  |         rootView?.viewTreeObserver?.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener { | ||||||
|  |             override fun onGlobalLayout() { | ||||||
|  |                 val r = Rect() | ||||||
|  |                 rootView.getWindowVisibleDisplayFrame(r) | ||||||
|  | 
 | ||||||
|  |                 val screenHeight = rootView.height | ||||||
|  |                 // Also subtract the height of the bottom inset as the SafeArea with "bottom: false" | ||||||
|  |                 // allows us to draw under the bottom system bar, if it is there. | ||||||
|  |                 val keypadHeight = screenHeight - r.bottom - bottomInset | ||||||
|  | 
 | ||||||
|  |                 val displayMetrics = activity?.resources?.displayMetrics | ||||||
|  |                 val logicalKeypadHeight = keypadHeight / (displayMetrics?.density ?: 1f) | ||||||
|  | 
 | ||||||
|  |                 if (keypadHeight > screenHeight * 0.15) { | ||||||
|  |                     sink?.success(logicalKeypadHeight.toDouble()) | ||||||
|  |                 } else { | ||||||
|  |                     sink?.success(0.0) | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         }) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     override fun onListen(arguments: Any?, events: EventChannel.EventSink?) { | ||||||
|  |         // "register" the event sink | ||||||
|  |         sink = events | ||||||
|  | 
 | ||||||
|  |         val rootView = activity?.window?.decorView?.rootView | ||||||
|  |         handleKeyboardHeightCheck(rootView) | ||||||
|  | 
 | ||||||
|  |         if (rootView != null) { | ||||||
|  |             ViewCompat.setOnApplyWindowInsetsListener(rootView!!) { _, windowInsets -> | ||||||
|  |                 val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars()) | ||||||
|  |                 val triggerEvent = bottomInset != insets.bottom | ||||||
|  |                 bottomInset = insets.bottom | ||||||
|  | 
 | ||||||
|  |                 // Notify in case the inset changed | ||||||
|  |                 if (triggerEvent) handleKeyboardHeightCheck(rootView) | ||||||
|  | 
 | ||||||
|  |                 WindowInsetsCompat.CONSUMED | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         Log.d(TAG, "KeyboardStreamHandler: Attached stream") | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     override fun onCancel(arguments: Any?) { | ||||||
|  |         MoxxyEventChannels.notificationEventSink = null | ||||||
|  |         Log.d(TAG, "KeyboardStreamHandler: Detached stream") | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -1,6 +1,5 @@ | |||||||
| // ignore_for_file: avoid_print | // ignore_for_file: avoid_print | ||||||
| import 'dart:io'; | import 'dart:io'; | ||||||
| import 'dart:typed_data'; |  | ||||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||||
| import 'package:flutter/services.dart'; | import 'package:flutter/services.dart'; | ||||||
| import 'package:get_it/get_it.dart'; | import 'package:get_it/get_it.dart'; | ||||||
| @ -51,6 +50,19 @@ class TestEvent extends BackgroundEvent { | |||||||
| class MyAppState extends State<MyApp> { | class MyAppState extends State<MyApp> { | ||||||
|   String? imagePath; |   String? imagePath; | ||||||
| 
 | 
 | ||||||
|  |   @override | ||||||
|  |   void initState() { | ||||||
|  |     super.initState(); | ||||||
|  | 
 | ||||||
|  |     const EventChannel('org.moxxy.moxxyv2/notification_stream') | ||||||
|  |         .receiveBroadcastStream() | ||||||
|  |         .listen( | ||||||
|  |       (event) { | ||||||
|  |         print('Keyboard height: ${event as double}'); | ||||||
|  |       }, | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   @override |   @override | ||||||
|   Widget build(BuildContext context) { |   Widget build(BuildContext context) { | ||||||
|     return MaterialApp( |     return MaterialApp( | ||||||
| @ -221,6 +233,7 @@ class MyAppState extends State<MyApp> { | |||||||
|               }, |               }, | ||||||
|               child: const Text('Share some text'), |               child: const Text('Share some text'), | ||||||
|             ), |             ), | ||||||
|  |             const TextField(), | ||||||
|           ], |           ], | ||||||
|         ), |         ), | ||||||
|       ), |       ), | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user