Skip to content

Commit

Permalink
Wire the old JNI bindings through the new API (#6425)
Browse files Browse the repository at this point in the history
Tested by going through a regular `flutter run` and by running
`flutter/flutter/examples/flutter_view`. `FlutterView` and
`FlutterNativeView` have been changed to wrap an instance of
`FlutterJNI` for all their internal native calls.

Also moves onPreEngineRestart into FlutterJNI.

Follows the `setHandler(interface)` pattern already used in
`FlutterJNI.java` for the other C++ to Java callbacks (see
`PlatformMessageHandler` and `RenderSurface`). The new interface is
`FlutterEngine.EngineHandler`. Sets and uses the impl in
`FlutterNativeView`.

Fixes flutter/flutter#22580
  • Loading branch information
Michael Klimushyn authored Oct 15, 2018
1 parent 01077b5 commit 55f9e1c
Show file tree
Hide file tree
Showing 6 changed files with 152 additions and 420 deletions.
Empty file.
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,14 @@ public FlutterEngine(
this.isBackgroundView = isBackgroundView;

this.flutterJNI = new FlutterJNI();
flutterJNI.setEngineHandler(new EngineHandler() {
@SuppressWarnings("unused")
public void onPreEngineRestart() {
if (pluginRegistry == null)
return;
pluginRegistry.onPreEngineRestart();
}
});
attachToJni();

// TODO(mattcarroll): FlutterRenderer is temporally coupled to attach(). Remove that coupling if possible.
Expand Down Expand Up @@ -99,12 +107,9 @@ public DartExecutor getDartExecutor() {
return dartExecutor;
}

// TODO(mattcarroll): what does this callback actually represent?
// Called by native to notify when the engine is restarted (cold reload).
@SuppressWarnings("unused")
private void onPreEngineRestart() {
if (pluginRegistry == null)
return;
pluginRegistry.onPreEngineRestart();
/** Callbacks triggered by the C++ layer in response to Engine lifecycle events. */
public interface EngineHandler {
/** Called when the engine is restarted. This happens during hot restart. */
void onPreEngineRestart();
}
}
16 changes: 16 additions & 0 deletions shell/platform/android/io/flutter/embedding/engine/FlutterJNI.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import java.util.concurrent.CopyOnWriteArraySet;

import io.flutter.embedding.engine.dart.PlatformMessageHandler;
import io.flutter.embedding.engine.FlutterEngine.EngineHandler;
import io.flutter.embedding.engine.renderer.FlutterRenderer;
import io.flutter.embedding.engine.renderer.OnFirstFrameRenderedListener;
import io.flutter.plugin.common.BinaryMessenger;
Expand All @@ -22,6 +23,7 @@ public class FlutterJNI {

private FlutterRenderer.RenderSurface renderSurface;
private PlatformMessageHandler platformMessageHandler;
private @Nullable EngineHandler engineHandler;
private final Set<OnFirstFrameRenderedListener> firstFrameListeners = new CopyOnWriteArraySet<>();

public void setRenderSurface(@Nullable FlutterRenderer.RenderSurface renderSurface) {
Expand All @@ -32,6 +34,10 @@ public void setPlatformMessageHandler(@Nullable PlatformMessageHandler platformM
this.platformMessageHandler = platformMessageHandler;
}

public void setEngineHandler(@Nullable EngineHandler engineHandler) {
this.engineHandler = engineHandler;
}

public void addOnFirstFrameRenderedListener(@NonNull OnFirstFrameRenderedListener listener) {
firstFrameListeners.add(listener);
}
Expand Down Expand Up @@ -183,4 +189,14 @@ public native void nativeInvokePlatformMessageResponseCallback(
int position
);
//------ End from FlutterNativeView ----

//------ Start from Engine ---
@SuppressWarnings("unused")
private void onPreEngineRestart() {
if (engineHandler == null) {
return;
}
engineHandler.onPreEngineRestart();
}
//------ End from Engine ---
}
191 changes: 94 additions & 97 deletions shell/platform/android/io/flutter/view/FlutterNativeView.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,16 @@
import android.content.Context;
import android.util.Log;
import io.flutter.app.FlutterPluginRegistry;
import io.flutter.embedding.engine.FlutterJNI;
import io.flutter.embedding.engine.FlutterEngine.EngineHandler;
import io.flutter.embedding.engine.renderer.FlutterRenderer.RenderSurface;
import io.flutter.plugin.common.*;
import java.nio.ByteBuffer;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.HashMap;
import java.util.Map;
import android.content.res.AssetManager;
import io.flutter.embedding.engine.dart.PlatformMessageHandler;

public class FlutterNativeView implements BinaryMessenger {
private static final String TAG = "FlutterNativeView";
Expand All @@ -25,6 +29,7 @@ public class FlutterNativeView implements BinaryMessenger {
private final FlutterPluginRegistry mPluginRegistry;
private long mNativePlatformView;
private FlutterView mFlutterView;
private FlutterJNI mFlutterJNI;
private final Context mContext;
private boolean applicationIsRunning;

Expand All @@ -35,6 +40,10 @@ public FlutterNativeView(Context context) {
public FlutterNativeView(Context context, boolean isBackgroundView) {
mContext = context;
mPluginRegistry = new FlutterPluginRegistry(this, context);
mFlutterJNI = new FlutterJNI();
mFlutterJNI.setRenderSurface(new RenderSurfaceImpl());
mFlutterJNI.setPlatformMessageHandler(new PlatformMessageHandlerImpl());
mFlutterJNI.setEngineHandler(new EngineHandlerImpl());
attach(this, isBackgroundView);
assertAttached();
mMessageHandlers = new HashMap<>();
Expand All @@ -43,13 +52,13 @@ public FlutterNativeView(Context context, boolean isBackgroundView) {
public void detach() {
mPluginRegistry.detach();
mFlutterView = null;
nativeDetach(mNativePlatformView);
mFlutterJNI.nativeDetach(mNativePlatformView);
}

public void destroy() {
mPluginRegistry.destroy();
mFlutterView = null;
nativeDestroy(mNativePlatformView);
mFlutterJNI.nativeDestroy(mNativePlatformView);
mNativePlatformView = 0;
applicationIsRunning = false;
}
Expand Down Expand Up @@ -101,7 +110,7 @@ private void runFromBundleInternal(String bundlePath, String entrypoint,
if (applicationIsRunning)
throw new AssertionError(
"This Flutter engine instance is already running an application");
nativeRunBundleAndSnapshotFromLibrary(mNativePlatformView, bundlePath,
mFlutterJNI.nativeRunBundleAndSnapshotFromLibrary(mNativePlatformView, bundlePath,
defaultPath, entrypoint, libraryPath, mContext.getResources().getAssets());

applicationIsRunning = true;
Expand All @@ -112,7 +121,8 @@ public boolean isApplicationRunning() {
}

public static String getObservatoryUri() {
return nativeGetObservatoryUri();
FlutterJNI flutterJNI = new FlutterJNI();
return flutterJNI.nativeGetObservatoryUri();
}

@Override
Expand All @@ -133,9 +143,9 @@ public void send(String channel, ByteBuffer message, BinaryReply callback) {
mPendingReplies.put(replyId, callback);
}
if (message == null) {
nativeDispatchEmptyPlatformMessage(mNativePlatformView, channel, replyId);
mFlutterJNI.nativeDispatchEmptyPlatformMessage(mNativePlatformView, channel, replyId);
} else {
nativeDispatchPlatformMessage(
mFlutterJNI.nativeDispatchPlatformMessage(
mNativePlatformView, channel, message, message.position(), replyId);
}
}
Expand All @@ -149,111 +159,98 @@ public void setMessageHandler(String channel, BinaryMessageHandler handler) {
}
}

/*package*/ FlutterJNI getFlutterJNI() {
return mFlutterJNI;
}

private void attach(FlutterNativeView view, boolean isBackgroundView) {
mNativePlatformView = nativeAttach(view, isBackgroundView);
mNativePlatformView = mFlutterJNI.nativeAttach(mFlutterJNI, isBackgroundView);
}

// Called by native to send us a platform message.
private void handlePlatformMessage(final String channel, byte[] message, final int replyId) {
assertAttached();
BinaryMessageHandler handler = mMessageHandlers.get(channel);
if (handler != null) {
try {
final ByteBuffer buffer = (message == null ? null : ByteBuffer.wrap(message));
handler.onMessage(buffer, new BinaryReply() {
private final AtomicBoolean done = new AtomicBoolean(false);
@Override
public void reply(ByteBuffer reply) {
if (!isAttached()) {
Log.d(TAG,
"handlePlatformMessage replying to a detached view, channel="
+ channel);
return;
}
if (done.getAndSet(true)) {
throw new IllegalStateException("Reply already submitted");
private final class PlatformMessageHandlerImpl implements PlatformMessageHandler {
// Called by native to send us a platform message.
public void handlePlatformMessage(final String channel, byte[] message, final int replyId) {
assertAttached();
BinaryMessageHandler handler = mMessageHandlers.get(channel);
if (handler != null) {
try {
final ByteBuffer buffer = (message == null ? null : ByteBuffer.wrap(message));
handler.onMessage(buffer, new BinaryReply() {
private final AtomicBoolean done = new AtomicBoolean(false);
@Override
public void reply(ByteBuffer reply) {
if (!isAttached()) {
Log.d(TAG,
"handlePlatformMessage replying to a detached view, channel="
+ channel);
return;
}
if (done.getAndSet(true)) {
throw new IllegalStateException("Reply already submitted");
}
if (reply == null) {
mFlutterJNI.nativeInvokePlatformMessageEmptyResponseCallback(
mNativePlatformView, replyId);
} else {
mFlutterJNI.nativeInvokePlatformMessageResponseCallback(
mNativePlatformView, replyId, reply, reply.position());
}
}
if (reply == null) {
nativeInvokePlatformMessageEmptyResponseCallback(
mNativePlatformView, replyId);
} else {
nativeInvokePlatformMessageResponseCallback(
mNativePlatformView, replyId, reply, reply.position());
}
}
});
} catch (Exception ex) {
Log.e(TAG, "Uncaught exception in binary message listener", ex);
nativeInvokePlatformMessageEmptyResponseCallback(mNativePlatformView, replyId);
});
} catch (Exception ex) {
Log.e(TAG, "Uncaught exception in binary message listener", ex);
mFlutterJNI.nativeInvokePlatformMessageEmptyResponseCallback(mNativePlatformView, replyId);
}
return;
}
return;
mFlutterJNI.nativeInvokePlatformMessageEmptyResponseCallback(mNativePlatformView, replyId);
}
nativeInvokePlatformMessageEmptyResponseCallback(mNativePlatformView, replyId);
}

// Called by native to respond to a platform message that we sent.
private void handlePlatformMessageResponse(int replyId, byte[] reply) {
BinaryReply callback = mPendingReplies.remove(replyId);
if (callback != null) {
try {
callback.reply(reply == null ? null : ByteBuffer.wrap(reply));
} catch (Exception ex) {
Log.e(TAG, "Uncaught exception in binary message reply handler", ex);
// Called by native to respond to a platform message that we sent.
public void handlePlatformMessageResponse(int replyId, byte[] reply) {
BinaryReply callback = mPendingReplies.remove(replyId);
if (callback != null) {
try {
callback.reply(reply == null ? null : ByteBuffer.wrap(reply));
} catch (Exception ex) {
Log.e(TAG, "Uncaught exception in binary message reply handler", ex);
}
}
}
}

// Called by native to update the semantics/accessibility tree.
private void updateSemantics(ByteBuffer buffer, String[] strings) {
if (mFlutterView == null) return;
mFlutterView.updateSemantics(buffer, strings);
}
private final class RenderSurfaceImpl implements RenderSurface {
// Called by native to update the semantics/accessibility tree.
public void updateSemantics(ByteBuffer buffer, String[] strings) {
if (mFlutterView == null) return;
mFlutterView.updateSemantics(buffer, strings);
}

// Called by native to update the custom accessibility actions.
private void updateCustomAccessibilityActions(ByteBuffer buffer, String[] strings) {
if (mFlutterView == null)
return;
mFlutterView.updateCustomAccessibilityActions(buffer, strings);
}
// Called by native to update the custom accessibility actions.
public void updateCustomAccessibilityActions(ByteBuffer buffer, String[] strings) {
if (mFlutterView == null)
return;
mFlutterView.updateCustomAccessibilityActions(buffer, strings);
}

// Called by native to notify first Flutter frame rendered.
private void onFirstFrame() {
if (mFlutterView == null) return;
mFlutterView.onFirstFrame();
}
// Called by native to notify first Flutter frame rendered.
public void onFirstFrameRendered() {
if (mFlutterView == null) return;
mFlutterView.onFirstFrame();
}

// Called by native to notify when the engine is restarted (cold reload).
@SuppressWarnings("unused")
private void onPreEngineRestart() {
if (mPluginRegistry == null)
return;
mPluginRegistry.onPreEngineRestart();
/*package*/ FlutterJNI getFlutterJNI() {
return mFlutterJNI;
}
}

private static native long nativeAttach(FlutterNativeView view, boolean isBackgroundView);
private static native void nativeDestroy(long nativePlatformViewAndroid);
private static native void nativeDetach(long nativePlatformViewAndroid);

private static native void nativeRunBundleAndSnapshotFromLibrary(
long nativePlatformViewAndroid, String bundlePath,
String defaultPath, String entrypoint, String libraryUrl,
AssetManager manager);

private static native String nativeGetObservatoryUri();

// Send an empty platform message to Dart.
private static native void nativeDispatchEmptyPlatformMessage(
long nativePlatformViewAndroid, String channel, int responseId);

// Send a data-carrying platform message to Dart.
private static native void nativeDispatchPlatformMessage(long nativePlatformViewAndroid,
String channel, ByteBuffer message, int position, int responseId);

// Send an empty response to a platform message received from Dart.
private static native void nativeInvokePlatformMessageEmptyResponseCallback(
long nativePlatformViewAndroid, int responseId);

// Send a data-carrying response to a platform message received from Dart.
private static native void nativeInvokePlatformMessageResponseCallback(
long nativePlatformViewAndroid, int responseId, ByteBuffer message, int position);
private final class EngineHandlerImpl implements EngineHandler {
// Called by native to notify when the engine is restarted (cold reload).
@SuppressWarnings("unused")
public void onPreEngineRestart() {
if (mPluginRegistry == null)
return;
mPluginRegistry.onPreEngineRestart();
}
}
}
Loading

0 comments on commit 55f9e1c

Please sign in to comment.