diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 90840267553b..8a0bf83a6b24 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -444,7 +444,13 @@ FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/dart/D FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/dart/PlatformMessageHandler.java FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/renderer/FlutterRenderer.java FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/renderer/OnFirstFrameRenderedListener.java +FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/systemchannels/KeyEventChannel.java +FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/systemchannels/LifecycleChannel.java +FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/systemchannels/LocalizationChannel.java +FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/systemchannels/NavigationChannel.java +FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/systemchannels/PlatformChannel.java FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/systemchannels/SettingsChannel.java +FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/systemchannels/SystemChannel.java FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/common/ActivityLifecycleListener.java FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/common/BasicMessageChannel.java FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/common/BinaryCodec.java diff --git a/shell/platform/android/BUILD.gn b/shell/platform/android/BUILD.gn index 1b49602f25d0..7779ecef8359 100644 --- a/shell/platform/android/BUILD.gn +++ b/shell/platform/android/BUILD.gn @@ -113,7 +113,13 @@ java_library("flutter_shell_java") { "io/flutter/embedding/engine/dart/PlatformMessageHandler.java", "io/flutter/embedding/engine/renderer/FlutterRenderer.java", "io/flutter/embedding/engine/renderer/OnFirstFrameRenderedListener.java", + "io/flutter/embedding/engine/systemchannels/KeyEventChannel.java", + "io/flutter/embedding/engine/systemchannels/LifecycleChannel.java", + "io/flutter/embedding/engine/systemchannels/LocalizationChannel.java", + "io/flutter/embedding/engine/systemchannels/NavigationChannel.java", + "io/flutter/embedding/engine/systemchannels/PlatformChannel.java", "io/flutter/embedding/engine/systemchannels/SettingsChannel.java", + "io/flutter/embedding/engine/systemchannels/SystemChannel.java", "io/flutter/plugin/common/ActivityLifecycleListener.java", "io/flutter/plugin/common/BasicMessageChannel.java", "io/flutter/plugin/common/BinaryCodec.java", diff --git a/shell/platform/android/io/flutter/embedding/engine/FlutterJNI.java b/shell/platform/android/io/flutter/embedding/engine/FlutterJNI.java index 4923f1c77c34..0ee86091ab09 100644 --- a/shell/platform/android/io/flutter/embedding/engine/FlutterJNI.java +++ b/shell/platform/android/io/flutter/embedding/engine/FlutterJNI.java @@ -199,7 +199,7 @@ public void setPlatformMessageHandler(@Nullable PlatformMessageHandler platformM @SuppressWarnings("unused") private void handlePlatformMessage(final String channel, byte[] message, final int replyId) { if (platformMessageHandler != null) { - platformMessageHandler.handlePlatformMessage(channel, message, replyId); + platformMessageHandler.handleMessageFromDart(channel, message, replyId); } // TODO(mattcarroll): log dropped messages when in debug mode (https://github.com/flutter/flutter/issues/25391) } diff --git a/shell/platform/android/io/flutter/embedding/engine/dart/DartExecutor.java b/shell/platform/android/io/flutter/embedding/engine/dart/DartExecutor.java index 28d6f5277201..f7cdd855d77d 100644 --- a/shell/platform/android/io/flutter/embedding/engine/dart/DartExecutor.java +++ b/shell/platform/android/io/flutter/embedding/engine/dart/DartExecutor.java @@ -37,29 +37,33 @@ */ public class DartExecutor implements BinaryMessenger { private static final String TAG = "DartExecutor"; - + + @NonNull private final FlutterJNI flutterJNI; + @NonNull private final DartMessenger messenger; private boolean isApplicationRunning = false; - + public DartExecutor(@NonNull FlutterJNI flutterJNI) { this.flutterJNI = flutterJNI; this.messenger = new DartMessenger(flutterJNI); } - + /** * Invoked when the {@link io.flutter.embedding.engine.FlutterEngine} that owns this * {@link DartExecutor} attaches to JNI. *

* When attached to JNI, this {@link DartExecutor} begins handling 2-way communication to/from * the Dart execution context. This communication is facilitate via 2 APIs: - * - {@link BinaryMessenger}, which sends messages to Dart - * - {@link PlatformMessageHandler}, which receives messages from Dart + *

*/ public void onAttachedToJNI() { flutterJNI.setPlatformMessageHandler(messenger); } - + /** * Invoked when the {@link io.flutter.embedding.engine.FlutterEngine} that owns this * {@link DartExecutor} detaches from JNI. @@ -70,7 +74,7 @@ public void onAttachedToJNI() { public void onDetachedFromJNI() { flutterJNI.setPlatformMessageHandler(null); } - + /** * Is this {@link DartExecutor} currently executing Dart code? * @@ -79,7 +83,7 @@ public void onDetachedFromJNI() { public boolean isExecutingDart() { return isApplicationRunning; } - + /** * Starts executing Dart code based on the given {@code dartEntrypoint}. *

@@ -87,12 +91,12 @@ public boolean isExecutingDart() { * * @param dartEntrypoint specifies which Dart function to run, and where to find it */ - public void executeDartEntrypoint(DartEntrypoint dartEntrypoint) { + public void executeDartEntrypoint(@NonNull DartEntrypoint dartEntrypoint) { if (isApplicationRunning) { Log.w(TAG, "Attempted to run a DartExecutor that is already running."); return; } - + flutterJNI.runBundleAndSnapshotFromLibrary( new String[]{ dartEntrypoint.pathToPrimaryBundle, @@ -102,10 +106,10 @@ public void executeDartEntrypoint(DartEntrypoint dartEntrypoint) { null, dartEntrypoint.androidAssetManager ); - + isApplicationRunning = true; } - + /** * Starts executing Dart code based on the given {@code dartCallback}. *

@@ -113,12 +117,12 @@ public void executeDartEntrypoint(DartEntrypoint dartEntrypoint) { * * @param dartCallback specifies which Dart callback to run, and where to find it */ - public void executeDartCallback(DartCallback dartCallback) { + public void executeDartCallback(@NonNull DartCallback dartCallback) { if (isApplicationRunning) { Log.w(TAG, "Attempted to run a DartExecutor that is already running."); return; } - + flutterJNI.runBundleAndSnapshotFromLibrary( new String[]{ dartCallback.pathToPrimaryBundle, @@ -128,12 +132,12 @@ public void executeDartCallback(DartCallback dartCallback) { dartCallback.callbackHandle.callbackLibraryPath, dartCallback.androidAssetManager ); - + isApplicationRunning = true; } - + //------ START BinaryMessenger ----- - + /** * Sends the given {@code message} from Android to Dart over the given {@code channel}. * @@ -141,10 +145,10 @@ public void executeDartCallback(DartCallback dartCallback) { * @param message the message payload, a direct-allocated {@link ByteBuffer} with the message bytes */ @Override - public void send(String channel, ByteBuffer message) { + public void send(@NonNull String channel, @Nullable ByteBuffer message) { messenger.send(channel, message, null); } - + /** * Sends the given {@code messages} from Android to Dart over the given {@code channel} and * then has the provided {@code callback} invoked when the Dart side responds. @@ -155,10 +159,10 @@ public void send(String channel, ByteBuffer message) { * @param callback a callback invoked when the Dart application responds to the message */ @Override - public void send(String channel, ByteBuffer message, BinaryMessenger.BinaryReply callback) { + public void send(@NonNull String channel, @Nullable ByteBuffer message, @Nullable BinaryMessenger.BinaryReply callback) { messenger.send(channel, message, callback); } - + /** * Sets the given {@link io.flutter.plugin.common.BinaryMessenger.BinaryMessageHandler} as the * singular handler for all incoming messages received from the Dart side of this Dart execution @@ -168,11 +172,11 @@ public void send(String channel, ByteBuffer message, BinaryMessenger.BinaryReply * @param handler a {@link BinaryMessageHandler} to be invoked on incoming messages, or null. */ @Override - public void setMessageHandler(String channel, BinaryMessenger.BinaryMessageHandler handler) { + public void setMessageHandler(@NonNull String channel, @Nullable BinaryMessenger.BinaryMessageHandler handler) { messenger.setMessageHandler(channel, handler); } //------ END BinaryMessenger ----- - + /** * Configuration options that specify which Dart entrypoint function is executed and where * to find that entrypoint and other assets required for Dart execution. @@ -181,23 +185,27 @@ public static class DartEntrypoint { /** * Standard Android AssetManager, provided from some {@code Context} or {@code Resources}. */ + @NonNull public final AssetManager androidAssetManager; - + /** * The first place that Dart will look for a given function or asset. */ + @NonNull public final String pathToPrimaryBundle; - + /** * A secondary fallback location that Dart will look for a given function or asset. */ + @Nullable public final String pathToFallbackBundle; - + /** * The name of a Dart function to execute. */ + @NonNull public final String dartEntrypointFunctionName; - + public DartEntrypoint( @NonNull AssetManager androidAssetManager, @NonNull String pathToBundle, @@ -210,7 +218,7 @@ public DartEntrypoint( dartEntrypointFunctionName ); } - + public DartEntrypoint( @NonNull AssetManager androidAssetManager, @NonNull String pathToPrimaryBundle, @@ -223,7 +231,7 @@ public DartEntrypoint( this.dartEntrypointFunctionName = dartEntrypointFunctionName; } } - + /** * Configuration options that specify which Dart callback function is executed and where * to find that callback and other assets required for Dart execution. @@ -233,22 +241,22 @@ public static class DartCallback { * Standard Android AssetManager, provided from some {@code Context} or {@code Resources}. */ public final AssetManager androidAssetManager; - + /** * The first place that Dart will look for a given function or asset. */ public final String pathToPrimaryBundle; - + /** * A secondary fallback location that Dart will look for a given function or asset. */ public final String pathToFallbackBundle; - + /** * A Dart callback that was previously registered with the Dart VM. */ public final FlutterCallbackInformation callbackHandle; - + public DartCallback( @NonNull AssetManager androidAssetManager, @NonNull String pathToPrimaryBundle, @@ -261,7 +269,7 @@ public DartCallback( callbackHandle ); } - + public DartCallback( @NonNull AssetManager androidAssetManager, @NonNull String pathToPrimaryBundle, diff --git a/shell/platform/android/io/flutter/embedding/engine/dart/DartMessenger.java b/shell/platform/android/io/flutter/embedding/engine/dart/DartMessenger.java index 16a6b10b8a26..e9fe0a7cd8c0 100644 --- a/shell/platform/android/io/flutter/embedding/engine/dart/DartMessenger.java +++ b/shell/platform/android/io/flutter/embedding/engine/dart/DartMessenger.java @@ -5,6 +5,7 @@ package io.flutter.embedding.engine.dart; import android.support.annotation.NonNull; +import android.support.annotation.Nullable; import android.util.Log; import java.nio.ByteBuffer; @@ -22,41 +23,50 @@ * IF YOU USE IT, WE WILL BREAK YOU. *

* See {@link BinaryMessenger}, which sends messages from Android to Dart + *

* See {@link PlatformMessageHandler}, which handles messages to Android from Dart */ class DartMessenger implements BinaryMessenger, PlatformMessageHandler { private static final String TAG = "DartMessenger"; - + + @NonNull private final FlutterJNI flutterJNI; + @NonNull private final Map messageHandlers; - private final Map mPendingReplies = new HashMap<>(); - private int mNextReplyId = 1; - + @NonNull + private final Map pendingReplies; + private int nextReplyId = 1; + DartMessenger(@NonNull FlutterJNI flutterJNI) { this.flutterJNI = flutterJNI; this.messageHandlers = new HashMap<>(); + this.pendingReplies = new HashMap<>(); } - + @Override - public void setMessageHandler(String channel, BinaryMessenger.BinaryMessageHandler handler) { + public void setMessageHandler(@NonNull String channel, @Nullable BinaryMessenger.BinaryMessageHandler handler) { if (handler == null) { messageHandlers.remove(channel); } else { messageHandlers.put(channel, handler); } } - + @Override - public void send(String channel, ByteBuffer message) { + public void send(@NonNull String channel, @NonNull ByteBuffer message) { send(channel, message, null); } - + @Override - public void send(String channel, ByteBuffer message, BinaryMessenger.BinaryReply callback) { + public void send( + @NonNull String channel, + @Nullable ByteBuffer message, + @Nullable BinaryMessenger.BinaryReply callback + ) { int replyId = 0; if (callback != null) { - replyId = mNextReplyId++; - mPendingReplies.put(replyId, callback); + replyId = nextReplyId++; + pendingReplies.put(replyId, callback); } if (message == null) { flutterJNI.dispatchEmptyPlatformMessage(channel, replyId); @@ -64,40 +74,30 @@ public void send(String channel, ByteBuffer message, BinaryMessenger.BinaryReply flutterJNI.dispatchPlatformMessage(channel, message, message.position(), replyId); } } - + @Override - public void handlePlatformMessage(final String channel, byte[] message, final int replyId) { + public void handleMessageFromDart( + @NonNull final String channel, + @Nullable byte[] message, + final int replyId + ) { BinaryMessenger.BinaryMessageHandler handler = messageHandlers.get(channel); if (handler != null) { try { final ByteBuffer buffer = (message == null ? null : ByteBuffer.wrap(message)); - handler.onMessage(buffer, new BinaryMessenger.BinaryReply() { - private final AtomicBoolean done = new AtomicBoolean(false); - - @Override - public void reply(ByteBuffer reply) { - if (done.getAndSet(true)) { - throw new IllegalStateException("Reply already submitted"); - } - if (reply == null) { - flutterJNI.invokePlatformMessageEmptyResponseCallback(replyId); - } else { - flutterJNI.invokePlatformMessageResponseCallback(replyId, reply, reply.position()); - } - } - }); + handler.onMessage(buffer, new Reply(flutterJNI, replyId)); } catch (Exception ex) { Log.e(TAG, "Uncaught exception in binary message listener", ex); flutterJNI.invokePlatformMessageEmptyResponseCallback(replyId); } - return; + } else { + flutterJNI.invokePlatformMessageEmptyResponseCallback(replyId); } - flutterJNI.invokePlatformMessageEmptyResponseCallback(replyId); } - + @Override - public void handlePlatformMessageResponse(int replyId, byte[] reply) { - BinaryMessenger.BinaryReply callback = mPendingReplies.remove(replyId); + public void handlePlatformMessageResponse(int replyId, @Nullable byte[] reply) { + BinaryMessenger.BinaryReply callback = pendingReplies.remove(replyId); if (callback != null) { try { callback.reply(reply == null ? null : ByteBuffer.wrap(reply)); @@ -106,4 +106,28 @@ public void handlePlatformMessageResponse(int replyId, byte[] reply) { } } } + + private static class Reply implements BinaryMessenger.BinaryReply { + @NonNull + private final FlutterJNI flutterJNI; + private final int replyId; + private final AtomicBoolean done = new AtomicBoolean(false); + + Reply(@NonNull FlutterJNI flutterJNI, int replyId) { + this.flutterJNI = flutterJNI; + this.replyId = replyId; + } + + @Override + public void reply(ByteBuffer reply) { + if (done.getAndSet(true)) { + throw new IllegalStateException("Reply already submitted"); + } + if (reply == null) { + flutterJNI.invokePlatformMessageEmptyResponseCallback(replyId); + } else { + flutterJNI.invokePlatformMessageResponseCallback(replyId, reply, reply.position()); + } + } + } } \ No newline at end of file diff --git a/shell/platform/android/io/flutter/embedding/engine/dart/PlatformMessageHandler.java b/shell/platform/android/io/flutter/embedding/engine/dart/PlatformMessageHandler.java index 0403348b871b..ea1011c09abc 100644 --- a/shell/platform/android/io/flutter/embedding/engine/dart/PlatformMessageHandler.java +++ b/shell/platform/android/io/flutter/embedding/engine/dart/PlatformMessageHandler.java @@ -9,7 +9,7 @@ * IF YOU USE IT, WE WILL BREAK YOU. */ public interface PlatformMessageHandler { - void handlePlatformMessage(final String channel, byte[] message, final int replyId); + void handleMessageFromDart(final String channel, byte[] message, final int replyId); void handlePlatformMessageResponse(int replyId, byte[] reply); } diff --git a/shell/platform/android/io/flutter/embedding/engine/systemchannels/KeyEventChannel.java b/shell/platform/android/io/flutter/embedding/engine/systemchannels/KeyEventChannel.java new file mode 100644 index 000000000000..2ecd048386fc --- /dev/null +++ b/shell/platform/android/io/flutter/embedding/engine/systemchannels/KeyEventChannel.java @@ -0,0 +1,54 @@ +// 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.systemchannels; + +import android.support.annotation.NonNull; +import android.view.KeyEvent; + +import java.util.HashMap; +import java.util.Map; + +import io.flutter.embedding.engine.dart.DartExecutor; +import io.flutter.plugin.common.BasicMessageChannel; +import io.flutter.plugin.common.JSONMessageCodec; + +/** + * TODO(mattcarroll): fill in javadoc for KeyEventChannel. + */ +public class KeyEventChannel { + + @NonNull + public final BasicMessageChannel channel; + + public KeyEventChannel(@NonNull DartExecutor dartExecutor) { + this.channel = new BasicMessageChannel<>(dartExecutor, "flutter/keyevent", JSONMessageCodec.INSTANCE); + } + + public void keyUp(@NonNull KeyEvent keyEvent) { + Map message = new HashMap<>(); + message.put("type", "keyup"); + message.put("keymap", "android"); + encodeKeyEvent(keyEvent, message); + + channel.send(message); + } + + public void keyDown(@NonNull KeyEvent keyEvent) { + Map message = new HashMap<>(); + message.put("type", "keydown"); + message.put("keymap", "android"); + encodeKeyEvent(keyEvent, message); + + channel.send(message); + } + + private void encodeKeyEvent(@NonNull KeyEvent event, @NonNull Map message) { + message.put("flags", event.getFlags()); + message.put("codePoint", event.getUnicodeChar()); + message.put("keyCode", event.getKeyCode()); + message.put("scanCode", event.getScanCode()); + message.put("metaState", event.getMetaState()); + } +} diff --git a/shell/platform/android/io/flutter/embedding/engine/systemchannels/LifecycleChannel.java b/shell/platform/android/io/flutter/embedding/engine/systemchannels/LifecycleChannel.java new file mode 100644 index 000000000000..7f3e4c8513a9 --- /dev/null +++ b/shell/platform/android/io/flutter/embedding/engine/systemchannels/LifecycleChannel.java @@ -0,0 +1,37 @@ +// 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.systemchannels; + +import android.support.annotation.NonNull; + +import io.flutter.embedding.engine.dart.DartExecutor; +import io.flutter.plugin.common.BasicMessageChannel; +import io.flutter.plugin.common.StringCodec; + +/** + * TODO(mattcarroll): fill in javadoc for LifecycleChannel. + */ +public class LifecycleChannel { + + @NonNull + public final BasicMessageChannel channel; + + public LifecycleChannel(@NonNull DartExecutor dartExecutor) { + this.channel = new BasicMessageChannel<>(dartExecutor, "flutter/lifecycle", StringCodec.INSTANCE); + } + + public void appIsInactive() { + channel.send("AppLifecycleState.inactive"); + } + + public void appIsResumed() { + channel.send("AppLifecycleState.resumed"); + } + + public void appIsPaused() { + channel.send("AppLifecycleState.paused"); + } + +} diff --git a/shell/platform/android/io/flutter/embedding/engine/systemchannels/LocalizationChannel.java b/shell/platform/android/io/flutter/embedding/engine/systemchannels/LocalizationChannel.java new file mode 100644 index 000000000000..ffb8f1f84a15 --- /dev/null +++ b/shell/platform/android/io/flutter/embedding/engine/systemchannels/LocalizationChannel.java @@ -0,0 +1,35 @@ +// 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.systemchannels; + +import android.support.annotation.NonNull; + +import java.util.Arrays; + +import io.flutter.embedding.engine.dart.DartExecutor; +import io.flutter.plugin.common.JSONMethodCodec; +import io.flutter.plugin.common.MethodChannel; + +/** + * TODO(mattcarroll): fill in javadoc for LocalizationChannel. + */ +public class LocalizationChannel { + + @NonNull + public final MethodChannel channel; + + public LocalizationChannel(@NonNull DartExecutor dartExecutor) { + this.channel = new MethodChannel(dartExecutor, "flutter/localization", JSONMethodCodec.INSTANCE); + } + + public void setLocale(String language, String country) { + channel.invokeMethod("setLocale", Arrays.asList(language, country)); + } + + public void setMethodCallHandler(MethodChannel.MethodCallHandler handler) { + channel.setMethodCallHandler(handler); + } + +} diff --git a/shell/platform/android/io/flutter/embedding/engine/systemchannels/NavigationChannel.java b/shell/platform/android/io/flutter/embedding/engine/systemchannels/NavigationChannel.java new file mode 100644 index 000000000000..f81f24204d39 --- /dev/null +++ b/shell/platform/android/io/flutter/embedding/engine/systemchannels/NavigationChannel.java @@ -0,0 +1,42 @@ +// 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.systemchannels; + +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; + +import io.flutter.embedding.engine.dart.DartExecutor; +import io.flutter.plugin.common.JSONMethodCodec; +import io.flutter.plugin.common.MethodChannel; + +/** + * TODO(mattcarroll): fill in javadoc for NavigationChannel. + */ +public class NavigationChannel { + + @NonNull + public final MethodChannel channel; + + public NavigationChannel(@NonNull DartExecutor dartExecutor) { + this.channel = new MethodChannel(dartExecutor, "flutter/navigation", JSONMethodCodec.INSTANCE); + } + + public void setInitialRoute(String initialRoute) { + channel.invokeMethod("setInitialRoute", initialRoute); + } + + public void pushRoute(String route) { + channel.invokeMethod("pushRoute", route); + } + + public void popRoute() { + channel.invokeMethod("popRoute", null); + } + + public void setMethodCallHandler(@Nullable MethodChannel.MethodCallHandler handler) { + channel.setMethodCallHandler(handler); + } + +} diff --git a/shell/platform/android/io/flutter/embedding/engine/systemchannels/PlatformChannel.java b/shell/platform/android/io/flutter/embedding/engine/systemchannels/PlatformChannel.java new file mode 100644 index 000000000000..b1ceb82b7a74 --- /dev/null +++ b/shell/platform/android/io/flutter/embedding/engine/systemchannels/PlatformChannel.java @@ -0,0 +1,29 @@ +// 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.systemchannels; + +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; + +import io.flutter.embedding.engine.dart.DartExecutor; +import io.flutter.plugin.common.JSONMethodCodec; +import io.flutter.plugin.common.MethodChannel; + +/** + * TODO(mattcarroll): fill in javadoc for PlatformChannel. + */ +public class PlatformChannel { + + public final MethodChannel channel; + + public PlatformChannel(@NonNull DartExecutor dartExecutor) { + this.channel = new MethodChannel(dartExecutor, "flutter/platform", JSONMethodCodec.INSTANCE); + } + + public void setMethodCallHandler(@Nullable MethodChannel.MethodCallHandler handler) { + channel.setMethodCallHandler(handler); + } + +} diff --git a/shell/platform/android/io/flutter/embedding/engine/systemchannels/SystemChannel.java b/shell/platform/android/io/flutter/embedding/engine/systemchannels/SystemChannel.java new file mode 100644 index 000000000000..46c85926daf1 --- /dev/null +++ b/shell/platform/android/io/flutter/embedding/engine/systemchannels/SystemChannel.java @@ -0,0 +1,34 @@ +// 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.systemchannels; + +import android.support.annotation.NonNull; + +import java.util.HashMap; +import java.util.Map; + +import io.flutter.embedding.engine.dart.DartExecutor; +import io.flutter.plugin.common.BasicMessageChannel; +import io.flutter.plugin.common.JSONMessageCodec; + +/** + * TODO(mattcarroll): fill in javadoc for SystemChannel. + */ +public class SystemChannel { + + @NonNull + public final BasicMessageChannel channel; + + public SystemChannel(@NonNull DartExecutor dartExecutor) { + this.channel = new BasicMessageChannel<>(dartExecutor, "flutter/system", JSONMessageCodec.INSTANCE); + } + + public void sendMemoryPressureWarning() { + Map message = new HashMap<>(1); + message.put("type", "memoryPressure"); + channel.send(message); + } + +} diff --git a/shell/platform/android/io/flutter/plugin/common/BinaryMessenger.java b/shell/platform/android/io/flutter/plugin/common/BinaryMessenger.java index c8f54e9e88f2..9f1e4eb4b67a 100644 --- a/shell/platform/android/io/flutter/plugin/common/BinaryMessenger.java +++ b/shell/platform/android/io/flutter/plugin/common/BinaryMessenger.java @@ -11,6 +11,11 @@ * The Flutter Dart code should use * BinaryMessages * to participate. + *

+ * {@code BinaryMessenger} is expected to be utilized from a single thread throughout the duration + * of its existence. If created on the main thread, then all invocations should take place on the + * main thread. If created on a background thread, then all invocations should take place on that + * background thread. * * @see BasicMessageChannel , which supports message passing with Strings and semi-structured messages. * @see MethodChannel , which supports communication using asynchronous method invocation. diff --git a/shell/platform/android/io/flutter/plugin/common/MethodChannel.java b/shell/platform/android/io/flutter/plugin/common/MethodChannel.java index d16671bc1c91..9f725e7bdf54 100644 --- a/shell/platform/android/io/flutter/plugin/common/MethodChannel.java +++ b/shell/platform/android/io/flutter/plugin/common/MethodChannel.java @@ -4,6 +4,7 @@ package io.flutter.plugin.common; +import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.util.Log; import io.flutter.plugin.common.BinaryMessenger.BinaryMessageHandler; @@ -66,7 +67,7 @@ public MethodChannel(BinaryMessenger messenger, String name, MethodCodec codec) * @param method the name String of the method. * @param arguments the arguments for the invocation, possibly null. */ - public void invokeMethod(String method, @Nullable Object arguments) { + public void invokeMethod(@NonNull String method, @Nullable Object arguments) { invokeMethod(method, arguments, null); } diff --git a/shell/platform/android/io/flutter/view/FlutterNativeView.java b/shell/platform/android/io/flutter/view/FlutterNativeView.java index c18f259f51e7..5988840ca7d3 100644 --- a/shell/platform/android/io/flutter/view/FlutterNativeView.java +++ b/shell/platform/android/io/flutter/view/FlutterNativeView.java @@ -179,7 +179,7 @@ private void attach(FlutterNativeView view, boolean isBackgroundView) { 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) { + public void handleMessageFromDart(final String channel, byte[] message, final int replyId) { assertAttached(); BinaryMessageHandler handler = mMessageHandlers.get(channel); if (handler != null) { @@ -190,7 +190,7 @@ public void handlePlatformMessage(final String channel, byte[] message, final in @Override public void reply(ByteBuffer reply) { if (!isAttached()) { - Log.d(TAG, "handlePlatformMessage replying ot a detached view, channel=" + channel); + Log.d(TAG, "handleMessageFromDart replying ot a detached view, channel=" + channel); return; } if (done.getAndSet(true)) { diff --git a/shell/platform/android/io/flutter/view/FlutterView.java b/shell/platform/android/io/flutter/view/FlutterView.java index e7d8c74ac6dd..49c2c8d6d694 100644 --- a/shell/platform/android/io/flutter/view/FlutterView.java +++ b/shell/platform/android/io/flutter/view/FlutterView.java @@ -27,7 +27,12 @@ import android.view.inputmethod.InputMethodManager; import io.flutter.app.FlutterPluginRegistry; import io.flutter.embedding.engine.dart.DartExecutor; +import io.flutter.embedding.engine.systemchannels.KeyEventChannel; +import io.flutter.embedding.engine.systemchannels.LifecycleChannel; +import io.flutter.embedding.engine.systemchannels.LocalizationChannel; +import io.flutter.embedding.engine.systemchannels.NavigationChannel; import io.flutter.embedding.engine.systemchannels.SettingsChannel; +import io.flutter.embedding.engine.systemchannels.SystemChannel; import io.flutter.plugin.common.*; import io.flutter.plugin.editing.TextInputPlugin; import io.flutter.plugin.platform.PlatformPlugin; @@ -81,17 +86,17 @@ static final class ViewportMetrics { } private final DartExecutor dartExecutor; + private final NavigationChannel navigationChannel; + private final KeyEventChannel keyEventChannel; + private final LifecycleChannel lifecycleChannel; + private final SettingsChannel settingsChannel; + private final SystemChannel systemChannel; private final InputMethodManager mImm; private final TextInputPlugin mTextInputPlugin; private final SurfaceHolder.Callback mSurfaceCallback; private final ViewportMetrics mMetrics; private final AccessibilityManager mAccessibilityManager; private final MethodChannel mFlutterLocalizationChannel; - private final MethodChannel mFlutterNavigationChannel; - private final BasicMessageChannel mFlutterKeyEventChannel; - private final BasicMessageChannel mFlutterLifecycleChannel; - private final BasicMessageChannel mFlutterSystemChannel; - private final SettingsChannel settingsChannel; private final List mActivityLifecycleListeners; private final List mFirstFrameListeners; private final AtomicLong nextTextureId = new AtomicLong(0L); @@ -154,12 +159,12 @@ public void surfaceDestroyed(SurfaceHolder holder) { mFirstFrameListeners = new ArrayList<>(); // Configure the platform plugins and flutter channels. - mFlutterLocalizationChannel = new MethodChannel(this, "flutter/localization", JSONMethodCodec.INSTANCE); - mFlutterNavigationChannel = new MethodChannel(this, "flutter/navigation", JSONMethodCodec.INSTANCE); - mFlutterKeyEventChannel = new BasicMessageChannel<>(this, "flutter/keyevent", JSONMessageCodec.INSTANCE); - mFlutterLifecycleChannel = new BasicMessageChannel<>(this, "flutter/lifecycle", StringCodec.INSTANCE); - mFlutterSystemChannel = new BasicMessageChannel<>(this, "flutter/system", JSONMessageCodec.INSTANCE); + navigationChannel = new NavigationChannel(dartExecutor); + keyEventChannel = new KeyEventChannel(dartExecutor); + lifecycleChannel = new LifecycleChannel(dartExecutor); + systemChannel = new SystemChannel(dartExecutor); settingsChannel = new SettingsChannel(dartExecutor); + mFlutterLocalizationChannel = new MethodChannel(this, "flutter/localization", JSONMethodCodec.INSTANCE); PlatformPlugin platformPlugin = new PlatformPlugin(activity); MethodChannel flutterPlatformChannel = new MethodChannel(this, "flutter/platform", JSONMethodCodec.INSTANCE); @@ -173,25 +178,12 @@ public void surfaceDestroyed(SurfaceHolder holder) { sendUserPlatformSettingsToDart(); } - private void encodeKeyEvent(KeyEvent event, Map message) { - message.put("flags", event.getFlags()); - message.put("codePoint", event.getUnicodeChar()); - message.put("keyCode", event.getKeyCode()); - message.put("scanCode", event.getScanCode()); - message.put("metaState", event.getMetaState()); - } - @Override public boolean onKeyUp(int keyCode, KeyEvent event) { if (!isAttached()) { return super.onKeyUp(keyCode, event); } - - Map message = new HashMap<>(); - message.put("type", "keyup"); - message.put("keymap", "android"); - encodeKeyEvent(event, message); - mFlutterKeyEventChannel.send(message); + keyEventChannel.keyUp(event); return super.onKeyUp(keyCode, event); } @@ -207,11 +199,7 @@ public boolean onKeyDown(int keyCode, KeyEvent event) { } } - Map message = new HashMap<>(); - message.put("type", "keydown"); - message.put("keymap", "android"); - encodeKeyEvent(event, message); - mFlutterKeyEventChannel.send(message); + keyEventChannel.keyDown(event); return super.onKeyDown(keyCode, event); } @@ -236,11 +224,11 @@ public void addActivityLifecycleListener(ActivityLifecycleListener listener) { } public void onStart() { - mFlutterLifecycleChannel.send("AppLifecycleState.inactive"); + lifecycleChannel.appIsInactive(); } public void onPause() { - mFlutterLifecycleChannel.send("AppLifecycleState.inactive"); + lifecycleChannel.appIsInactive(); } public void onPostResume() { @@ -248,17 +236,15 @@ public void onPostResume() { for (ActivityLifecycleListener listener : mActivityLifecycleListeners) { listener.onPostResume(); } - mFlutterLifecycleChannel.send("AppLifecycleState.resumed"); + lifecycleChannel.appIsResumed(); } public void onStop() { - mFlutterLifecycleChannel.send("AppLifecycleState.paused"); + lifecycleChannel.appIsPaused(); } public void onMemoryPressure() { - Map message = new HashMap<>(1); - message.put("type", "memoryPressure"); - mFlutterSystemChannel.send(message); + systemChannel.sendMemoryPressureWarning(); } /** @@ -297,15 +283,15 @@ public void disableTransparentBackground() { } public void setInitialRoute(String route) { - mFlutterNavigationChannel.invokeMethod("setInitialRoute", route); + navigationChannel.setInitialRoute(route); } public void pushRoute(String route) { - mFlutterNavigationChannel.invokeMethod("pushRoute", route); + navigationChannel.pushRoute(route); } public void popRoute() { - mFlutterNavigationChannel.invokeMethod("popRoute", null); + navigationChannel.popRoute(); } private void sendUserPlatformSettingsToDart() {