Skip to content

Commit 7ead767

Browse files
authored
Merge pull request alibaba#9 from alibaba/master
update
2 parents 14d8bfa + 1571d96 commit 7ead767

21 files changed

+434
-143
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,4 @@ example/android/app/.classpath
1717
example/android/app/.project
1818
example/android/.project
1919
flutter_boost
20+
.flutter-plugins-dependencies

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ addons:
99
- libstdc++6
1010
# - fonts-droid
1111
before_script:
12-
- git clone https://github.com/flutter/flutter.git -b v1.12.13-hotfixes --depth 1
12+
- git clone https://github.com/flutter/flutter.git -b flutter-1.17-candidate.3 --depth 1
1313
- ./flutter/bin/flutter doctor
1414
script:
1515
- ./flutter/bin/flutter test --coverage --coverage-path=lcov.info

Frequently Asked Question.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ bool isTopContainer = FlutterBoost.BoostContainer.of(context).onstage
3030
回答:无障碍模式下目前Flutter Engine有bug,已经提交issue和PR给flutter啦。请参考这个issue:https://github.com/alibaba/flutter_boost/issues/488及其分析。提交给flutter的PR见这里:https://github.com/flutter/engine/pull/14155
3131

3232
### 5. 在ios模拟器下运行最新的flutter boost会闪退
33-
回答:如上面第4条所说的,最新的flutter engine在voice over下有bug,会导致crash。因为模拟器下flutter默认会将voice over模式打开,所以其实就是辅助模式,这回触发上面的bug:“在ios中voice over打开,demo在点击交互会crash”。
33+
回答:如上面第4条所说的,最新的flutter engine在voice over下有bug,会导致crash。因为模拟器下flutter默认会将voice over模式打开,所以其实就是辅助模式,这会触发上面的bug:“在ios中voice over打开,demo在点击交互会crash”。
3434
可参考Engine的代码注释:
3535
```c++
3636
#if TARGET_OS_SIMULATOR

README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,11 @@ flutter_boost:
5656

5757
# Boost Integration
5858

59-
Please see the boost example for details.
59+
Please see
60+
61+
1. Boost detail example
62+
63+
2. integrated document <a href="INTEGRATION.md">Integration </a>
6064

6165
# FAQ
6266
please read this document:

README_CN.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,10 @@ flutter_boost:
5555

5656
## boost集成
5757

58-
集成请看boost的Examples
58+
集成请看:
59+
1. boost的Examples
60+
61+
2. 集成文档 <a href="INTEGRATION.md">Integration </a>
5962

6063

6164

android/src/main/java/com/idlefish/flutterboost/FlutterBoost.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,18 @@ public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
6464
//fix crash:'FlutterBoostPlugin not register yet'
6565
//case: initFlutter after Activity.OnCreate method,and then called start/stop crash
6666
// In SplashActivity ,showDialog(in OnCreate method) to check permission, if authorized, then init sdk and jump homePage)
67+
68+
// fix bug : The LauncherActivity will be launch by clicking app icon when app enter background in HuaWei Rom, cause missing forgoround event
69+
if(mEnterActivityCreate && mCurrentActiveActivity == null) {
70+
Intent intent = activity.getIntent();
71+
if (!activity.isTaskRoot()
72+
&& intent != null
73+
&& intent.hasCategory(Intent.CATEGORY_LAUNCHER)
74+
&& intent.getAction() != null
75+
&& intent.getAction().equals(Intent.ACTION_MAIN)) {
76+
return;
77+
}
78+
}
6779
mEnterActivityCreate = true;
6880
mCurrentActiveActivity = activity;
6981
if (mPlatform.whenEngineStart() == ConfigBuilder.ANY_ACTIVITY_CREATED) {

android/src/main/java/com/idlefish/flutterboost/FlutterViewContainerManager.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ void pushRecord(IContainerRecord record) {
7474
}
7575

7676
void popRecord(IContainerRecord record) {
77+
if(mRecordStack.empty()) return;
78+
7779
if(mRecordStack.peek() == record) {
7880
mRecordStack.pop();
7981
}
Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
package com.idlefish.flutterboost;
2+
import android.content.Context;
3+
import android.graphics.SurfaceTexture;
4+
import android.util.AttributeSet;
5+
import android.view.Surface;
6+
import android.view.TextureView;
7+
8+
import androidx.annotation.NonNull;
9+
import androidx.annotation.Nullable;
10+
import io.flutter.Log;
11+
import io.flutter.embedding.engine.renderer.FlutterRenderer;
12+
import io.flutter.embedding.engine.renderer.RenderSurface;
13+
14+
public class XFlutterTextureView extends TextureView implements RenderSurface {
15+
private static final String TAG = "FlutterTextureView";
16+
17+
private boolean isSurfaceAvailableForRendering = false;
18+
private boolean isAttachedToFlutterRenderer = false;
19+
@Nullable
20+
private FlutterRenderer flutterRenderer;
21+
22+
private Surface renderSurface;
23+
24+
// Connects the {@code SurfaceTexture} beneath this {@code TextureView} with Flutter's native code.
25+
// Callbacks are received by this Object and then those messages are forwarded to our
26+
// FlutterRenderer, and then on to the JNI bridge over to native Flutter code.
27+
private final SurfaceTextureListener surfaceTextureListener = new SurfaceTextureListener() {
28+
@Override
29+
public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int width, int height) {
30+
Log.v(TAG, "SurfaceTextureListener.onSurfaceTextureAvailable()");
31+
isSurfaceAvailableForRendering = true;
32+
33+
// If we're already attached to a FlutterRenderer then we're now attached to both a renderer
34+
// and the Android window, so we can begin rendering now.
35+
if (isAttachedToFlutterRenderer) {
36+
connectSurfaceToRenderer();
37+
}
38+
}
39+
40+
@Override
41+
public void onSurfaceTextureSizeChanged(@NonNull SurfaceTexture surface, int width, int height) {
42+
Log.v(TAG, "SurfaceTextureListener.onSurfaceTextureSizeChanged()");
43+
if (isAttachedToFlutterRenderer) {
44+
changeSurfaceSize(width, height);
45+
}
46+
}
47+
48+
@Override
49+
public void onSurfaceTextureUpdated(@NonNull SurfaceTexture surface) {
50+
// Invoked every time a new frame is available. We don't care.
51+
}
52+
53+
@Override
54+
public boolean onSurfaceTextureDestroyed(@NonNull SurfaceTexture surface) {
55+
Log.v(TAG, "SurfaceTextureListener.onSurfaceTextureDestroyed()");
56+
isSurfaceAvailableForRendering = false;
57+
58+
// If we're attached to a FlutterRenderer then we need to notify it that our SurfaceTexture
59+
// has been destroyed.
60+
if (isAttachedToFlutterRenderer) {
61+
disconnectSurfaceFromRenderer();
62+
}
63+
64+
// Return true to indicate that no further painting will take place
65+
// within this SurfaceTexture.
66+
return true;
67+
}
68+
};
69+
70+
/**
71+
* Constructs a {@code FlutterTextureView} programmatically, without any XML attributes.
72+
*/
73+
public XFlutterTextureView(@NonNull Context context) {
74+
this(context, null);
75+
}
76+
77+
/**
78+
* Constructs a {@code FlutterTextureView} in an XML-inflation-compliant manner.
79+
*/
80+
public XFlutterTextureView(@NonNull Context context, @Nullable AttributeSet attrs) {
81+
super(context, attrs);
82+
init();
83+
}
84+
85+
private void init() {
86+
// Listen for when our underlying SurfaceTexture becomes available, changes size, or
87+
// gets destroyed, and take the appropriate actions.
88+
setSurfaceTextureListener(surfaceTextureListener);
89+
}
90+
91+
@Nullable
92+
@Override
93+
public FlutterRenderer getAttachedRenderer() {
94+
return flutterRenderer;
95+
}
96+
97+
/**
98+
* Invoked by the owner of this {@code FlutterTextureView} when it wants to begin rendering
99+
* a Flutter UI to this {@code FlutterTextureView}.
100+
*
101+
* If an Android {@link SurfaceTexture} is available, this method will give that
102+
* {@link SurfaceTexture} to the given {@link FlutterRenderer} to begin rendering
103+
* Flutter's UI to this {@code FlutterTextureView}.
104+
*
105+
* If no Android {@link SurfaceTexture} is available yet, this {@code FlutterTextureView}
106+
* will wait until a {@link SurfaceTexture} becomes available and then give that
107+
* {@link SurfaceTexture} to the given {@link FlutterRenderer} to begin rendering
108+
* Flutter's UI to this {@code FlutterTextureView}.
109+
*/
110+
public void attachToRenderer(@NonNull FlutterRenderer flutterRenderer) {
111+
Log.v(TAG, "Attaching to FlutterRenderer.");
112+
if (this.flutterRenderer != null) {
113+
Log.v(TAG, "Already connected to a FlutterRenderer. Detaching from old one and attaching to new one.");
114+
this.flutterRenderer.stopRenderingToSurface();
115+
}
116+
117+
this.flutterRenderer = flutterRenderer;
118+
isAttachedToFlutterRenderer = true;
119+
120+
// If we're already attached to an Android window then we're now attached to both a renderer
121+
// and the Android window. We can begin rendering now.
122+
if (isSurfaceAvailableForRendering) {
123+
Log.v(TAG, "Surface is available for rendering. Connecting FlutterRenderer to Android surface.");
124+
connectSurfaceToRenderer();
125+
}
126+
}
127+
128+
/**
129+
* Invoked by the owner of this {@code FlutterTextureView} when it no longer wants to render
130+
* a Flutter UI to this {@code FlutterTextureView}.
131+
*
132+
* This method will cease any on-going rendering from Flutter to this {@code FlutterTextureView}.
133+
*/
134+
public void detachFromRenderer() {
135+
if (flutterRenderer != null) {
136+
// If we're attached to an Android window then we were rendering a Flutter UI. Now that
137+
// this FlutterTextureView is detached from the FlutterRenderer, we need to stop rendering.
138+
// TODO(mattcarroll): introduce a isRendererConnectedToSurface() to wrap "getWindowToken() != null"
139+
if (getWindowToken() != null) {
140+
Log.v(TAG, "Disconnecting FlutterRenderer from Android surface.");
141+
disconnectSurfaceFromRenderer();
142+
}
143+
144+
flutterRenderer = null;
145+
isAttachedToFlutterRenderer = false;
146+
} else {
147+
Log.w(TAG, "detachFromRenderer() invoked when no FlutterRenderer was attached.");
148+
}
149+
}
150+
151+
// FlutterRenderer and getSurfaceTexture() must both be non-null.
152+
private void connectSurfaceToRenderer() {
153+
if (flutterRenderer == null || getSurfaceTexture() == null) {
154+
throw new IllegalStateException("connectSurfaceToRenderer() should only be called when flutterRenderer and getSurfaceTexture() are non-null.");
155+
}
156+
157+
// flutterRenderer.startRenderingToSurface(new Surface(getSurfaceTexture()));
158+
159+
renderSurface = new Surface(getSurfaceTexture());
160+
flutterRenderer.startRenderingToSurface(renderSurface);
161+
}
162+
163+
// FlutterRenderer must be non-null.
164+
private void changeSurfaceSize(int width, int height) {
165+
if (flutterRenderer == null) {
166+
throw new IllegalStateException("changeSurfaceSize() should only be called when flutterRenderer is non-null.");
167+
}
168+
169+
Log.v(TAG, "Notifying FlutterRenderer that Android surface size has changed to " + width + " x " + height);
170+
flutterRenderer.surfaceChanged(width, height);
171+
}
172+
173+
// FlutterRenderer must be non-null.
174+
private void disconnectSurfaceFromRenderer() {
175+
if (flutterRenderer == null) {
176+
throw new IllegalStateException("disconnectSurfaceFromRenderer() should only be called when flutterRenderer is non-null.");
177+
}
178+
179+
flutterRenderer.stopRenderingToSurface();
180+
if(renderSurface!=null){
181+
renderSurface.release();
182+
renderSurface = null;
183+
}
184+
185+
}
186+
}

android/src/main/java/com/idlefish/flutterboost/XFlutterView.java

Lines changed: 19 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -38,32 +38,12 @@
3838
import io.flutter.embedding.engine.renderer.FlutterRenderer;
3939
import io.flutter.embedding.engine.renderer.FlutterUiDisplayListener;
4040
import io.flutter.embedding.engine.renderer.RenderSurface;
41-
import io.flutter.embedding.engine.systemchannels.TextInputChannel;
41+
import io.flutter.embedding.engine.systemchannels.SettingsChannel;
4242
import io.flutter.plugin.editing.TextInputPlugin;
4343
import io.flutter.plugin.platform.PlatformViewsController;
4444
import io.flutter.view.AccessibilityBridge;
4545

46-
/**
47-
* Displays a Flutter UI on an Android device.
48-
* <p>
49-
* A {@code FlutterView}'s UI is painted by a corresponding {@link FlutterEngine}.
50-
* <p>
51-
* A {@code FlutterView} can operate in 2 different {@link RenderMode}s:
52-
* <ol>
53-
* <li>{@link RenderMode#surface}, which paints a Flutter UI to a {@link android.view.SurfaceView}.
54-
* This mode has the best performance, but a {@code FlutterView} in this mode cannot be positioned
55-
* between 2 other Android {@code View}s in the z-index, nor can it be animated/transformed.
56-
* Unless the special capabilities of a {@link android.graphics.SurfaceTexture} are required,
57-
* developers should strongly prefer this render mode.</li>
58-
* <li>{@link RenderMode#texture}, which paints a Flutter UI to a {@link android.graphics.SurfaceTexture}.
59-
* This mode is not as performant as {@link RenderMode#surface}, but a {@code FlutterView} in this
60-
* mode can be animated and transformed, as well as positioned in the z-index between 2+ other
61-
* Android {@code Views}. Unless the special capabilities of a {@link android.graphics.SurfaceTexture}
62-
* are required, developers should strongly prefer the {@link RenderMode#surface} render mode.</li>
63-
* </ol>
64-
* See <a>https://source.android.com/devices/graphics/arch-tv#surface_or_texture</a> for more
65-
* information comparing {@link android.view.SurfaceView} and {@link android.view.TextureView}.
66-
*/
46+
6747
public class XFlutterView extends FrameLayout {
6848
private static final String TAG = "FlutterView";
6949

@@ -150,26 +130,12 @@ public XFlutterView(@NonNull Context context) {
150130
this(context, null, null, null);
151131
}
152132

153-
/**
154-
* Constructs a {@code FlutterView} programmatically, without any XML attributes,
155-
* and allows selection of a {@link #renderMode}.
156-
* <p>
157-
* {@link #transparencyMode} defaults to {@link TransparencyMode#opaque}.
158-
* <p>
159-
* {@code FlutterView} requires an {@code Activity} instead of a generic {@code Context}
160-
* to be compatible with {@link PlatformViewsController}.
161-
*/
133+
162134
public XFlutterView(@NonNull Context context, @NonNull FlutterView.RenderMode renderMode) {
163135
this(context, null, renderMode, null);
164136
}
165137

166-
/**
167-
* Constructs a {@code FlutterView} programmatically, without any XML attributes,
168-
* assumes the use of {@link RenderMode#surface}, and allows selection of a {@link #transparencyMode}.
169-
* <p>
170-
* {@code FlutterView} requires an {@code Activity} instead of a generic {@code Context}
171-
* to be compatible with {@link PlatformViewsController}.
172-
*/
138+
173139
public XFlutterView(@NonNull Context context, @NonNull FlutterView.TransparencyMode transparencyMode) {
174140
this(context, null, FlutterView.RenderMode.surface, transparencyMode);
175141
}
@@ -217,7 +183,7 @@ private void init() {
217183
break;
218184
case texture:
219185
Log.v(TAG, "Internally using a FlutterTextureView.");
220-
FlutterTextureView flutterTextureView = new FlutterTextureView(getContext());
186+
XFlutterTextureView flutterTextureView = new XFlutterTextureView(getContext());
221187
renderSurface = flutterTextureView;
222188
addView(flutterTextureView);
223189
break;
@@ -434,7 +400,7 @@ public InputConnection onCreateInputConnection(@NonNull EditorInfo outAttrs) {
434400
*/
435401
@Override
436402
public boolean checkInputConnectionProxy(View view) {
437-
return flutterEngine != null
403+
return flutterEngine != null&&view!=null
438404
? flutterEngine.getPlatformViewsController().checkInputConnectionProxy(view)
439405
: super.checkInputConnectionProxy(view);
440406
}
@@ -609,16 +575,9 @@ public void attachToFlutterEngine(
609575
this.flutterEngine.getPlatformViewsController().attachToView(this);
610576

611577

612-
613-
if(textInputPlugin==null){
614-
textInputPlugin = new XTextInputPlugin(
615-
this,
616-
flutterEngine.getTextInputChannel(),
617-
this.flutterEngine.getPlatformViewsController()
618-
);
619-
}
620-
621-
textInputPlugin.setTextInputMethodHandler();
578+
textInputPlugin= XTextInputPlugin.getTextInputPlugin( this.flutterEngine.getDartExecutor(),
579+
this.flutterEngine.getPlatformViewsController());
580+
textInputPlugin.updateView(this);
622581
textInputPlugin.getInputMethodManager().restartInput(this);
623582

624583

@@ -717,7 +676,7 @@ public void detachFromFlutterEngine() {
717676
}
718677
public void release(){
719678
if(textInputPlugin!=null){
720-
textInputPlugin.release();
679+
textInputPlugin.release(this);
721680
}
722681
}
723682

@@ -788,9 +747,17 @@ private void sendLocalesToFlutter(@NonNull Configuration config) {
788747
*/
789748
private void sendUserSettingsToFlutter() {
790749
if(flutterEngine!=null&&flutterEngine.getSettingsChannel()!=null){
791-
flutterEngine.getSettingsChannel().startMessage()
750+
// Lookup the current brightness of the Android OS.
751+
boolean isNightModeOn = (getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES;
752+
SettingsChannel.PlatformBrightness brightness = isNightModeOn
753+
? SettingsChannel.PlatformBrightness.dark
754+
: SettingsChannel.PlatformBrightness.light;
755+
756+
757+
flutterEngine.getSettingsChannel().startMessage()
792758
.setTextScaleFactor(getResources().getConfiguration().fontScale)
793759
.setUse24HourFormat(DateFormat.is24HourFormat(getContext()))
760+
.setPlatformBrightness(brightness)
794761
.send();
795762
}
796763
}

0 commit comments

Comments
 (0)