Revert "Android Background Platform Channels (#29147)" (flutter/engine#29344)
This reverts commit c40f7670e7.
This commit is contained in:
@@ -708,7 +708,6 @@ FILE: ../../../flutter/shell/common/persistent_cache_unittests.cc
|
||||
FILE: ../../../flutter/shell/common/pipeline.cc
|
||||
FILE: ../../../flutter/shell/common/pipeline.h
|
||||
FILE: ../../../flutter/shell/common/pipeline_unittests.cc
|
||||
FILE: ../../../flutter/shell/common/platform_message_handler.h
|
||||
FILE: ../../../flutter/shell/common/platform_view.cc
|
||||
FILE: ../../../flutter/shell/common/platform_view.h
|
||||
FILE: ../../../flutter/shell/common/pointer_data_dispatcher.cc
|
||||
@@ -842,7 +841,6 @@ FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/Flutte
|
||||
FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/dart/DartExecutor.java
|
||||
FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/dart/DartMessenger.java
|
||||
FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/dart/PlatformMessageHandler.java
|
||||
FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/dart/PlatformTaskQueue.java
|
||||
FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/deferredcomponents/DeferredComponentManager.java
|
||||
FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/deferredcomponents/PlayStoreDeferredComponentManager.java
|
||||
FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/loader/ApplicationInfoLoader.java
|
||||
@@ -940,8 +938,6 @@ FILE: ../../../flutter/shell/platform/android/jni/jni_mock_unittest.cc
|
||||
FILE: ../../../flutter/shell/platform/android/jni/platform_view_android_jni.cc
|
||||
FILE: ../../../flutter/shell/platform/android/jni/platform_view_android_jni.h
|
||||
FILE: ../../../flutter/shell/platform/android/library_loader.cc
|
||||
FILE: ../../../flutter/shell/platform/android/platform_message_handler_android.cc
|
||||
FILE: ../../../flutter/shell/platform/android/platform_message_handler_android.h
|
||||
FILE: ../../../flutter/shell/platform/android/platform_message_response_android.cc
|
||||
FILE: ../../../flutter/shell/platform/android/platform_message_response_android.h
|
||||
FILE: ../../../flutter/shell/platform/android/platform_view_android.cc
|
||||
|
||||
@@ -73,7 +73,6 @@ source_set("common") {
|
||||
"engine.h",
|
||||
"pipeline.cc",
|
||||
"pipeline.h",
|
||||
"platform_message_handler.h",
|
||||
"platform_view.cc",
|
||||
"platform_view.h",
|
||||
"pointer_data_dispatcher.cc",
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
// Copyright 2013 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.
|
||||
|
||||
#ifndef SHELL_COMMON_PLATFORM_MESSAGE_HANDLER_H_
|
||||
#define SHELL_COMMON_PLATFORM_MESSAGE_HANDLER_H_
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "flutter/lib/ui/window/platform_message.h"
|
||||
|
||||
namespace flutter {
|
||||
|
||||
/// An interface over the ability to handle PlatformMessages that are being sent
|
||||
/// from Flutter to the host platform.
|
||||
class PlatformMessageHandler {
|
||||
public:
|
||||
virtual ~PlatformMessageHandler() = default;
|
||||
|
||||
/// Ultimately sends the PlatformMessage to the host platform.
|
||||
/// This method is invoked on the ui thread.
|
||||
virtual void HandlePlatformMessage(
|
||||
std::unique_ptr<PlatformMessage> message) = 0;
|
||||
|
||||
/// Performs the return procedure for an associated call to
|
||||
/// HandlePlatformMessage.
|
||||
/// This method should be thread-safe and able to be invoked on any thread.
|
||||
virtual void InvokePlatformMessageResponseCallback(
|
||||
int response_id,
|
||||
std::unique_ptr<fml::Mapping> mapping) = 0;
|
||||
|
||||
/// Performs the return procedure for an associated call to
|
||||
/// HandlePlatformMessage where there is no return value.
|
||||
/// This method should be thread-safe and able to be invoked on any thread.
|
||||
virtual void InvokePlatformMessageEmptyResponseCallback(int response_id) = 0;
|
||||
};
|
||||
} // namespace flutter
|
||||
|
||||
#endif // SHELL_COMMON_PLATFORM_MESSAGE_HANDLER_H_
|
||||
@@ -184,9 +184,4 @@ PlatformView::CreateSnapshotSurfaceProducer() {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<PlatformMessageHandler>
|
||||
PlatformView::GetPlatformMessageHandler() const {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace flutter
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
#include "flutter/lib/ui/window/pointer_data_packet.h"
|
||||
#include "flutter/lib/ui/window/pointer_data_packet_converter.h"
|
||||
#include "flutter/lib/ui/window/viewport_metrics.h"
|
||||
#include "flutter/shell/common/platform_message_handler.h"
|
||||
#include "flutter/shell/common/pointer_data_dispatcher.h"
|
||||
#include "flutter/shell/common/vsync_waiter.h"
|
||||
#include "third_party/skia/include/core/SkSize.h"
|
||||
@@ -811,17 +810,6 @@ class PlatformView {
|
||||
virtual std::unique_ptr<SnapshotSurfaceProducer>
|
||||
CreateSnapshotSurfaceProducer();
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
/// @brief Specifies a delegate that will receive PlatformMessages from
|
||||
/// Flutter to the host platform.
|
||||
///
|
||||
/// @details If this returns `null` that means PlatformMessages should be sent
|
||||
/// to the PlatformView. That is to protect legacy behavior, any embedder
|
||||
/// that wants to support executing Platform Channel handlers on background
|
||||
/// threads should be returing a thread-safe PlatformMessageHandler instead.
|
||||
virtual std::shared_ptr<PlatformMessageHandler> GetPlatformMessageHandler()
|
||||
const;
|
||||
|
||||
protected:
|
||||
PlatformView::Delegate& delegate_;
|
||||
const TaskRunners task_runners_;
|
||||
|
||||
@@ -625,7 +625,6 @@ bool Shell::Setup(std::unique_ptr<PlatformView> platform_view,
|
||||
}
|
||||
|
||||
platform_view_ = std::move(platform_view);
|
||||
platform_message_handler_ = platform_view_->GetPlatformMessageHandler();
|
||||
engine_ = std::move(engine);
|
||||
rasterizer_ = std::move(rasterizer);
|
||||
io_manager_ = std::move(io_manager);
|
||||
@@ -1193,17 +1192,13 @@ void Shell::OnEngineHandlePlatformMessage(
|
||||
return;
|
||||
}
|
||||
|
||||
if (platform_message_handler_) {
|
||||
platform_message_handler_->HandlePlatformMessage(std::move(message));
|
||||
} else {
|
||||
task_runners_.GetPlatformTaskRunner()->PostTask(
|
||||
fml::MakeCopyable([view = platform_view_->GetWeakPtr(),
|
||||
message = std::move(message)]() mutable {
|
||||
if (view) {
|
||||
view->HandlePlatformMessage(std::move(message));
|
||||
}
|
||||
}));
|
||||
}
|
||||
task_runners_.GetPlatformTaskRunner()->PostTask(
|
||||
fml::MakeCopyable([view = platform_view_->GetWeakPtr(),
|
||||
message = std::move(message)]() mutable {
|
||||
if (view) {
|
||||
view->HandlePlatformMessage(std::move(message));
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
void Shell::HandleEngineSkiaMessage(std::unique_ptr<PlatformMessage> message) {
|
||||
@@ -1872,9 +1867,4 @@ fml::TimePoint Shell::GetCurrentTimePoint() {
|
||||
return fml::TimePoint::Now();
|
||||
}
|
||||
|
||||
const std::shared_ptr<PlatformMessageHandler>&
|
||||
Shell::GetPlatformMessageHandler() const {
|
||||
return platform_message_handler_;
|
||||
}
|
||||
|
||||
} // namespace flutter
|
||||
|
||||
@@ -395,12 +395,6 @@ class Shell final : public PlatformView::Delegate,
|
||||
/// @see `CreateCompatibleGenerator`
|
||||
void RegisterImageDecoder(ImageGeneratorFactory factory, int32_t priority);
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
/// @brief Returns the delegate object that handles PlatformMessage's from
|
||||
/// Flutter to the host platform (and its responses).
|
||||
const std::shared_ptr<PlatformMessageHandler>& GetPlatformMessageHandler()
|
||||
const;
|
||||
|
||||
private:
|
||||
using ServiceProtocolHandler =
|
||||
std::function<bool(const ServiceProtocol::Handler::ServiceProtocolMap&,
|
||||
@@ -418,7 +412,6 @@ class Shell final : public PlatformView::Delegate,
|
||||
std::unique_ptr<ShellIOManager> io_manager_; // on IO task runner
|
||||
std::shared_ptr<fml::SyncSwitch> is_gpu_disabled_sync_switch_;
|
||||
std::shared_ptr<VolatilePathTracker> volatile_path_tracker_;
|
||||
std::shared_ptr<PlatformMessageHandler> platform_message_handler_;
|
||||
|
||||
fml::WeakPtr<Engine> weak_engine_; // to be shared across threads
|
||||
fml::TaskRunnerAffineWeakPtr<Rasterizer>
|
||||
|
||||
@@ -325,8 +325,7 @@ std::unique_ptr<Shell> ShellTest::CreateShell(
|
||||
std::shared_ptr<ShellTestExternalViewEmbedder>
|
||||
shell_test_external_view_embedder,
|
||||
bool is_gpu_disabled,
|
||||
ShellTestPlatformView::BackendType rendering_backend,
|
||||
Shell::CreateCallback<PlatformView> platform_view_create_callback) {
|
||||
ShellTestPlatformView::BackendType rendering_backend) {
|
||||
const auto vsync_clock = std::make_shared<ShellTestVsyncClock>();
|
||||
|
||||
CreateVsyncWaiter create_vsync_waiter = [&]() {
|
||||
@@ -339,21 +338,21 @@ std::unique_ptr<Shell> ShellTest::CreateShell(
|
||||
}
|
||||
};
|
||||
|
||||
if (!platform_view_create_callback) {
|
||||
platform_view_create_callback = [vsync_clock, //
|
||||
&create_vsync_waiter, //
|
||||
shell_test_external_view_embedder, //
|
||||
rendering_backend //
|
||||
](Shell& shell) {
|
||||
return ShellTestPlatformView::Create(shell, //
|
||||
shell.GetTaskRunners(), //
|
||||
vsync_clock, //
|
||||
std::move(create_vsync_waiter), //
|
||||
rendering_backend, //
|
||||
shell_test_external_view_embedder //
|
||||
);
|
||||
};
|
||||
}
|
||||
Shell::CreateCallback<PlatformView> platfrom_view_create_callback =
|
||||
[vsync_clock, //
|
||||
&create_vsync_waiter, //
|
||||
shell_test_external_view_embedder, //
|
||||
rendering_backend //
|
||||
](Shell& shell) {
|
||||
return ShellTestPlatformView::Create(
|
||||
shell, //
|
||||
shell.GetTaskRunners(), //
|
||||
vsync_clock, //
|
||||
std::move(create_vsync_waiter), //
|
||||
rendering_backend, //
|
||||
shell_test_external_view_embedder //
|
||||
);
|
||||
};
|
||||
|
||||
Shell::CreateCallback<Rasterizer> rasterizer_create_callback =
|
||||
[](Shell& shell) { return std::make_unique<Rasterizer>(shell); };
|
||||
@@ -361,7 +360,7 @@ std::unique_ptr<Shell> ShellTest::CreateShell(
|
||||
return Shell::Create(flutter::PlatformData(), //
|
||||
task_runners, //
|
||||
settings, //
|
||||
platform_view_create_callback, //
|
||||
platfrom_view_create_callback, //
|
||||
rasterizer_create_callback, //
|
||||
is_gpu_disabled //
|
||||
);
|
||||
|
||||
@@ -43,9 +43,7 @@ class ShellTest : public FixtureTest {
|
||||
shell_test_external_view_embedder = nullptr,
|
||||
bool is_gpu_disabled = false,
|
||||
ShellTestPlatformView::BackendType rendering_backend =
|
||||
ShellTestPlatformView::BackendType::kDefaultBackend,
|
||||
Shell::CreateCallback<PlatformView> platform_view_create_callback =
|
||||
nullptr);
|
||||
ShellTestPlatformView::BackendType::kDefaultBackend);
|
||||
void DestroyShell(std::unique_ptr<Shell> shell);
|
||||
void DestroyShell(std::unique_ptr<Shell> shell, TaskRunners task_runners);
|
||||
TaskRunners GetTaskRunnersForFixture();
|
||||
|
||||
@@ -45,10 +45,6 @@
|
||||
|
||||
namespace flutter {
|
||||
namespace testing {
|
||||
|
||||
using ::testing::_;
|
||||
using ::testing::Return;
|
||||
|
||||
namespace {
|
||||
class MockPlatformViewDelegate : public PlatformView::Delegate {
|
||||
MOCK_METHOD1(OnPlatformViewCreated, void(std::unique_ptr<Surface> surface));
|
||||
@@ -123,27 +119,6 @@ class MockPlatformView : public PlatformView {
|
||||
MockPlatformView(MockPlatformViewDelegate& delegate, TaskRunners task_runners)
|
||||
: PlatformView(delegate, task_runners) {}
|
||||
MOCK_METHOD0(CreateRenderingSurface, std::unique_ptr<Surface>());
|
||||
MOCK_CONST_METHOD0(GetPlatformMessageHandler,
|
||||
std::shared_ptr<PlatformMessageHandler>());
|
||||
};
|
||||
|
||||
class MockPlatformMessageHandler : public PlatformMessageHandler {
|
||||
public:
|
||||
MOCK_METHOD1(HandlePlatformMessage,
|
||||
void(std::unique_ptr<PlatformMessage> message));
|
||||
MOCK_METHOD2(InvokePlatformMessageResponseCallback,
|
||||
void(int response_id, std::unique_ptr<fml::Mapping> mapping));
|
||||
MOCK_METHOD1(InvokePlatformMessageEmptyResponseCallback,
|
||||
void(int response_id));
|
||||
};
|
||||
|
||||
class MockPlatformMessageResponse : public PlatformMessageResponse {
|
||||
public:
|
||||
static fml::RefPtr<MockPlatformMessageResponse> Create() {
|
||||
return fml::AdoptRef(new MockPlatformMessageResponse());
|
||||
}
|
||||
MOCK_METHOD1(Complete, void(std::unique_ptr<fml::Mapping> data));
|
||||
MOCK_METHOD0(CompleteEmpty, void());
|
||||
};
|
||||
} // namespace
|
||||
|
||||
@@ -3187,52 +3162,7 @@ TEST_F(ShellTest, UIWorkAfterOnPlatformViewDestroyed) {
|
||||
shell->GetTaskRunners().GetUITaskRunner(),
|
||||
[&ui_flush_latch]() { ui_flush_latch.Signal(); });
|
||||
ui_flush_latch.Wait();
|
||||
DestroyShell(std::move(shell));
|
||||
}
|
||||
|
||||
TEST_F(ShellTest, UsesPlatformMessageHandler) {
|
||||
TaskRunners task_runners = GetTaskRunnersForFixture();
|
||||
auto settings = CreateSettingsForFixture();
|
||||
MockPlatformViewDelegate platform_view_delegate;
|
||||
auto platform_message_handler =
|
||||
std::make_shared<MockPlatformMessageHandler>();
|
||||
int message_id = 1;
|
||||
EXPECT_CALL(*platform_message_handler, HandlePlatformMessage(_));
|
||||
EXPECT_CALL(*platform_message_handler,
|
||||
InvokePlatformMessageEmptyResponseCallback(message_id));
|
||||
Shell::CreateCallback<PlatformView> platform_view_create_callback =
|
||||
[&platform_view_delegate, task_runners,
|
||||
platform_message_handler](flutter::Shell& shell) {
|
||||
auto result = std::make_unique<MockPlatformView>(platform_view_delegate,
|
||||
task_runners);
|
||||
EXPECT_CALL(*result, GetPlatformMessageHandler())
|
||||
.WillOnce(Return(platform_message_handler));
|
||||
return result;
|
||||
};
|
||||
auto shell = CreateShell(
|
||||
/*settings=*/std::move(settings),
|
||||
/*task_runners=*/task_runners,
|
||||
/*simulate_vsync=*/false,
|
||||
/*shell_test_external_view_embedder=*/nullptr,
|
||||
/*is_gpu_disabled=*/false,
|
||||
/*rendering_backend=*/
|
||||
ShellTestPlatformView::BackendType::kDefaultBackend,
|
||||
/*platform_view_create_callback=*/platform_view_create_callback);
|
||||
|
||||
EXPECT_EQ(platform_message_handler, shell->GetPlatformMessageHandler());
|
||||
PostSync(task_runners.GetUITaskRunner(), [&shell]() {
|
||||
size_t data_size = 4;
|
||||
fml::MallocMapping bytes =
|
||||
fml::MallocMapping(static_cast<uint8_t*>(malloc(data_size)), data_size);
|
||||
fml::RefPtr<MockPlatformMessageResponse> response =
|
||||
MockPlatformMessageResponse::Create();
|
||||
auto message = std::make_unique<PlatformMessage>(
|
||||
/*channel=*/"foo", /*data=*/std::move(bytes), /*response=*/response);
|
||||
(static_cast<Engine::Delegate*>(shell.get()))
|
||||
->OnEngineHandlePlatformMessage(std::move(message));
|
||||
});
|
||||
shell->GetPlatformMessageHandler()
|
||||
->InvokePlatformMessageEmptyResponseCallback(message_id);
|
||||
DestroyShell(std::move(shell));
|
||||
}
|
||||
|
||||
|
||||
@@ -79,8 +79,6 @@ source_set("flutter_shell_native_src") {
|
||||
"flutter_main.cc",
|
||||
"flutter_main.h",
|
||||
"library_loader.cc",
|
||||
"platform_message_handler_android.cc",
|
||||
"platform_message_handler_android.h",
|
||||
"platform_message_response_android.cc",
|
||||
"platform_message_response_android.h",
|
||||
"platform_view_android.cc",
|
||||
@@ -188,7 +186,6 @@ android_java_sources = [
|
||||
"io/flutter/embedding/engine/dart/DartExecutor.java",
|
||||
"io/flutter/embedding/engine/dart/DartMessenger.java",
|
||||
"io/flutter/embedding/engine/dart/PlatformMessageHandler.java",
|
||||
"io/flutter/embedding/engine/dart/PlatformTaskQueue.java",
|
||||
"io/flutter/embedding/engine/deferredcomponents/DeferredComponentManager.java",
|
||||
"io/flutter/embedding/engine/deferredcomponents/PlayStoreDeferredComponentManager.java",
|
||||
"io/flutter/embedding/engine/loader/ApplicationInfoLoader.java",
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
#include "flutter/shell/common/shell.h"
|
||||
#include "flutter/shell/common/thread_host.h"
|
||||
#include "flutter/shell/platform/android/jni/platform_view_android_jni.h"
|
||||
#include "flutter/shell/platform/android/platform_message_handler_android.h"
|
||||
#include "flutter/shell/platform/android/platform_view_android.h"
|
||||
|
||||
namespace flutter {
|
||||
@@ -97,11 +96,6 @@ class AndroidShellHolder {
|
||||
|
||||
void NotifyLowMemoryWarning();
|
||||
|
||||
const std::shared_ptr<PlatformMessageHandler>& GetPlatformMessageHandler()
|
||||
const {
|
||||
return shell_->GetPlatformMessageHandler();
|
||||
}
|
||||
|
||||
private:
|
||||
const flutter::Settings settings_;
|
||||
const std::shared_ptr<PlatformViewAndroidJNI> jni_facade_;
|
||||
|
||||
@@ -7,7 +7,6 @@ namespace flutter {
|
||||
namespace testing {
|
||||
namespace {
|
||||
class MockPlatformViewAndroidJNI : public PlatformViewAndroidJNI {
|
||||
public:
|
||||
MOCK_METHOD2(FlutterViewHandlePlatformMessage,
|
||||
void(std::unique_ptr<flutter::PlatformMessage> message,
|
||||
int responseId));
|
||||
@@ -52,15 +51,6 @@ class MockPlatformViewAndroidJNI : public PlatformViewAndroidJNI {
|
||||
MOCK_METHOD0(GetDisplayRefreshRate, double());
|
||||
MOCK_METHOD1(RequestDartDeferredLibrary, bool(int loading_unit_id));
|
||||
};
|
||||
|
||||
class MockPlatformMessageResponse : public PlatformMessageResponse {
|
||||
public:
|
||||
static fml::RefPtr<MockPlatformMessageResponse> Create() {
|
||||
return fml::AdoptRef(new MockPlatformMessageResponse());
|
||||
}
|
||||
MOCK_METHOD1(Complete, void(std::unique_ptr<fml::Mapping> data));
|
||||
MOCK_METHOD0(CompleteEmpty, void());
|
||||
};
|
||||
} // namespace
|
||||
|
||||
TEST(AndroidShellHolder, Create) {
|
||||
@@ -75,34 +65,5 @@ TEST(AndroidShellHolder, Create) {
|
||||
nullptr, /*is_fake_window=*/true);
|
||||
holder->GetPlatformView()->NotifyCreated(window);
|
||||
}
|
||||
|
||||
TEST(AndroidShellHolder, HandlePlatformMessage) {
|
||||
Settings settings;
|
||||
settings.enable_software_rendering = false;
|
||||
auto jni = std::make_shared<MockPlatformViewAndroidJNI>();
|
||||
auto holder = std::make_unique<AndroidShellHolder>(settings, jni);
|
||||
EXPECT_NE(holder.get(), nullptr);
|
||||
EXPECT_TRUE(holder->IsValid());
|
||||
EXPECT_NE(holder->GetPlatformView().get(), nullptr);
|
||||
auto window = fml::MakeRefCounted<AndroidNativeWindow>(
|
||||
nullptr, /*is_fake_window=*/true);
|
||||
holder->GetPlatformView()->NotifyCreated(window);
|
||||
EXPECT_TRUE(holder->GetPlatformMessageHandler());
|
||||
size_t data_size = 4;
|
||||
fml::MallocMapping bytes =
|
||||
fml::MallocMapping(static_cast<uint8_t*>(malloc(data_size)), data_size);
|
||||
fml::RefPtr<MockPlatformMessageResponse> response =
|
||||
MockPlatformMessageResponse::Create();
|
||||
auto message = std::make_unique<PlatformMessage>(
|
||||
/*channel=*/"foo", /*data=*/std::move(bytes), /*response=*/response);
|
||||
int response_id = 1;
|
||||
EXPECT_CALL(*jni,
|
||||
FlutterViewHandlePlatformMessage(::testing::_, response_id));
|
||||
EXPECT_CALL(*response, CompleteEmpty());
|
||||
holder->GetPlatformMessageHandler()->HandlePlatformMessage(
|
||||
std::move(message));
|
||||
holder->GetPlatformMessageHandler()
|
||||
->InvokePlatformMessageEmptyResponseCallback(response_id);
|
||||
}
|
||||
} // namespace testing
|
||||
} // namespace flutter
|
||||
|
||||
@@ -41,7 +41,6 @@ import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CopyOnWriteArraySet;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
|
||||
/**
|
||||
* Interface between Flutter embedding's Java code and Flutter engine's C/C++ code.
|
||||
@@ -99,12 +98,6 @@ import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
@Keep
|
||||
public class FlutterJNI {
|
||||
private static final String TAG = "FlutterJNI";
|
||||
// This serializes the invocation of platform message responses and the
|
||||
// attachment and detachment of the shell holder. This ensures that we don't
|
||||
// detach FlutterJNI on the platform thread while a background thread invokes
|
||||
// a message response. Typically accessing the shell holder happens on the
|
||||
// platform thread and doesn't require locking.
|
||||
private ReentrantReadWriteLock shellHolderLock = new ReentrantReadWriteLock();
|
||||
|
||||
// BEGIN Methods related to loading for FlutterLoader.
|
||||
/**
|
||||
@@ -311,12 +304,7 @@ public class FlutterJNI {
|
||||
public void attachToNative() {
|
||||
ensureRunningOnMainThread();
|
||||
ensureNotAttachedToNative();
|
||||
shellHolderLock.writeLock().lock();
|
||||
try {
|
||||
nativeShellHolderId = performNativeAttach(this);
|
||||
} finally {
|
||||
shellHolderLock.writeLock().unlock();
|
||||
}
|
||||
nativeShellHolderId = performNativeAttach(this);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
@@ -380,13 +368,8 @@ public class FlutterJNI {
|
||||
public void detachFromNativeAndReleaseResources() {
|
||||
ensureRunningOnMainThread();
|
||||
ensureAttachedToNative();
|
||||
shellHolderLock.writeLock().lock();
|
||||
try {
|
||||
nativeDestroy(nativeShellHolderId);
|
||||
nativeShellHolderId = null;
|
||||
} finally {
|
||||
shellHolderLock.writeLock().unlock();
|
||||
}
|
||||
nativeDestroy(nativeShellHolderId);
|
||||
nativeShellHolderId = null;
|
||||
}
|
||||
|
||||
private native void nativeDestroy(long nativeShellHolderId);
|
||||
@@ -875,33 +858,14 @@ public class FlutterJNI {
|
||||
this.platformMessageHandler = platformMessageHandler;
|
||||
}
|
||||
|
||||
private native void nativeCleanupMessageData(long messageData);
|
||||
|
||||
/**
|
||||
* Destroys the resources provided sent to `handlePlatformMessage`.
|
||||
*
|
||||
* <p>This can be called on any thread.
|
||||
*
|
||||
* @param messageData the argument sent to handlePlatformMessage.
|
||||
*/
|
||||
public void cleanupMessageData(long messageData) {
|
||||
// This doesn't rely on being attached like other methods.
|
||||
nativeCleanupMessageData(messageData);
|
||||
}
|
||||
|
||||
// Called by native on the ui thread.
|
||||
// Called by native.
|
||||
// TODO(mattcarroll): determine if message is nonull or nullable
|
||||
@SuppressWarnings("unused")
|
||||
@VisibleForTesting
|
||||
public void handlePlatformMessage(
|
||||
@NonNull final String channel,
|
||||
ByteBuffer message,
|
||||
final int replyId,
|
||||
final long messageData) {
|
||||
@NonNull final String channel, ByteBuffer message, final int replyId) {
|
||||
if (platformMessageHandler != null) {
|
||||
platformMessageHandler.handleMessageFromDart(channel, message, replyId, messageData);
|
||||
} else {
|
||||
nativeCleanupMessageData(messageData);
|
||||
platformMessageHandler.handleMessageFromDart(channel, message, replyId);
|
||||
}
|
||||
// TODO(mattcarroll): log dropped messages when in debug mode
|
||||
// (https://github.com/flutter/flutter/issues/25391)
|
||||
@@ -967,20 +931,16 @@ public class FlutterJNI {
|
||||
int responseId);
|
||||
|
||||
// TODO(mattcarroll): differentiate between channel responses and platform responses.
|
||||
@UiThread
|
||||
public void invokePlatformMessageEmptyResponseCallback(int responseId) {
|
||||
// Called on any thread.
|
||||
shellHolderLock.readLock().lock();
|
||||
try {
|
||||
if (isAttached()) {
|
||||
nativeInvokePlatformMessageEmptyResponseCallback(nativeShellHolderId, responseId);
|
||||
} else {
|
||||
Log.w(
|
||||
TAG,
|
||||
"Tried to send a platform message response, but FlutterJNI was detached from native C++. Could not send. Response ID: "
|
||||
+ responseId);
|
||||
}
|
||||
} finally {
|
||||
shellHolderLock.readLock().unlock();
|
||||
ensureRunningOnMainThread();
|
||||
if (isAttached()) {
|
||||
nativeInvokePlatformMessageEmptyResponseCallback(nativeShellHolderId, responseId);
|
||||
} else {
|
||||
Log.w(
|
||||
TAG,
|
||||
"Tried to send a platform message response, but FlutterJNI was detached from native C++. Could not send. Response ID: "
|
||||
+ responseId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -989,25 +949,21 @@ public class FlutterJNI {
|
||||
long nativeShellHolderId, int responseId);
|
||||
|
||||
// TODO(mattcarroll): differentiate between channel responses and platform responses.
|
||||
@UiThread
|
||||
public void invokePlatformMessageResponseCallback(
|
||||
int responseId, @NonNull ByteBuffer message, int position) {
|
||||
// Called on any thread.
|
||||
ensureRunningOnMainThread();
|
||||
if (!message.isDirect()) {
|
||||
throw new IllegalArgumentException("Expected a direct ByteBuffer.");
|
||||
}
|
||||
shellHolderLock.readLock().lock();
|
||||
try {
|
||||
if (isAttached()) {
|
||||
nativeInvokePlatformMessageResponseCallback(
|
||||
nativeShellHolderId, responseId, message, position);
|
||||
} else {
|
||||
Log.w(
|
||||
TAG,
|
||||
"Tried to send a platform message response, but FlutterJNI was detached from native C++. Could not send. Response ID: "
|
||||
+ responseId);
|
||||
}
|
||||
} finally {
|
||||
shellHolderLock.readLock().unlock();
|
||||
if (isAttached()) {
|
||||
nativeInvokePlatformMessageResponseCallback(
|
||||
nativeShellHolderId, responseId, message, position);
|
||||
} else {
|
||||
Log.w(
|
||||
TAG,
|
||||
"Tried to send a platform message response, but FlutterJNI was detached from native C++. Could not send. Response ID: "
|
||||
+ responseId);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -59,7 +59,7 @@ public class DartExecutor implements BinaryMessenger {
|
||||
this.flutterJNI = flutterJNI;
|
||||
this.assetManager = assetManager;
|
||||
this.dartMessenger = new DartMessenger(flutterJNI);
|
||||
dartMessenger.setMessageHandler("flutter/isolate", isolateChannelMessageHandler, null);
|
||||
dartMessenger.setMessageHandler("flutter/isolate", isolateChannelMessageHandler);
|
||||
this.binaryMessenger = new DefaultBinaryMessenger(dartMessenger);
|
||||
// The JNI might already be attached if coming from a spawned engine. If so, correctly report
|
||||
// that this DartExecutor is already running.
|
||||
@@ -168,14 +168,6 @@ public class DartExecutor implements BinaryMessenger {
|
||||
}
|
||||
|
||||
// ------ START BinaryMessenger (Deprecated: use getBinaryMessenger() instead) -----
|
||||
/** @deprecated Use {@link #getBinaryMessenger()} instead. */
|
||||
@Deprecated
|
||||
@UiThread
|
||||
@Override
|
||||
public TaskQueue makeBackgroundTaskQueue() {
|
||||
return binaryMessenger.makeBackgroundTaskQueue();
|
||||
}
|
||||
|
||||
/** @deprecated Use {@link #getBinaryMessenger()} instead. */
|
||||
@Deprecated
|
||||
@Override
|
||||
@@ -200,10 +192,8 @@ public class DartExecutor implements BinaryMessenger {
|
||||
@Override
|
||||
@UiThread
|
||||
public void setMessageHandler(
|
||||
@NonNull String channel,
|
||||
@Nullable BinaryMessenger.BinaryMessageHandler handler,
|
||||
@Nullable TaskQueue taskQueue) {
|
||||
binaryMessenger.setMessageHandler(channel, handler, taskQueue);
|
||||
@NonNull String channel, @Nullable BinaryMessenger.BinaryMessageHandler handler) {
|
||||
binaryMessenger.setMessageHandler(channel, handler);
|
||||
}
|
||||
// ------ END BinaryMessenger -----
|
||||
|
||||
@@ -381,10 +371,6 @@ public class DartExecutor implements BinaryMessenger {
|
||||
this.messenger = messenger;
|
||||
}
|
||||
|
||||
public TaskQueue makeBackgroundTaskQueue() {
|
||||
return messenger.makeBackgroundTaskQueue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the given {@code message} from Android to Dart over the given {@code channel}.
|
||||
*
|
||||
@@ -427,10 +413,8 @@ public class DartExecutor implements BinaryMessenger {
|
||||
@Override
|
||||
@UiThread
|
||||
public void setMessageHandler(
|
||||
@NonNull String channel,
|
||||
@Nullable BinaryMessenger.BinaryMessageHandler handler,
|
||||
@Nullable TaskQueue taskQueue) {
|
||||
messenger.setMessageHandler(channel, handler, taskQueue);
|
||||
@NonNull String channel, @Nullable BinaryMessenger.BinaryMessageHandler handler) {
|
||||
messenger.setMessageHandler(channel, handler);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,11 +13,6 @@ import io.flutter.plugin.common.BinaryMessenger;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.WeakHashMap;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
/**
|
||||
@@ -31,104 +26,25 @@ class DartMessenger implements BinaryMessenger, PlatformMessageHandler {
|
||||
private static final String TAG = "DartMessenger";
|
||||
|
||||
@NonNull private final FlutterJNI flutterJNI;
|
||||
|
||||
@NonNull private final ConcurrentHashMap<String, HandlerInfo> messageHandlers;
|
||||
|
||||
@NonNull private final Map<String, BinaryMessenger.BinaryMessageHandler> messageHandlers;
|
||||
@NonNull private final Map<Integer, BinaryMessenger.BinaryReply> pendingReplies;
|
||||
private int nextReplyId = 1;
|
||||
|
||||
@NonNull private final DartMessengerTaskQueue platformTaskQueue = new PlatformTaskQueue();
|
||||
|
||||
@NonNull private WeakHashMap<TaskQueue, DartMessengerTaskQueue> createdTaskQueues;
|
||||
|
||||
@NonNull private TaskQueueFactory taskQueueFactory;
|
||||
|
||||
DartMessenger(@NonNull FlutterJNI flutterJNI, @NonNull TaskQueueFactory taskQueueFactory) {
|
||||
this.flutterJNI = flutterJNI;
|
||||
this.messageHandlers = new ConcurrentHashMap<>();
|
||||
this.pendingReplies = new HashMap<>();
|
||||
this.createdTaskQueues = new WeakHashMap<TaskQueue, DartMessengerTaskQueue>();
|
||||
this.taskQueueFactory = taskQueueFactory;
|
||||
}
|
||||
|
||||
DartMessenger(@NonNull FlutterJNI flutterJNI) {
|
||||
this(flutterJNI, new DefaultTaskQueueFactory());
|
||||
}
|
||||
|
||||
private static class TaskQueueToken implements TaskQueue {}
|
||||
|
||||
interface DartMessengerTaskQueue {
|
||||
void dispatch(@NonNull Runnable runnable);
|
||||
}
|
||||
|
||||
interface TaskQueueFactory {
|
||||
DartMessengerTaskQueue makeBackgroundTaskQueue();
|
||||
}
|
||||
|
||||
private static class DefaultTaskQueueFactory implements TaskQueueFactory {
|
||||
public DartMessengerTaskQueue makeBackgroundTaskQueue() {
|
||||
return new DefaultTaskQueue();
|
||||
}
|
||||
}
|
||||
|
||||
private static class HandlerInfo {
|
||||
@NonNull public final BinaryMessenger.BinaryMessageHandler handler;
|
||||
@Nullable public final DartMessengerTaskQueue taskQueue;
|
||||
|
||||
HandlerInfo(
|
||||
@NonNull BinaryMessenger.BinaryMessageHandler handler,
|
||||
@Nullable DartMessengerTaskQueue taskQueue) {
|
||||
this.handler = handler;
|
||||
this.taskQueue = taskQueue;
|
||||
}
|
||||
}
|
||||
|
||||
private static class DefaultTaskQueue implements DartMessengerTaskQueue {
|
||||
@NonNull private final ExecutorService executor;
|
||||
|
||||
DefaultTaskQueue() {
|
||||
// TODO(gaaclarke): Use a shared thread pool with serial queues instead of
|
||||
// making a thread for each TaskQueue.
|
||||
ThreadFactory threadFactory =
|
||||
(Runnable runnable) -> {
|
||||
return new Thread(runnable, "DartMessenger.DefaultTaskQueue");
|
||||
};
|
||||
this.executor = Executors.newSingleThreadExecutor(threadFactory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispatch(@NonNull Runnable runnable) {
|
||||
executor.execute(runnable);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskQueue makeBackgroundTaskQueue() {
|
||||
DartMessengerTaskQueue taskQueue = taskQueueFactory.makeBackgroundTaskQueue();
|
||||
TaskQueueToken token = new TaskQueueToken();
|
||||
createdTaskQueues.put(token, taskQueue);
|
||||
return token;
|
||||
this.flutterJNI = flutterJNI;
|
||||
this.messageHandlers = new HashMap<>();
|
||||
this.pendingReplies = new HashMap<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMessageHandler(
|
||||
@NonNull String channel,
|
||||
@Nullable BinaryMessenger.BinaryMessageHandler handler,
|
||||
@Nullable TaskQueue taskQueue) {
|
||||
@NonNull String channel, @Nullable BinaryMessenger.BinaryMessageHandler handler) {
|
||||
if (handler == null) {
|
||||
Log.v(TAG, "Removing handler for channel '" + channel + "'");
|
||||
messageHandlers.remove(channel);
|
||||
} else {
|
||||
DartMessengerTaskQueue dartMessengerTaskQueue = null;
|
||||
if (taskQueue != null) {
|
||||
dartMessengerTaskQueue = createdTaskQueues.get(taskQueue);
|
||||
if (dartMessengerTaskQueue == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Unrecognized TaskQueue, use BinaryMessenger to create your TaskQueue (ex makeBackgroundTaskQueue).");
|
||||
}
|
||||
}
|
||||
Log.v(TAG, "Setting handler for channel '" + channel + "'");
|
||||
messageHandlers.put(channel, new HandlerInfo(handler, dartMessengerTaskQueue));
|
||||
messageHandlers.put(channel, handler);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,13 +72,20 @@ class DartMessenger implements BinaryMessenger, PlatformMessageHandler {
|
||||
}
|
||||
}
|
||||
|
||||
private void invokeHandler(
|
||||
@Nullable HandlerInfo handlerInfo, @Nullable ByteBuffer message, final int replyId) {
|
||||
// Called from any thread.
|
||||
if (handlerInfo != null) {
|
||||
@Override
|
||||
public void handleMessageFromDart(
|
||||
@NonNull final String channel, @Nullable ByteBuffer message, final int replyId) {
|
||||
Log.v(TAG, "Received message from Dart over channel '" + channel + "'");
|
||||
BinaryMessenger.BinaryMessageHandler handler = messageHandlers.get(channel);
|
||||
if (handler != null) {
|
||||
try {
|
||||
Log.v(TAG, "Deferring to registered handler to process message.");
|
||||
handlerInfo.handler.onMessage(message, new Reply(flutterJNI, replyId));
|
||||
handler.onMessage(message, new Reply(flutterJNI, replyId));
|
||||
if (message != null && message.isDirect()) {
|
||||
// This ensures that if a user retains an instance to the ByteBuffer and it happens to
|
||||
// be direct they will get a deterministic error.
|
||||
message.limit(0);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
Log.e(TAG, "Uncaught exception in binary message listener", ex);
|
||||
flutterJNI.invokePlatformMessageEmptyResponseCallback(replyId);
|
||||
@@ -175,37 +98,6 @@ class DartMessenger implements BinaryMessenger, PlatformMessageHandler {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMessageFromDart(
|
||||
@NonNull final String channel,
|
||||
@Nullable ByteBuffer message,
|
||||
final int replyId,
|
||||
long messageData) {
|
||||
// Called from the ui thread.
|
||||
Log.v(TAG, "Received message from Dart over channel '" + channel + "'");
|
||||
@Nullable final HandlerInfo handlerInfo = messageHandlers.get(channel);
|
||||
@Nullable
|
||||
final DartMessengerTaskQueue taskQueue = (handlerInfo != null) ? handlerInfo.taskQueue : null;
|
||||
Runnable myRunnable =
|
||||
() -> {
|
||||
try {
|
||||
invokeHandler(handlerInfo, message, replyId);
|
||||
if (message != null && message.isDirect()) {
|
||||
// This ensures that if a user retains an instance to the ByteBuffer and it happens to
|
||||
// be direct they will get a deterministic error.
|
||||
message.limit(0);
|
||||
}
|
||||
} finally {
|
||||
// This is deleting the data underneath the message object.
|
||||
flutterJNI.cleanupMessageData(messageData);
|
||||
}
|
||||
};
|
||||
@NonNull
|
||||
final DartMessengerTaskQueue nonnullTaskQueue =
|
||||
taskQueue == null ? platformTaskQueue : taskQueue;
|
||||
nonnullTaskQueue.dispatch(myRunnable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handlePlatformMessageResponse(int replyId, @Nullable ByteBuffer reply) {
|
||||
Log.v(TAG, "Received message reply from Dart.");
|
||||
|
||||
@@ -11,10 +11,7 @@ import java.nio.ByteBuffer;
|
||||
/** Handler that receives messages from Dart code. */
|
||||
public interface PlatformMessageHandler {
|
||||
void handleMessageFromDart(
|
||||
@NonNull final String channel,
|
||||
@Nullable ByteBuffer message,
|
||||
final int replyId,
|
||||
long messageData);
|
||||
@NonNull final String channel, @Nullable ByteBuffer message, final int replyId);
|
||||
|
||||
void handlePlatformMessageResponse(int replyId, @Nullable ByteBuffer reply);
|
||||
}
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
// Copyright 2013 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.
|
||||
|
||||
package io.flutter.embedding.engine.dart;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
/** A BinaryMessenger.TaskQueue that posts to the platform thread (aka main thread). */
|
||||
public class PlatformTaskQueue implements DartMessenger.DartMessengerTaskQueue {
|
||||
@NonNull private final Handler handler = new Handler(Looper.getMainLooper());
|
||||
|
||||
@Override
|
||||
public void dispatch(@NonNull Runnable runnable) {
|
||||
handler.post(runnable);
|
||||
}
|
||||
}
|
||||
@@ -36,7 +36,6 @@ public final class BasicMessageChannel<T> {
|
||||
@NonNull private final BinaryMessenger messenger;
|
||||
@NonNull private final String name;
|
||||
@NonNull private final MessageCodec<T> codec;
|
||||
@Nullable private final BinaryMessenger.TaskQueue taskQueue;
|
||||
|
||||
/**
|
||||
* Creates a new channel associated with the specified {@link BinaryMessenger} and with the
|
||||
@@ -48,25 +47,6 @@ public final class BasicMessageChannel<T> {
|
||||
*/
|
||||
public BasicMessageChannel(
|
||||
@NonNull BinaryMessenger messenger, @NonNull String name, @NonNull MessageCodec<T> codec) {
|
||||
this(messenger, name, codec, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new channel associated with the specified {@link BinaryMessenger} and with the
|
||||
* specified name and {@link MessageCodec}.
|
||||
*
|
||||
* @param messenger a {@link BinaryMessenger}.
|
||||
* @param name a channel name String.
|
||||
* @param codec a {@link MessageCodec}.
|
||||
* @param taskQueue a {@link BinaryMessenger.TaskQueue} that specifies what thread will execute
|
||||
* the handler. Specifying null means execute on the platform thread. See also {@link
|
||||
* BinaryMessenger#makeBackgroundTaskQueue()}.
|
||||
*/
|
||||
public BasicMessageChannel(
|
||||
@NonNull BinaryMessenger messenger,
|
||||
@NonNull String name,
|
||||
@NonNull MessageCodec<T> codec,
|
||||
BinaryMessenger.TaskQueue taskQueue) {
|
||||
if (BuildConfig.DEBUG) {
|
||||
if (messenger == null) {
|
||||
Log.e(TAG, "Parameter messenger must not be null.");
|
||||
@@ -81,7 +61,6 @@ public final class BasicMessageChannel<T> {
|
||||
this.messenger = messenger;
|
||||
this.name = name;
|
||||
this.codec = codec;
|
||||
this.taskQueue = taskQueue;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -122,8 +101,7 @@ public final class BasicMessageChannel<T> {
|
||||
*/
|
||||
@UiThread
|
||||
public void setMessageHandler(@Nullable final MessageHandler<T> handler) {
|
||||
messenger.setMessageHandler(
|
||||
name, handler == null ? null : new IncomingMessageHandler(handler), taskQueue);
|
||||
messenger.setMessageHandler(name, handler == null ? null : new IncomingMessageHandler(handler));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -26,24 +26,6 @@ import java.nio.ByteBuffer;
|
||||
* @see EventChannel , which supports communication using event streams.
|
||||
*/
|
||||
public interface BinaryMessenger {
|
||||
/**
|
||||
* An abstraction over the threading policy used to invoke message handlers.
|
||||
*
|
||||
* <p>These are generated by calling methods like {@link
|
||||
* BinaryMessenger#makeBackgroundTaskQueue()} and can be passed into platform channels'
|
||||
* constructors to control the threading policy for handling platform channels' messages.
|
||||
*/
|
||||
public interface TaskQueue {}
|
||||
|
||||
/**
|
||||
* Creates a TaskQueue that executes the tasks serially on a background thread.
|
||||
*
|
||||
* <p>There is no guarantee that the tasks will execute on the same thread, just that execution is
|
||||
* serial.
|
||||
*/
|
||||
@UiThread
|
||||
TaskQueue makeBackgroundTaskQueue();
|
||||
|
||||
/**
|
||||
* Sends a binary message to the Flutter application.
|
||||
*
|
||||
@@ -80,14 +62,9 @@ public interface BinaryMessenger {
|
||||
*
|
||||
* @param channel the name {@link String} of the channel.
|
||||
* @param handler a {@link BinaryMessageHandler} to be invoked on incoming messages, or null.
|
||||
* @param taskQueue a {@link BinaryMessenger.TaskQueue} that specifies what thread will execute
|
||||
* the handler. Specifying null means execute on the platform thread.
|
||||
*/
|
||||
@UiThread
|
||||
void setMessageHandler(
|
||||
@NonNull String channel,
|
||||
@Nullable BinaryMessageHandler handler,
|
||||
@Nullable TaskQueue taskQueue);
|
||||
void setMessageHandler(@NonNull String channel, @Nullable BinaryMessageHandler handler);
|
||||
|
||||
/** Handler for incoming binary messages from Flutter. */
|
||||
interface BinaryMessageHandler {
|
||||
@@ -120,6 +97,7 @@ public interface BinaryMessenger {
|
||||
* outgoing replies must place the reply bytes between position zero and current position.
|
||||
* Reply receivers can read from the buffer directly.
|
||||
*/
|
||||
@UiThread
|
||||
void reply(@Nullable ByteBuffer reply);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
|
||||
package io.flutter.plugin.common;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.UiThread;
|
||||
import io.flutter.BuildConfig;
|
||||
import io.flutter.Log;
|
||||
@@ -35,7 +34,6 @@ public final class EventChannel {
|
||||
private final BinaryMessenger messenger;
|
||||
private final String name;
|
||||
private final MethodCodec codec;
|
||||
@Nullable private final BinaryMessenger.TaskQueue taskQueue;
|
||||
|
||||
/**
|
||||
* Creates a new channel associated with the specified {@link BinaryMessenger} and with the
|
||||
@@ -57,25 +55,6 @@ public final class EventChannel {
|
||||
* @param codec a {@link MessageCodec}.
|
||||
*/
|
||||
public EventChannel(BinaryMessenger messenger, String name, MethodCodec codec) {
|
||||
this(messenger, name, codec, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new channel associated with the specified {@link BinaryMessenger} and with the
|
||||
* specified name and {@link MethodCodec}.
|
||||
*
|
||||
* @param messenger a {@link BinaryMessenger}.
|
||||
* @param name a channel name String.
|
||||
* @param codec a {@link MessageCodec}.
|
||||
* @param taskQueue a {@link BinaryMessenger.TaskQueue} that specifies what thread will execute
|
||||
* the handler. Specifying null means execute on the platform thread. See also {@link
|
||||
* BinaryMessenger#makeBackgroundTaskQueue()}.
|
||||
*/
|
||||
public EventChannel(
|
||||
BinaryMessenger messenger,
|
||||
String name,
|
||||
MethodCodec codec,
|
||||
BinaryMessenger.TaskQueue taskQueue) {
|
||||
if (BuildConfig.DEBUG) {
|
||||
if (messenger == null) {
|
||||
Log.e(TAG, "Parameter messenger must not be null.");
|
||||
@@ -90,7 +69,6 @@ public final class EventChannel {
|
||||
this.messenger = messenger;
|
||||
this.name = name;
|
||||
this.codec = codec;
|
||||
this.taskQueue = taskQueue;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -106,7 +84,7 @@ public final class EventChannel {
|
||||
@UiThread
|
||||
public void setStreamHandler(final StreamHandler handler) {
|
||||
messenger.setMessageHandler(
|
||||
name, handler == null ? null : new IncomingStreamRequestHandler(handler), taskQueue);
|
||||
name, handler == null ? null : new IncomingStreamRequestHandler(handler));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -35,7 +35,6 @@ public class MethodChannel {
|
||||
private final BinaryMessenger messenger;
|
||||
private final String name;
|
||||
private final MethodCodec codec;
|
||||
private final BinaryMessenger.TaskQueue taskQueue;
|
||||
|
||||
/**
|
||||
* Creates a new channel associated with the specified {@link BinaryMessenger} and with the
|
||||
@@ -57,25 +56,6 @@ public class MethodChannel {
|
||||
* @param codec a {@link MessageCodec}.
|
||||
*/
|
||||
public MethodChannel(BinaryMessenger messenger, String name, MethodCodec codec) {
|
||||
this(messenger, name, codec, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new channel associated with the specified {@link BinaryMessenger} and with the
|
||||
* specified name and {@link MethodCodec}.
|
||||
*
|
||||
* @param messenger a {@link BinaryMessenger}.
|
||||
* @param name a channel name String.
|
||||
* @param codec a {@link MessageCodec}.
|
||||
* @param taskQueue a {@link BinaryMessenger.TaskQueue} that specifies what thread will execute
|
||||
* the handler. Specifying null means execute on the platform thread. See also {@link
|
||||
* BinaryMessenger#makeBackgroundTaskQueue()}.
|
||||
*/
|
||||
public MethodChannel(
|
||||
BinaryMessenger messenger,
|
||||
String name,
|
||||
MethodCodec codec,
|
||||
@Nullable BinaryMessenger.TaskQueue taskQueue) {
|
||||
if (BuildConfig.DEBUG) {
|
||||
if (messenger == null) {
|
||||
Log.e(TAG, "Parameter messenger must not be null.");
|
||||
@@ -90,7 +70,6 @@ public class MethodChannel {
|
||||
this.messenger = messenger;
|
||||
this.name = name;
|
||||
this.codec = codec;
|
||||
this.taskQueue = taskQueue;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -138,7 +117,7 @@ public class MethodChannel {
|
||||
@UiThread
|
||||
public void setMethodCallHandler(final @Nullable MethodCallHandler handler) {
|
||||
messenger.setMessageHandler(
|
||||
name, handler == null ? null : new IncomingMethodCallHandler(handler), taskQueue);
|
||||
name, handler == null ? null : new IncomingMethodCallHandler(handler));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -124,12 +124,6 @@ public class FlutterNativeView implements BinaryMessenger {
|
||||
return FlutterJNI.getObservatoryUri();
|
||||
}
|
||||
|
||||
@Override
|
||||
@UiThread
|
||||
public TaskQueue makeBackgroundTaskQueue() {
|
||||
return dartExecutor.getBinaryMessenger().makeBackgroundTaskQueue();
|
||||
}
|
||||
|
||||
@Override
|
||||
@UiThread
|
||||
public void send(String channel, ByteBuffer message) {
|
||||
@@ -149,8 +143,8 @@ public class FlutterNativeView implements BinaryMessenger {
|
||||
|
||||
@Override
|
||||
@UiThread
|
||||
public void setMessageHandler(String channel, BinaryMessageHandler handler, TaskQueue taskQueue) {
|
||||
dartExecutor.getBinaryMessenger().setMessageHandler(channel, handler, taskQueue);
|
||||
public void setMessageHandler(String channel, BinaryMessageHandler handler) {
|
||||
dartExecutor.getBinaryMessenger().setMessageHandler(channel, handler);
|
||||
}
|
||||
|
||||
/*package*/ FlutterJNI getFlutterJNI() {
|
||||
|
||||
@@ -822,12 +822,6 @@ public class FlutterView extends SurfaceView
|
||||
return PointerIcon.getSystemIcon(getContext(), type);
|
||||
}
|
||||
|
||||
@Override
|
||||
@UiThread
|
||||
public TaskQueue makeBackgroundTaskQueue() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@UiThread
|
||||
public void send(String channel, ByteBuffer message) {
|
||||
@@ -846,8 +840,8 @@ public class FlutterView extends SurfaceView
|
||||
|
||||
@Override
|
||||
@UiThread
|
||||
public void setMessageHandler(String channel, BinaryMessageHandler handler, TaskQueue taskQueue) {
|
||||
mNativeView.setMessageHandler(channel, handler, taskQueue);
|
||||
public void setMessageHandler(String channel, BinaryMessageHandler handler) {
|
||||
mNativeView.setMessageHandler(channel, handler);
|
||||
}
|
||||
|
||||
/** Listener will be called on the Android UI thread once when Flutter renders the first frame. */
|
||||
|
||||
@@ -1,64 +0,0 @@
|
||||
|
||||
#include "flutter/shell/platform/android/platform_message_handler_android.h"
|
||||
|
||||
namespace flutter {
|
||||
|
||||
PlatformMessageHandlerAndroid::PlatformMessageHandlerAndroid(
|
||||
const std::shared_ptr<PlatformViewAndroidJNI>& jni_facade)
|
||||
: jni_facade_(jni_facade) {}
|
||||
|
||||
void PlatformMessageHandlerAndroid::InvokePlatformMessageResponseCallback(
|
||||
int response_id,
|
||||
std::unique_ptr<fml::Mapping> mapping) {
|
||||
// Called from any thread.
|
||||
if (!response_id) {
|
||||
return;
|
||||
}
|
||||
// TODO(gaaclarke): Move the jump to the ui thread here from
|
||||
// PlatformMessageResponseDart so we won't need to use a mutex anymore.
|
||||
fml::RefPtr<flutter::PlatformMessageResponse> message_response;
|
||||
{
|
||||
std::lock_guard lock(pending_responses_mutex_);
|
||||
auto it = pending_responses_.find(response_id);
|
||||
if (it == pending_responses_.end())
|
||||
return;
|
||||
message_response = std::move(it->second);
|
||||
pending_responses_.erase(it);
|
||||
}
|
||||
|
||||
message_response->Complete(std::move(mapping));
|
||||
}
|
||||
|
||||
void PlatformMessageHandlerAndroid::InvokePlatformMessageEmptyResponseCallback(
|
||||
int response_id) {
|
||||
// Called from any thread.
|
||||
if (!response_id) {
|
||||
return;
|
||||
}
|
||||
fml::RefPtr<flutter::PlatformMessageResponse> message_response;
|
||||
{
|
||||
std::lock_guard lock(pending_responses_mutex_);
|
||||
auto it = pending_responses_.find(response_id);
|
||||
if (it == pending_responses_.end())
|
||||
return;
|
||||
message_response = std::move(it->second);
|
||||
pending_responses_.erase(it);
|
||||
}
|
||||
message_response->CompleteEmpty();
|
||||
}
|
||||
|
||||
// |PlatformView|
|
||||
void PlatformMessageHandlerAndroid::HandlePlatformMessage(
|
||||
std::unique_ptr<flutter::PlatformMessage> message) {
|
||||
// Called from the ui thread.
|
||||
int response_id = next_response_id_++;
|
||||
if (auto response = message->response()) {
|
||||
std::lock_guard lock(pending_responses_mutex_);
|
||||
pending_responses_[response_id] = response;
|
||||
}
|
||||
// This call can re-enter in InvokePlatformMessageXxxResponseCallback.
|
||||
jni_facade_->FlutterViewHandlePlatformMessage(std::move(message),
|
||||
response_id);
|
||||
}
|
||||
|
||||
} // namespace flutter
|
||||
@@ -1,38 +0,0 @@
|
||||
// Copyright 2013 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.
|
||||
|
||||
#ifndef SHELL_PLATFORM_ANDROID_PLATFORM_MESSAGE_HANDLER_H_
|
||||
#define SHELL_PLATFORM_ANDROID_PLATFORM_MESSAGE_HANDLER_H_
|
||||
|
||||
#include <jni.h>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "flutter/lib/ui/window/platform_message.h"
|
||||
#include "flutter/shell/common/platform_message_handler.h"
|
||||
#include "flutter/shell/platform/android/jni/platform_view_android_jni.h"
|
||||
|
||||
namespace flutter {
|
||||
class PlatformMessageHandlerAndroid : public PlatformMessageHandler {
|
||||
public:
|
||||
PlatformMessageHandlerAndroid(
|
||||
const std::shared_ptr<PlatformViewAndroidJNI>& jni_facade);
|
||||
void HandlePlatformMessage(std::unique_ptr<PlatformMessage> message) override;
|
||||
void InvokePlatformMessageResponseCallback(
|
||||
int response_id,
|
||||
std::unique_ptr<fml::Mapping> mapping) override;
|
||||
|
||||
void InvokePlatformMessageEmptyResponseCallback(int response_id) override;
|
||||
|
||||
private:
|
||||
const std::shared_ptr<PlatformViewAndroidJNI> jni_facade_;
|
||||
int next_response_id_ = 1;
|
||||
std::unordered_map<int, fml::RefPtr<flutter::PlatformMessageResponse>>
|
||||
pending_responses_;
|
||||
std::mutex pending_responses_mutex_;
|
||||
};
|
||||
} // namespace flutter
|
||||
|
||||
#endif
|
||||
@@ -73,8 +73,7 @@ PlatformViewAndroid::PlatformViewAndroid(
|
||||
: PlatformView(delegate, std::move(task_runners)),
|
||||
jni_facade_(jni_facade),
|
||||
android_context_(std::move(android_context)),
|
||||
platform_view_android_delegate_(jni_facade),
|
||||
platform_message_handler_(new PlatformMessageHandlerAndroid(jni_facade)) {
|
||||
platform_view_android_delegate_(jni_facade) {
|
||||
// TODO(dnfield): always create a pbuffer surface for background use to
|
||||
// resolve https://github.com/flutter/flutter/issues/73675
|
||||
if (android_context_) {
|
||||
@@ -191,11 +190,51 @@ void PlatformViewAndroid::DispatchEmptyPlatformMessage(JNIEnv* env,
|
||||
std::move(response)));
|
||||
}
|
||||
|
||||
void PlatformViewAndroid::InvokePlatformMessageResponseCallback(
|
||||
JNIEnv* env,
|
||||
jint response_id,
|
||||
jobject java_response_data,
|
||||
jint java_response_position) {
|
||||
if (!response_id)
|
||||
return;
|
||||
auto it = pending_responses_.find(response_id);
|
||||
if (it == pending_responses_.end())
|
||||
return;
|
||||
uint8_t* response_data =
|
||||
static_cast<uint8_t*>(env->GetDirectBufferAddress(java_response_data));
|
||||
FML_DCHECK(response_data != nullptr);
|
||||
std::vector<uint8_t> response = std::vector<uint8_t>(
|
||||
response_data, response_data + java_response_position);
|
||||
auto message_response = std::move(it->second);
|
||||
pending_responses_.erase(it);
|
||||
message_response->Complete(
|
||||
std::make_unique<fml::DataMapping>(std::move(response)));
|
||||
}
|
||||
|
||||
void PlatformViewAndroid::InvokePlatformMessageEmptyResponseCallback(
|
||||
JNIEnv* env,
|
||||
jint response_id) {
|
||||
if (!response_id)
|
||||
return;
|
||||
auto it = pending_responses_.find(response_id);
|
||||
if (it == pending_responses_.end())
|
||||
return;
|
||||
auto message_response = std::move(it->second);
|
||||
pending_responses_.erase(it);
|
||||
message_response->CompleteEmpty();
|
||||
}
|
||||
|
||||
// |PlatformView|
|
||||
void PlatformViewAndroid::HandlePlatformMessage(
|
||||
std::unique_ptr<flutter::PlatformMessage> message) {
|
||||
// Called from the ui thread.
|
||||
platform_message_handler_->HandlePlatformMessage(std::move(message));
|
||||
int response_id = next_response_id_++;
|
||||
if (auto response = message->response()) {
|
||||
pending_responses_[response_id] = response;
|
||||
}
|
||||
// This call can re-enter in InvokePlatformMessageXxxResponseCallback.
|
||||
jni_facade_->FlutterViewHandlePlatformMessage(std::move(message),
|
||||
response_id);
|
||||
message = nullptr;
|
||||
}
|
||||
|
||||
// |PlatformView|
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
#include "flutter/shell/common/snapshot_surface_producer.h"
|
||||
#include "flutter/shell/platform/android/context/android_context.h"
|
||||
#include "flutter/shell/platform/android/jni/platform_view_android_jni.h"
|
||||
#include "flutter/shell/platform/android/platform_message_handler_android.h"
|
||||
#include "flutter/shell/platform/android/platform_view_android_delegate/platform_view_android_delegate.h"
|
||||
#include "flutter/shell/platform/android/surface/android_native_window.h"
|
||||
#include "flutter/shell/platform/android/surface/android_surface.h"
|
||||
@@ -80,6 +79,14 @@ class PlatformViewAndroid final : public PlatformView {
|
||||
std::string name,
|
||||
jint response_id);
|
||||
|
||||
void InvokePlatformMessageResponseCallback(JNIEnv* env,
|
||||
jint response_id,
|
||||
jobject java_response_data,
|
||||
jint java_response_position);
|
||||
|
||||
void InvokePlatformMessageEmptyResponseCallback(JNIEnv* env,
|
||||
jint response_id);
|
||||
|
||||
void DispatchSemanticsAction(JNIEnv* env,
|
||||
jint id,
|
||||
jint action,
|
||||
@@ -109,11 +116,6 @@ class PlatformViewAndroid final : public PlatformView {
|
||||
return android_context_;
|
||||
}
|
||||
|
||||
std::shared_ptr<PlatformMessageHandler> GetPlatformMessageHandler()
|
||||
const override {
|
||||
return platform_message_handler_;
|
||||
}
|
||||
|
||||
private:
|
||||
const std::shared_ptr<PlatformViewAndroidJNI> jni_facade_;
|
||||
std::shared_ptr<AndroidContext> android_context_;
|
||||
@@ -122,7 +124,11 @@ class PlatformViewAndroid final : public PlatformView {
|
||||
PlatformViewAndroidDelegate platform_view_android_delegate_;
|
||||
|
||||
std::unique_ptr<AndroidSurface> android_surface_;
|
||||
std::shared_ptr<PlatformMessageHandlerAndroid> platform_message_handler_;
|
||||
|
||||
// We use id 0 to mean that no response is expected.
|
||||
int next_response_id_ = 1;
|
||||
std::unordered_map<int, fml::RefPtr<flutter::PlatformMessageResponse>>
|
||||
pending_responses_;
|
||||
|
||||
// |PlatformView|
|
||||
void UpdateSemantics(
|
||||
|
||||
@@ -405,13 +405,6 @@ static void DispatchEmptyPlatformMessage(JNIEnv* env,
|
||||
);
|
||||
}
|
||||
|
||||
static void CleanupMessageData(JNIEnv* env,
|
||||
jobject jcaller,
|
||||
jlong message_data) {
|
||||
// Called from any thread.
|
||||
free(reinterpret_cast<void*>(message_data));
|
||||
}
|
||||
|
||||
static void DispatchPointerDataPacket(JNIEnv* env,
|
||||
jobject jcaller,
|
||||
jlong shell_holder,
|
||||
@@ -490,21 +483,22 @@ static void InvokePlatformMessageResponseCallback(JNIEnv* env,
|
||||
jint responseId,
|
||||
jobject message,
|
||||
jint position) {
|
||||
uint8_t* response_data =
|
||||
static_cast<uint8_t*>(env->GetDirectBufferAddress(message));
|
||||
FML_DCHECK(response_data != nullptr);
|
||||
auto mapping = std::make_unique<fml::MallocMapping>(
|
||||
fml::MallocMapping::Copy(response_data, response_data + position));
|
||||
ANDROID_SHELL_HOLDER->GetPlatformMessageHandler()
|
||||
->InvokePlatformMessageResponseCallback(responseId, std::move(mapping));
|
||||
ANDROID_SHELL_HOLDER->GetPlatformView()
|
||||
->InvokePlatformMessageResponseCallback(env, //
|
||||
responseId, //
|
||||
message, //
|
||||
position //
|
||||
);
|
||||
}
|
||||
|
||||
static void InvokePlatformMessageEmptyResponseCallback(JNIEnv* env,
|
||||
jobject jcaller,
|
||||
jlong shell_holder,
|
||||
jint responseId) {
|
||||
ANDROID_SHELL_HOLDER->GetPlatformMessageHandler()
|
||||
->InvokePlatformMessageEmptyResponseCallback(responseId);
|
||||
ANDROID_SHELL_HOLDER->GetPlatformView()
|
||||
->InvokePlatformMessageEmptyResponseCallback(env, //
|
||||
responseId //
|
||||
);
|
||||
}
|
||||
|
||||
static void NotifyLowMemoryWarning(JNIEnv* env,
|
||||
@@ -644,11 +638,6 @@ bool RegisterApi(JNIEnv* env) {
|
||||
.signature = "(JLjava/lang/String;I)V",
|
||||
.fnPtr = reinterpret_cast<void*>(&DispatchEmptyPlatformMessage),
|
||||
},
|
||||
{
|
||||
.name = "nativeCleanupMessageData",
|
||||
.signature = "(J)V",
|
||||
.fnPtr = reinterpret_cast<void*>(&CleanupMessageData),
|
||||
},
|
||||
{
|
||||
.name = "nativeDispatchPlatformMessage",
|
||||
.signature = "(JLjava/lang/String;Ljava/nio/ByteBuffer;II)V",
|
||||
@@ -830,7 +819,7 @@ bool RegisterApi(JNIEnv* env) {
|
||||
|
||||
g_handle_platform_message_method =
|
||||
env->GetMethodID(g_flutter_jni_class->obj(), "handlePlatformMessage",
|
||||
"(Ljava/lang/String;Ljava/nio/ByteBuffer;IJ)V");
|
||||
"(Ljava/lang/String;Ljava/nio/ByteBuffer;I)V");
|
||||
|
||||
if (g_handle_platform_message_method == nullptr) {
|
||||
FML_LOG(ERROR) << "Could not locate handlePlatformMessage method";
|
||||
@@ -1113,7 +1102,6 @@ PlatformViewAndroidJNIImpl::~PlatformViewAndroidJNIImpl() = default;
|
||||
void PlatformViewAndroidJNIImpl::FlutterViewHandlePlatformMessage(
|
||||
std::unique_ptr<flutter::PlatformMessage> message,
|
||||
int responseId) {
|
||||
// Called from the ui thread.
|
||||
JNIEnv* env = fml::jni::AttachCurrentThread();
|
||||
|
||||
auto java_object = java_object_.get(env);
|
||||
@@ -1129,14 +1117,11 @@ void PlatformViewAndroidJNIImpl::FlutterViewHandlePlatformMessage(
|
||||
env, env->NewDirectByteBuffer(
|
||||
const_cast<uint8_t*>(message->data().GetMapping()),
|
||||
message->data().GetSize()));
|
||||
// Message data is deleted in CleanupMessageData.
|
||||
fml::MallocMapping mapping = message->releaseData();
|
||||
env->CallVoidMethod(java_object.obj(), g_handle_platform_message_method,
|
||||
java_channel.obj(), message_array.obj(), responseId,
|
||||
mapping.Release());
|
||||
java_channel.obj(), message_array.obj(), responseId);
|
||||
} else {
|
||||
env->CallVoidMethod(java_object.obj(), g_handle_platform_message_method,
|
||||
java_channel.obj(), nullptr, responseId, nullptr);
|
||||
java_channel.obj(), nullptr, responseId);
|
||||
}
|
||||
|
||||
FML_CHECK(fml::jni::CheckException(env));
|
||||
|
||||
@@ -10,7 +10,6 @@ import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import io.flutter.embedding.engine.FlutterJNI;
|
||||
import io.flutter.embedding.engine.dart.DartMessenger.DartMessengerTaskQueue;
|
||||
import io.flutter.plugin.common.BinaryMessenger;
|
||||
import io.flutter.plugin.common.BinaryMessenger.BinaryMessageHandler;
|
||||
import java.nio.ByteBuffer;
|
||||
@@ -23,8 +22,6 @@ import org.robolectric.annotation.Config;
|
||||
@Config(manifest = Config.NONE)
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public class DartMessengerTest {
|
||||
SynchronousTaskQueue synchronousTaskQueue = new SynchronousTaskQueue();
|
||||
|
||||
private static class ReportingUncaughtExceptionHandler
|
||||
implements Thread.UncaughtExceptionHandler {
|
||||
public Throwable latestException;
|
||||
@@ -35,12 +32,6 @@ public class DartMessengerTest {
|
||||
}
|
||||
}
|
||||
|
||||
private static class SynchronousTaskQueue implements DartMessengerTaskQueue {
|
||||
public void dispatch(Runnable runnable) {
|
||||
runnable.run();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void itHandlesErrors() {
|
||||
// Setup test.
|
||||
@@ -53,14 +44,14 @@ public class DartMessengerTest {
|
||||
currentThread.setUncaughtExceptionHandler(reportingHandler);
|
||||
|
||||
// Create object under test.
|
||||
final DartMessenger messenger = new DartMessenger(fakeFlutterJni, () -> synchronousTaskQueue);
|
||||
final DartMessenger messenger = new DartMessenger(fakeFlutterJni);
|
||||
final BinaryMessageHandler throwingHandler = mock(BinaryMessageHandler.class);
|
||||
Mockito.doThrow(AssertionError.class)
|
||||
.when(throwingHandler)
|
||||
.onMessage(any(ByteBuffer.class), any(DartMessenger.Reply.class));
|
||||
BinaryMessenger.TaskQueue taskQueue = messenger.makeBackgroundTaskQueue();
|
||||
messenger.setMessageHandler("test", throwingHandler, taskQueue);
|
||||
messenger.handleMessageFromDart("test", ByteBuffer.allocate(0), 0, 0);
|
||||
|
||||
messenger.setMessageHandler("test", throwingHandler);
|
||||
messenger.handleMessageFromDart("test", ByteBuffer.allocate(0), 0);
|
||||
assertNotNull(reportingHandler.latestException);
|
||||
assertTrue(reportingHandler.latestException instanceof AssertionError);
|
||||
currentThread.setUncaughtExceptionHandler(savedHandler);
|
||||
@@ -70,22 +61,21 @@ public class DartMessengerTest {
|
||||
public void givesDirectByteBuffer() {
|
||||
// Setup test.
|
||||
final FlutterJNI fakeFlutterJni = mock(FlutterJNI.class);
|
||||
final DartMessenger messenger = new DartMessenger(fakeFlutterJni, () -> synchronousTaskQueue);
|
||||
final DartMessenger messenger = new DartMessenger(fakeFlutterJni);
|
||||
final String channel = "foobar";
|
||||
final boolean[] wasDirect = {false};
|
||||
final BinaryMessenger.BinaryMessageHandler handler =
|
||||
(message, reply) -> {
|
||||
wasDirect[0] = message.isDirect();
|
||||
};
|
||||
BinaryMessenger.TaskQueue taskQueue = messenger.makeBackgroundTaskQueue();
|
||||
messenger.setMessageHandler(channel, handler, taskQueue);
|
||||
messenger.setMessageHandler(channel, handler);
|
||||
final ByteBuffer message = ByteBuffer.allocateDirect(4 * 2);
|
||||
message.rewind();
|
||||
message.putChar('a');
|
||||
message.putChar('b');
|
||||
message.putChar('c');
|
||||
message.putChar('d');
|
||||
messenger.handleMessageFromDart(channel, message, /*replyId=*/ 123, 0);
|
||||
messenger.handleMessageFromDart(channel, message, /*replyId=*/ 123);
|
||||
assertTrue(wasDirect[0]);
|
||||
}
|
||||
|
||||
@@ -93,7 +83,7 @@ public class DartMessengerTest {
|
||||
public void directByteBufferLimitZeroAfterUsage() {
|
||||
// Setup test.
|
||||
final FlutterJNI fakeFlutterJni = mock(FlutterJNI.class);
|
||||
final DartMessenger messenger = new DartMessenger(fakeFlutterJni, () -> synchronousTaskQueue);
|
||||
final DartMessenger messenger = new DartMessenger(fakeFlutterJni);
|
||||
final String channel = "foobar";
|
||||
final ByteBuffer[] byteBuffers = {null};
|
||||
final int bufferSize = 4 * 2;
|
||||
@@ -102,15 +92,14 @@ public class DartMessengerTest {
|
||||
byteBuffers[0] = message;
|
||||
assertEquals(bufferSize, byteBuffers[0].limit());
|
||||
};
|
||||
BinaryMessenger.TaskQueue taskQueue = messenger.makeBackgroundTaskQueue();
|
||||
messenger.setMessageHandler(channel, handler, taskQueue);
|
||||
messenger.setMessageHandler(channel, handler);
|
||||
final ByteBuffer message = ByteBuffer.allocateDirect(bufferSize);
|
||||
message.rewind();
|
||||
message.putChar('a');
|
||||
message.putChar('b');
|
||||
message.putChar('c');
|
||||
message.putChar('d');
|
||||
messenger.handleMessageFromDart(channel, message, /*replyId=*/ 123, 0);
|
||||
messenger.handleMessageFromDart(channel, message, /*replyId=*/ 123);
|
||||
assertNotNull(byteBuffers[0]);
|
||||
assertTrue(byteBuffers[0].isDirect());
|
||||
assertEquals(0, byteBuffers[0].limit());
|
||||
@@ -150,40 +139,4 @@ public class DartMessengerTest {
|
||||
messenger.send(channel, null, null);
|
||||
verify(fakeFlutterJni, times(1)).dispatchEmptyPlatformMessage(eq("foobar"), eq(2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cleansUpMessageData() throws InterruptedException {
|
||||
final FlutterJNI fakeFlutterJni = mock(FlutterJNI.class);
|
||||
final DartMessenger messenger = new DartMessenger(fakeFlutterJni, () -> synchronousTaskQueue);
|
||||
BinaryMessenger.TaskQueue taskQueue = messenger.makeBackgroundTaskQueue();
|
||||
String channel = "foobar";
|
||||
BinaryMessenger.BinaryMessageHandler handler =
|
||||
(ByteBuffer message, BinaryMessenger.BinaryReply reply) -> {
|
||||
reply.reply(null);
|
||||
};
|
||||
messenger.setMessageHandler(channel, handler, taskQueue);
|
||||
final ByteBuffer message = ByteBuffer.allocateDirect(4 * 2);
|
||||
int replyId = 1;
|
||||
long messageData = 1234;
|
||||
messenger.handleMessageFromDart(channel, message, replyId, messageData);
|
||||
verify(fakeFlutterJni).cleanupMessageData(eq(messageData));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cleansUpMessageDataOnError() throws InterruptedException {
|
||||
final FlutterJNI fakeFlutterJni = mock(FlutterJNI.class);
|
||||
final DartMessenger messenger = new DartMessenger(fakeFlutterJni, () -> synchronousTaskQueue);
|
||||
BinaryMessenger.TaskQueue taskQueue = messenger.makeBackgroundTaskQueue();
|
||||
String channel = "foobar";
|
||||
BinaryMessenger.BinaryMessageHandler handler =
|
||||
(ByteBuffer message, BinaryMessenger.BinaryReply reply) -> {
|
||||
throw new RuntimeException("hello");
|
||||
};
|
||||
messenger.setMessageHandler(channel, handler, taskQueue);
|
||||
final ByteBuffer message = ByteBuffer.allocateDirect(4 * 2);
|
||||
int replyId = 1;
|
||||
long messageData = 1234;
|
||||
messenger.handleMessageFromDart(channel, message, replyId, messageData);
|
||||
verify(fakeFlutterJni).cleanupMessageData(eq(messageData));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1884,7 +1884,7 @@ public class TextInputPluginTest {
|
||||
textInputChannel.setTextInputMethodHandler(mockHandler);
|
||||
|
||||
verify(mockBinaryMessenger, times(1))
|
||||
.setMessageHandler(any(String.class), binaryMessageHandlerCaptor.capture(), eq(null));
|
||||
.setMessageHandler(any(String.class), binaryMessageHandlerCaptor.capture());
|
||||
|
||||
BinaryMessenger.BinaryMessageHandler binaryMessageHandler =
|
||||
binaryMessageHandlerCaptor.getValue();
|
||||
@@ -1917,7 +1917,7 @@ public class TextInputPluginTest {
|
||||
new TextInputPlugin(testView, textInputChannel, mock(PlatformViewsController.class));
|
||||
|
||||
verify(mockBinaryMessenger, times(1))
|
||||
.setMessageHandler(any(String.class), binaryMessageHandlerCaptor.capture(), eq(null));
|
||||
.setMessageHandler(any(String.class), binaryMessageHandlerCaptor.capture());
|
||||
|
||||
JSONObject arguments = new JSONObject();
|
||||
arguments.put("action", "actionCommand");
|
||||
@@ -1948,7 +1948,7 @@ public class TextInputPluginTest {
|
||||
new TextInputPlugin(testView, textInputChannel, mock(PlatformViewsController.class));
|
||||
|
||||
verify(mockBinaryMessenger, times(1))
|
||||
.setMessageHandler(any(String.class), binaryMessageHandlerCaptor.capture(), eq(null));
|
||||
.setMessageHandler(any(String.class), binaryMessageHandlerCaptor.capture());
|
||||
|
||||
JSONObject arguments = new JSONObject();
|
||||
arguments.put("action", "actionCommand");
|
||||
|
||||
@@ -218,7 +218,7 @@ public class PlatformViewsControllerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Config(shadows = {ShadowFlutterJNI.class, ShadowPlatformTaskQueue.class})
|
||||
@Config(shadows = {ShadowFlutterJNI.class})
|
||||
public void getPlatformViewById__hybridComposition() {
|
||||
PlatformViewsController platformViewsController = new PlatformViewsController();
|
||||
|
||||
@@ -246,7 +246,7 @@ public class PlatformViewsControllerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Config(shadows = {ShadowFlutterJNI.class, ShadowPlatformTaskQueue.class})
|
||||
@Config(shadows = {ShadowFlutterJNI.class})
|
||||
public void createPlatformViewMessage__initializesAndroidView() {
|
||||
PlatformViewsController platformViewsController = new PlatformViewsController();
|
||||
|
||||
@@ -268,7 +268,7 @@ public class PlatformViewsControllerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Config(shadows = {ShadowFlutterJNI.class, ShadowPlatformTaskQueue.class})
|
||||
@Config(shadows = {ShadowFlutterJNI.class})
|
||||
public void createPlatformViewMessage__throwsIfViewIsNull() {
|
||||
PlatformViewsController platformViewsController = new PlatformViewsController();
|
||||
|
||||
@@ -296,7 +296,7 @@ public class PlatformViewsControllerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Config(shadows = {ShadowFlutterJNI.class, ShadowPlatformTaskQueue.class})
|
||||
@Config(shadows = {ShadowFlutterJNI.class})
|
||||
public void onDetachedFromJNI_clearsPlatformViewContext() {
|
||||
PlatformViewsController platformViewsController = new PlatformViewsController();
|
||||
|
||||
@@ -326,7 +326,7 @@ public class PlatformViewsControllerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Config(shadows = {ShadowFlutterJNI.class, ShadowPlatformTaskQueue.class})
|
||||
@Config(shadows = {ShadowFlutterJNI.class})
|
||||
public void onPreEngineRestart_clearsPlatformViewContext() {
|
||||
PlatformViewsController platformViewsController = new PlatformViewsController();
|
||||
|
||||
@@ -356,7 +356,7 @@ public class PlatformViewsControllerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Config(shadows = {ShadowFlutterJNI.class, ShadowPlatformTaskQueue.class})
|
||||
@Config(shadows = {ShadowFlutterJNI.class})
|
||||
public void createPlatformViewMessage__throwsIfViewHasParent() {
|
||||
PlatformViewsController platformViewsController = new PlatformViewsController();
|
||||
|
||||
@@ -386,7 +386,7 @@ public class PlatformViewsControllerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Config(shadows = {ShadowFlutterJNI.class, ShadowPlatformTaskQueue.class})
|
||||
@Config(shadows = {ShadowFlutterJNI.class})
|
||||
public void disposeAndroidView__hybridComposition() {
|
||||
PlatformViewsController platformViewsController = new PlatformViewsController();
|
||||
|
||||
@@ -427,12 +427,7 @@ public class PlatformViewsControllerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Config(
|
||||
shadows = {
|
||||
ShadowFlutterSurfaceView.class,
|
||||
ShadowFlutterJNI.class,
|
||||
ShadowPlatformTaskQueue.class
|
||||
})
|
||||
@Config(shadows = {ShadowFlutterSurfaceView.class, ShadowFlutterJNI.class})
|
||||
public void onEndFrame__destroysOverlaySurfaceAfterFrameOnFlutterSurfaceView() {
|
||||
final PlatformViewsController platformViewsController = new PlatformViewsController();
|
||||
|
||||
@@ -530,12 +525,7 @@ public class PlatformViewsControllerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Config(
|
||||
shadows = {
|
||||
ShadowFlutterSurfaceView.class,
|
||||
ShadowFlutterJNI.class,
|
||||
ShadowPlatformTaskQueue.class
|
||||
})
|
||||
@Config(shadows = {ShadowFlutterSurfaceView.class, ShadowFlutterJNI.class})
|
||||
public void onEndFrame__removesPlatformViewParent() {
|
||||
final PlatformViewsController platformViewsController = new PlatformViewsController();
|
||||
|
||||
@@ -573,12 +563,7 @@ public class PlatformViewsControllerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Config(
|
||||
shadows = {
|
||||
ShadowFlutterSurfaceView.class,
|
||||
ShadowFlutterJNI.class,
|
||||
ShadowPlatformTaskQueue.class
|
||||
})
|
||||
@Config(shadows = {ShadowFlutterSurfaceView.class, ShadowFlutterJNI.class})
|
||||
public void detach__destroysOverlaySurfaces() {
|
||||
final PlatformViewsController platformViewsController = new PlatformViewsController();
|
||||
|
||||
@@ -710,7 +695,7 @@ public class PlatformViewsControllerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Config(shadows = {ShadowFlutterJNI.class, ShadowPlatformTaskQueue.class})
|
||||
@Config(shadows = {ShadowFlutterJNI.class})
|
||||
public void convertPlatformViewRenderSurfaceAsDefault() {
|
||||
final PlatformViewsController platformViewsController = new PlatformViewsController();
|
||||
|
||||
@@ -756,7 +741,7 @@ public class PlatformViewsControllerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Config(shadows = {ShadowFlutterJNI.class, ShadowPlatformTaskQueue.class})
|
||||
@Config(shadows = {ShadowFlutterJNI.class})
|
||||
public void dontConverRenderSurfaceWhenFlagIsTrue() {
|
||||
final PlatformViewsController platformViewsController = new PlatformViewsController();
|
||||
|
||||
@@ -827,10 +812,7 @@ public class PlatformViewsControllerTest {
|
||||
new MethodCall("create", platformViewCreateArguments);
|
||||
|
||||
jni.handlePlatformMessage(
|
||||
"flutter/platform_views",
|
||||
encodeMethodCall(platformCreateMethodCall),
|
||||
/*replyId=*/ 0,
|
||||
/*messageData=*/ 0);
|
||||
"flutter/platform_views", encodeMethodCall(platformCreateMethodCall), /*replyId=*/ 0);
|
||||
}
|
||||
|
||||
private static void disposePlatformView(
|
||||
@@ -844,10 +826,7 @@ public class PlatformViewsControllerTest {
|
||||
new MethodCall("dispose", platformViewDisposeArguments);
|
||||
|
||||
jni.handlePlatformMessage(
|
||||
"flutter/platform_views",
|
||||
encodeMethodCall(platformDisposeMethodCall),
|
||||
/*replyId=*/ 0,
|
||||
/*messageData=*/ 0);
|
||||
"flutter/platform_views", encodeMethodCall(platformDisposeMethodCall), /*replyId=*/ 0);
|
||||
}
|
||||
|
||||
private static void synchronizeToNativeViewHierarchy(
|
||||
@@ -856,10 +835,7 @@ public class PlatformViewsControllerTest {
|
||||
final MethodCall convertMethodCall = new MethodCall("synchronizeToNativeViewHierarchy", yes);
|
||||
|
||||
jni.handlePlatformMessage(
|
||||
"flutter/platform_views",
|
||||
encodeMethodCall(convertMethodCall),
|
||||
/*replyId=*/ 0,
|
||||
/*messageData=*/ 0);
|
||||
"flutter/platform_views", encodeMethodCall(convertMethodCall), /*replyId=*/ 0);
|
||||
}
|
||||
|
||||
private static FlutterView attach(
|
||||
@@ -925,20 +901,6 @@ public class PlatformViewsControllerTest {
|
||||
return view;
|
||||
}
|
||||
|
||||
/**
|
||||
* For convenience when writing tests, this allows us to make fake messages from Flutter via
|
||||
* Platform Channels. Typically those calls happen on the ui thread which dispatches to the
|
||||
* platform thread. Since tests run on the platform thread it makes it difficult to test without
|
||||
* this, but isn't technically required.
|
||||
*/
|
||||
@Implements(io.flutter.embedding.engine.dart.PlatformTaskQueue.class)
|
||||
public static class ShadowPlatformTaskQueue {
|
||||
@Implementation
|
||||
public void dispatch(Runnable runnable) {
|
||||
runnable.run();
|
||||
}
|
||||
}
|
||||
|
||||
@Implements(FlutterJNI.class)
|
||||
public static class ShadowFlutterJNI {
|
||||
private static SparseArray<ByteBuffer> replies = new SparseArray<>();
|
||||
|
||||
@@ -31,10 +31,7 @@ public class MainActivity extends FlutterActivity {
|
||||
|
||||
@Override
|
||||
public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
|
||||
flutterEngine
|
||||
.getDartExecutor()
|
||||
.getBinaryMessenger()
|
||||
.setMessageHandler("finish", finishHandler, null);
|
||||
flutterEngine.getDartExecutor().getBinaryMessenger().setMessageHandler("finish", finishHandler);
|
||||
|
||||
final boolean moved = moveTaskToBack(true);
|
||||
if (!moved) {
|
||||
|
||||
@@ -22,8 +22,7 @@ public class SpawnedEngineActivity extends TestActivity {
|
||||
|
||||
secondEngine
|
||||
.getDartExecutor()
|
||||
.setMessageHandler(
|
||||
"take_screenshot", (byteBuffer, binaryReply) -> notifyFlutterRendered(), null);
|
||||
.setMessageHandler("take_screenshot", (byteBuffer, binaryReply) -> notifyFlutterRendered());
|
||||
|
||||
return secondEngine;
|
||||
}
|
||||
|
||||
@@ -19,8 +19,7 @@ public abstract class TestableFlutterActivity extends FlutterActivity {
|
||||
// registration will fail and print a scary exception in the logs.
|
||||
flutterEngine
|
||||
.getDartExecutor()
|
||||
.setMessageHandler(
|
||||
"take_screenshot", (byteBuffer, binaryReply) -> notifyFlutterRendered(), null);
|
||||
.setMessageHandler("take_screenshot", (byteBuffer, binaryReply) -> notifyFlutterRendered());
|
||||
}
|
||||
|
||||
protected void notifyFlutterRendered() {
|
||||
|
||||
Reference in New Issue
Block a user