• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 package io.flutter.view;
6 
7 import android.app.Activity;
8 import android.content.Context;
9 import android.support.annotation.NonNull;
10 import android.support.annotation.UiThread;
11 import android.util.Log;
12 import io.flutter.app.FlutterPluginRegistry;
13 import io.flutter.embedding.engine.FlutterJNI;
14 import io.flutter.embedding.engine.FlutterEngine.EngineLifecycleListener;
15 import io.flutter.embedding.engine.dart.DartExecutor;
16 import io.flutter.embedding.engine.renderer.FlutterRenderer;
17 import io.flutter.embedding.engine.renderer.FlutterRenderer.RenderSurface;
18 import io.flutter.embedding.engine.renderer.OnFirstFrameRenderedListener;
19 import io.flutter.plugin.common.*;
20 import java.nio.ByteBuffer;
21 import java.util.concurrent.atomic.AtomicBoolean;
22 import java.util.HashMap;
23 import java.util.Map;
24 
25 import io.flutter.embedding.engine.dart.PlatformMessageHandler;
26 
27 public class FlutterNativeView implements BinaryMessenger {
28     private static final String TAG = "FlutterNativeView";
29 
30     private final FlutterPluginRegistry mPluginRegistry;
31     private final DartExecutor dartExecutor;
32     private FlutterView mFlutterView;
33     private final FlutterJNI mFlutterJNI;
34     private final Context mContext;
35     private boolean applicationIsRunning;
36 
FlutterNativeView(@onNull Context context)37     public FlutterNativeView(@NonNull Context context) {
38         this(context, false);
39     }
40 
FlutterNativeView(@onNull Context context, boolean isBackgroundView)41     public FlutterNativeView(@NonNull Context context, boolean isBackgroundView) {
42         mContext = context;
43         mPluginRegistry = new FlutterPluginRegistry(this, context);
44         mFlutterJNI = new FlutterJNI();
45         mFlutterJNI.setRenderSurface(new RenderSurfaceImpl());
46         this.dartExecutor = new DartExecutor(mFlutterJNI, context.getAssets());
47         mFlutterJNI.addEngineLifecycleListener(new EngineLifecycleListenerImpl());
48         attach(this, isBackgroundView);
49         assertAttached();
50     }
51 
detachFromFlutterView()52     public void detachFromFlutterView() {
53         mPluginRegistry.detach();
54         mFlutterView = null;
55     }
56 
destroy()57     public void destroy() {
58         mPluginRegistry.destroy();
59         dartExecutor.onDetachedFromJNI();
60         mFlutterView = null;
61         mFlutterJNI.detachFromNativeAndReleaseResources();
62         applicationIsRunning = false;
63     }
64 
65     @NonNull
getDartExecutor()66     public DartExecutor getDartExecutor() {
67         return dartExecutor;
68     }
69 
70     @NonNull
getPluginRegistry()71     public FlutterPluginRegistry getPluginRegistry() {
72         return mPluginRegistry;
73     }
74 
attachViewAndActivity(FlutterView flutterView, Activity activity)75     public void attachViewAndActivity(FlutterView flutterView, Activity activity) {
76         mFlutterView = flutterView;
77         mPluginRegistry.attach(flutterView, activity);
78     }
79 
isAttached()80     public boolean isAttached() {
81         return mFlutterJNI.isAttached();
82     }
83 
assertAttached()84     public void assertAttached() {
85         if (!isAttached()) throw new AssertionError("Platform view is not attached");
86     }
87 
runFromBundle(FlutterRunArguments args)88     public void runFromBundle(FlutterRunArguments args) {
89         if (args.entrypoint == null) {
90             throw new AssertionError("An entrypoint must be specified");
91         }
92         assertAttached();
93         if (applicationIsRunning)
94             throw new AssertionError(
95                     "This Flutter engine instance is already running an application");
96         mFlutterJNI.runBundleAndSnapshotFromLibrary(
97             args.bundlePath,
98             args.entrypoint,
99             args.libraryPath,
100             mContext.getResources().getAssets()
101         );
102 
103         applicationIsRunning = true;
104     }
105 
isApplicationRunning()106     public boolean isApplicationRunning() {
107         return applicationIsRunning;
108     }
109 
getObservatoryUri()110     public static String getObservatoryUri() {
111         return FlutterJNI.getObservatoryUri();
112     }
113 
114     @Override
115     @UiThread
send(String channel, ByteBuffer message)116     public void send(String channel, ByteBuffer message) {
117         dartExecutor.send(channel, message);
118     }
119 
120     @Override
121     @UiThread
send(String channel, ByteBuffer message, BinaryReply callback)122     public void send(String channel, ByteBuffer message, BinaryReply callback) {
123         if (!isAttached()) {
124             Log.d(TAG, "FlutterView.send called on a detached view, channel=" + channel);
125             return;
126         }
127 
128         dartExecutor.send(channel, message, callback);
129     }
130 
131     @Override
132     @UiThread
setMessageHandler(String channel, BinaryMessageHandler handler)133     public void setMessageHandler(String channel, BinaryMessageHandler handler) {
134         dartExecutor.setMessageHandler(channel, handler);
135     }
136 
getFlutterJNI()137     /*package*/ FlutterJNI getFlutterJNI() {
138         return mFlutterJNI;
139     }
140 
attach(FlutterNativeView view, boolean isBackgroundView)141     private void attach(FlutterNativeView view, boolean isBackgroundView) {
142         mFlutterJNI.attachToNative(isBackgroundView);
143         dartExecutor.onAttachedToJNI();
144     }
145 
146     private final class RenderSurfaceImpl implements RenderSurface {
147         @Override
attachToRenderer(@onNull FlutterRenderer renderer)148         public void attachToRenderer(@NonNull FlutterRenderer renderer) {
149             // Not relevant for v1 embedding.
150         }
151 
152         @Override
detachFromRenderer()153         public void detachFromRenderer() {
154             // Not relevant for v1 embedding.
155         }
156 
157         // Called by native to update the semantics/accessibility tree.
updateSemantics(ByteBuffer buffer, String[] strings)158         public void updateSemantics(ByteBuffer buffer, String[] strings) {
159             if (mFlutterView == null) {
160                 return;
161             }
162             mFlutterView.updateSemantics(buffer, strings);
163         }
164 
165         // Called by native to update the custom accessibility actions.
updateCustomAccessibilityActions(ByteBuffer buffer, String[] strings)166         public void updateCustomAccessibilityActions(ByteBuffer buffer, String[] strings) {
167             if (mFlutterView == null) {
168                 return;
169             }
170             mFlutterView.updateCustomAccessibilityActions(buffer, strings);
171         }
172 
173         // Called by native to notify first Flutter frame rendered.
onFirstFrameRendered()174         public void onFirstFrameRendered() {
175             if (mFlutterView == null) {
176                 return;
177             }
178             mFlutterView.onFirstFrame();
179         }
180 
181         @Override
addOnFirstFrameRenderedListener(@onNull OnFirstFrameRenderedListener listener)182         public void addOnFirstFrameRenderedListener(@NonNull OnFirstFrameRenderedListener listener) {}
183 
184         @Override
removeOnFirstFrameRenderedListener(@onNull OnFirstFrameRenderedListener listener)185         public void removeOnFirstFrameRenderedListener(@NonNull OnFirstFrameRenderedListener listener) {}
186     }
187 
188     private final class EngineLifecycleListenerImpl implements EngineLifecycleListener {
189         // Called by native to notify when the engine is restarted (cold reload).
190         @SuppressWarnings("unused")
onPreEngineRestart()191         public void onPreEngineRestart() {
192             if (mFlutterView != null) {
193                 mFlutterView.resetAccessibilityTree();
194             }
195             if (mPluginRegistry == null) {
196                 return;
197             }
198             mPluginRegistry.onPreEngineRestart();
199         }
200     }
201 }
202