diff --git a/shell/platform/android/io/flutter/view/FlutterView.java b/shell/platform/android/io/flutter/view/FlutterView.java index 4cc23736da43a1aa98d0a1d674d2e4a04368937f..c3d023b64c63a41634318706ac2ddaa041476e21 100644 --- a/shell/platform/android/io/flutter/view/FlutterView.java +++ b/shell/platform/android/io/flutter/view/FlutterView.java @@ -581,11 +581,16 @@ public class FlutterView extends SurfaceView private static native void nativeSurfaceDestroyed(long nativePlatformViewAndroid); private static native Bitmap nativeGetBitmap(long nativePlatformViewAndroid); + // Send a platform message to Dart. + private static native void nativeDispatchPlatformMessage(long nativePlatformViewAndroid, String name, String message, int responseId); private static native void nativeDispatchPointerDataPacket(long nativePlatformViewAndroid, ByteBuffer buffer, int position); private static native void nativeDispatchSemanticsAction(long nativePlatformViewAndroid, int id, int action); private static native void nativeSetSemanticsEnabled(long nativePlatformViewAndroid, boolean enabled); - private static native void nativeInvokePlatformMessageResponseCallback(long nativePlatformViewAndroid, int responseId, String buffer); + // Send a response to a platform message received from Dart. + private static native void nativeInvokePlatformMessageResponseCallback(long nativePlatformViewAndroid, int responseId, String message); + + // Called by native to send us a platform message. @CalledByNative private void handlePlatformMessage(String name, String message, final int responseId) { OnMessageListener listener = mOnMessageListeners.get(name); @@ -597,10 +602,10 @@ public class FlutterView extends SurfaceView OnMessageListenerAsync asyncListener = mAsyncOnMessageListeners.get(name); if (asyncListener != null) { asyncListener.onMessage(this, message, new MessageResponse() { - @Override - public void send(String response) { - nativeInvokePlatformMessageResponseCallback(mNativePlatformView, responseId, response); - } + @Override + public void send(String response) { + nativeInvokePlatformMessageResponseCallback(mNativePlatformView, responseId, response); + } }); return; } @@ -608,6 +613,17 @@ public class FlutterView extends SurfaceView nativeInvokePlatformMessageResponseCallback(mNativePlatformView, responseId, null); } + private int mNextResponseId = 1; + private final Map mPendingResponses = new HashMap(); + + // Called by native to respond to a platform message that we sent. + @CalledByNative + private void handlePlatformMessageResponse(int responseId, String response) { + MessageReplyCallback callback = mPendingResponses.remove(responseId); + if (callback != null) + callback.onReply(response); + } + @CalledByNative private void updateSemantics(ByteBuffer buffer, String[] strings) { if (mAccessibilityNodeProvider != null) { @@ -712,12 +728,23 @@ public class FlutterView extends SurfaceView return true; } + private void dispatchPlatformMessage(String name, String message, MessageReplyCallback callback) { + int responseId = 0; + if (callback != null) { + responseId = mNextResponseId++; + mPendingResponses.put(responseId, callback); + } + nativeDispatchPlatformMessage(mNativePlatformView, name, message, responseId); + } + /** * Send a message to the Flutter application. The Flutter Dart code can register a * host message handler that will receive these messages. */ public void sendToFlutter(String messageName, String message, final MessageReplyCallback callback) { + // TODO(abarth): Switch to dispatchPlatformMessage once the framework + // side has been converted. mFlutterAppMessages.sendString(messageName, message, new ApplicationMessages.SendStringResponse() { @Override diff --git a/shell/platform/android/platform_view_android.cc b/shell/platform/android/platform_view_android.cc index ca0070b48d0a8897738c8e6988e66c5a589c5ecb..489fae4c8c82e46be5fa843f44a546f77e620dc4 100644 --- a/shell/platform/android/platform_view_android.cc +++ b/shell/platform/android/platform_view_android.cc @@ -30,6 +30,36 @@ #include "third_party/skia/include/core/SkSurface.h" namespace shell { +namespace { + +class PlatformMessageResponseAndroid : public blink::PlatformMessageResponse { + FRIEND_MAKE_REF_COUNTED(PlatformMessageResponseAndroid); + + public: + void Complete(std::vector data) override { + ftl::RefPtr self(this); + blink::Threads::Platform()->PostTask( + [ self, data = std::move(data) ]() mutable { + if (!self->view_) + return; + static_cast(self->view_.get()) + ->HandlePlatformMessageResponse(self->response_id_, + std::move(data)); + }); + } + + void CompleteWithError() override { Complete(std::vector()); } + + private: + PlatformMessageResponseAndroid(int response_id, + ftl::WeakPtr view) + : response_id_(response_id), view_(view) {} + + int response_id_; + ftl::WeakPtr view_; +}; + +} // namespace PlatformViewAndroid::PlatformViewAndroid() : PlatformView(std::make_unique()) {} @@ -105,6 +135,29 @@ void PlatformViewAndroid::SurfaceDestroyed(JNIEnv* env, jobject obj) { ReleaseSurface(); } +void PlatformViewAndroid::DispatchPlatformMessage(JNIEnv* env, + jobject obj, + jstring java_name, + jstring java_message_data, + jint response_id) { + std::string name = base::android::ConvertJavaStringToUTF8(env, java_name); + std::string data; + if (java_message_data) + data = base::android::ConvertJavaStringToUTF8(env, java_message_data); + + ftl::RefPtr response; + if (response_id) { + response = ftl::MakeRefCounted( + response_id, GetWeakPtr()); + } + + PlatformView::DispatchPlatformMessage( + ftl::MakeRefCounted( + std::move(name), + std::vector(data.data(), data.data() + data.size()), + std::move(response))); +} + void PlatformViewAndroid::DispatchPointerDataPacket(JNIEnv* env, jobject obj, jobject buffer, @@ -143,33 +196,47 @@ void PlatformViewAndroid::InvokePlatformMessageResponseCallback( void PlatformViewAndroid::HandlePlatformMessage( ftl::RefPtr message) { JNIEnv* env = base::android::AttachCurrentThread(); - { - base::android::ScopedJavaLocalRef view = flutter_view_.get(env); - if (view.is_null()) - return; + base::android::ScopedJavaLocalRef view = flutter_view_.get(env); + if (view.is_null()) + return; - int response_id = 0; - if (auto response = message->response()) { - response_id = next_response_id_++; - pending_responses_[response_id] = response; - } + int response_id = 0; + if (auto response = message->response()) { + response_id = next_response_id_++; + pending_responses_[response_id] = response; + } - base::StringPiece message_name = message->name(); + base::StringPiece message_name = message->name(); - auto data = message->data(); - base::StringPiece message_data(data.data(), data.size()); + auto data = message->data(); + base::StringPiece message_data(data.data(), data.size()); - auto java_message_name = - base::android::ConvertUTF8ToJavaString(env, message_name); - auto java_message_data = - base::android::ConvertUTF8ToJavaString(env, message_data); - message = nullptr; + auto java_message_name = + base::android::ConvertUTF8ToJavaString(env, message_name); + auto java_message_data = + base::android::ConvertUTF8ToJavaString(env, message_data); + message = nullptr; - // This call can re-enter in InvokePlatformMessageResponseCallback. - Java_FlutterView_handlePlatformMessage( - env, view.obj(), java_message_name.obj(), java_message_data.obj(), - response_id); - } + // This call can re-enter in InvokePlatformMessageResponseCallback. + Java_FlutterView_handlePlatformMessage(env, view.obj(), + java_message_name.obj(), + java_message_data.obj(), response_id); +} + +void PlatformViewAndroid::HandlePlatformMessageResponse( + int response_id, + std::vector data) { + JNIEnv* env = base::android::AttachCurrentThread(); + base::android::ScopedJavaLocalRef view = flutter_view_.get(env); + if (view.is_null()) + return; + + base::StringPiece message_data(data.data(), data.size()); + auto java_message_data = + base::android::ConvertUTF8ToJavaString(env, message_data); + + Java_FlutterView_handlePlatformMessageResponse(env, view.obj(), response_id, + java_message_data.obj()); } void PlatformViewAndroid::DispatchSemanticsAction(JNIEnv* env, diff --git a/shell/platform/android/platform_view_android.h b/shell/platform/android/platform_view_android.h index 4517c98fd9b329b67c8c2837d2c3b0bf7814f6d1..942064cb4382657242b3c1b5f1e992d1c18c8d59 100644 --- a/shell/platform/android/platform_view_android.h +++ b/shell/platform/android/platform_view_android.h @@ -37,6 +37,12 @@ class PlatformViewAndroid : public PlatformView { void SurfaceDestroyed(JNIEnv* env, jobject obj); + void DispatchPlatformMessage(JNIEnv* env, + jobject obj, + jstring name, + jstring message, + jint response_id); + void DispatchPointerDataPacket(JNIEnv* env, jobject obj, jobject buffer, @@ -61,6 +67,8 @@ class PlatformViewAndroid : public PlatformView { void HandlePlatformMessage( ftl::RefPtr message) override; + void HandlePlatformMessageResponse(int response_id, std::vector data); + void RunFromSource(const std::string& main, const std::string& packages, const std::string& assets_directory) override;