Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
F
flutter_boost_1.22.4
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
李增强
flutter_boost_1.22.4
Commits
1d3ace17
Commit
1d3ace17
authored
Sep 06, 2019
by
yangwu.jia
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'v1.5.4-hotfixes' into develop
# Conflicts: # .gitignore
parents
13ba5551
d58a2f06
Changes
16
Hide whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
686 additions
and
58 deletions
+686
-58
.gitignore
.gitignore
+7
-1
android/src/main/java/com/idlefish/flutterboost/BoostFlutterEngine.java
...in/java/com/idlefish/flutterboost/BoostFlutterEngine.java
+1
-0
android/src/main/java/com/idlefish/flutterboost/BoostFlutterView.java
...main/java/com/idlefish/flutterboost/BoostFlutterView.java
+1
-9
android/src/main/java/com/idlefish/flutterboost/Utils.java
android/src/main/java/com/idlefish/flutterboost/Utils.java
+38
-0
android/src/main/java/com/idlefish/flutterboost/XAndroidKeyProcessor.java
.../java/com/idlefish/flutterboost/XAndroidKeyProcessor.java
+97
-0
android/src/main/java/com/idlefish/flutterboost/XFlutterView.java
...src/main/java/com/idlefish/flutterboost/XFlutterView.java
+62
-42
android/src/main/java/com/idlefish/flutterboost/XInputConnectionAdaptor.java
...va/com/idlefish/flutterboost/XInputConnectionAdaptor.java
+208
-0
android/src/main/java/com/idlefish/flutterboost/XTextInputPlugin.java
...main/java/com/idlefish/flutterboost/XTextInputPlugin.java
+223
-0
android/src/main/java/com/idlefish/flutterboost/containers/BoostFlutterActivity.java
...dlefish/flutterboost/containers/BoostFlutterActivity.java
+2
-0
ios/Classes/Engine/FLBFlutterEngine.m
ios/Classes/Engine/FLBFlutterEngine.m
+5
-0
ios/Classes/Messaging/BoostMessageChannel.h
ios/Classes/Messaging/BoostMessageChannel.h
+2
-0
ios/Classes/Messaging/BoostMessageChannel.mm
ios/Classes/Messaging/BoostMessageChannel.mm
+24
-0
ios/Classes/container/FLBFlutterViewContainer.h
ios/Classes/container/FLBFlutterViewContainer.h
+3
-1
ios/Classes/container/FLBFlutterViewContainer.m
ios/Classes/container/FLBFlutterViewContainer.m
+10
-5
lib/container/boost_container.dart
lib/container/boost_container.dart
+1
-0
lib/container/container_coordinator.dart
lib/container/container_coordinator.dart
+2
-0
No files found.
.gitignore
View file @
1d3ace17
...
...
@@ -9,4 +9,10 @@ build/
pubspec.lock
.flutter-plugins
flutter
flutter_boost
IDEWorkspaceChecks.plist
org.eclipse.buildship.core.prefs
Breakpoints_v2.xcbkptlist
flutter_boost2
example/android/app/.classpath
example/android/app/.project
example/android/.project
android/src/main/java/com/idlefish/flutterboost/BoostFlutterEngine.java
View file @
1d3ace17
...
...
@@ -23,6 +23,7 @@ import io.flutter.embedding.engine.renderer.FlutterRenderer;
import
io.flutter.embedding.engine.renderer.OnFirstFrameRenderedListener
;
import
io.flutter.plugin.common.BinaryMessenger
;
import
io.flutter.plugin.common.PluginRegistry
;
import
io.flutter.plugin.editing.TextInputPlugin
;
import
io.flutter.plugin.platform.PlatformViewRegistry
;
import
io.flutter.view.FlutterMain
;
import
io.flutter.view.FlutterView
;
...
...
android/src/main/java/com/idlefish/flutterboost/BoostFlutterView.java
View file @
1d3ace17
...
...
@@ -55,8 +55,6 @@ public class BoostFlutterView extends FrameLayout {
private
XFlutterView
mFlutterView
;
private
PlatformPlugin
mPlatformPlugin
;
private
Bundle
mArguments
;
private
RenderingProgressCoverCreator
mRenderingProgressCoverCreator
;
...
...
@@ -116,8 +114,6 @@ public class BoostFlutterView extends FrameLayout {
mArguments
=
new
Bundle
();
}
mPlatformPlugin
=
new
PlatformPlugin
((
Activity
)
getContext
(),
mFlutterEngine
.
getPlatformChannel
());
mFlutterView
=
new
XFlutterView
(
getContext
(),
getRenderMode
(),
getTransparencyMode
());
addView
(
mFlutterView
,
new
FrameLayout
.
LayoutParams
(
ViewGroup
.
LayoutParams
.
MATCH_PARENT
,
ViewGroup
.
LayoutParams
.
MATCH_PARENT
));
...
...
@@ -213,7 +209,6 @@ public class BoostFlutterView extends FrameLayout {
@Override
protected
void
onAttachedToWindow
()
{
super
.
onAttachedToWindow
();
mPlatformPlugin
.
onPostResume
();
ViewCompat
.
requestApplyInsets
(
this
);
getViewTreeObserver
().
addOnGlobalLayoutListener
(
mGlobalLayoutListener
);
}
...
...
@@ -297,10 +292,7 @@ public class BoostFlutterView extends FrameLayout {
Debuger
.
log
(
"BoostFlutterView onDestroy"
);
mFlutterView
.
removeOnFirstFrameRenderedListener
(
mOnFirstFrameRenderedListener
);
AccessibilityBridge
bridge
=
mFlutterView
.
getAccessibilityBridge
();
if
(
bridge
!=
null
){
bridge
.
release
();
}
mFlutterView
.
release
();
}
//混合栈的返回和原来Flutter的返回逻辑不同
...
...
android/src/main/java/com/idlefish/flutterboost/Utils.java
View file @
1d3ace17
...
...
@@ -34,6 +34,7 @@ import android.util.DisplayMetrics;
import
android.view.View
;
import
android.view.Window
;
import
android.view.WindowManager
;
import
android.view.inputmethod.InputMethodManager
;
import
java.io.BufferedReader
;
import
java.io.File
;
...
...
@@ -251,4 +252,41 @@ public class Utils {
}
return
line
;
}
public
static
void
fixInputMethodManagerLeak
(
Context
destContext
)
{
if
(
destContext
==
null
)
{
return
;
}
InputMethodManager
imm
=
(
InputMethodManager
)
destContext
.
getSystemService
(
Context
.
INPUT_METHOD_SERVICE
);
if
(
imm
==
null
)
{
return
;
}
String
[]
arr
=
new
String
[]{
"mLastSrvView"
,
"mServedView"
,
"mNextServedView"
};
Field
f
=
null
;
Object
obj_get
=
null
;
for
(
int
i
=
0
;
i
<
arr
.
length
;
i
++)
{
String
param
=
arr
[
i
];
try
{
f
=
imm
.
getClass
().
getDeclaredField
(
param
);
if
(
f
.
isAccessible
()
==
false
)
{
f
.
setAccessible
(
true
);
}
// author: sodino mail:sodino@qq.com
obj_get
=
f
.
get
(
imm
);
if
(
obj_get
!=
null
&&
obj_get
instanceof
View
)
{
View
v_get
=
(
View
)
obj_get
;
if
(
v_get
.
getContext
()
==
destContext
)
{
// 被InputMethodManager持有引用的context是想要目标销毁的
f
.
set
(
imm
,
null
);
// 置空,破坏掉path to gc节点
}
else
{
// 不是想要目标销毁的,即为又进了另一层界面了,不要处理,避免影响原逻辑,也就不用继续for循环了
break
;
}
}
}
catch
(
Throwable
t
){
t
.
printStackTrace
();
}
}
}
}
\ No newline at end of file
android/src/main/java/com/idlefish/flutterboost/XAndroidKeyProcessor.java
0 → 100644
View file @
1d3ace17
package
com.idlefish.flutterboost
;
import
android.support.annotation.NonNull
;
import
android.support.annotation.Nullable
;
import
android.view.KeyCharacterMap
;
import
android.view.KeyEvent
;
import
io.flutter.embedding.engine.systemchannels.KeyEventChannel
;
import
io.flutter.plugin.editing.TextInputPlugin
;
public
class
XAndroidKeyProcessor
{
@NonNull
private
final
KeyEventChannel
keyEventChannel
;
@NonNull
private
final
XTextInputPlugin
textInputPlugin
;
private
int
combiningCharacter
;
public
XAndroidKeyProcessor
(
@NonNull
KeyEventChannel
keyEventChannel
,
@NonNull
XTextInputPlugin
textInputPlugin
)
{
this
.
keyEventChannel
=
keyEventChannel
;
this
.
textInputPlugin
=
textInputPlugin
;
}
public
void
onKeyUp
(
@NonNull
KeyEvent
keyEvent
)
{
Character
complexCharacter
=
applyCombiningCharacterToBaseCharacter
(
keyEvent
.
getUnicodeChar
());
keyEventChannel
.
keyUp
(
new
KeyEventChannel
.
FlutterKeyEvent
(
keyEvent
,
complexCharacter
)
);
}
public
void
onKeyDown
(
@NonNull
KeyEvent
keyEvent
)
{
if
(
textInputPlugin
.
getLastInputConnection
()
!=
null
&&
textInputPlugin
.
getInputMethodManager
().
isAcceptingText
())
{
textInputPlugin
.
getLastInputConnection
().
sendKeyEvent
(
keyEvent
);
}
Character
complexCharacter
=
applyCombiningCharacterToBaseCharacter
(
keyEvent
.
getUnicodeChar
());
keyEventChannel
.
keyDown
(
new
KeyEventChannel
.
FlutterKeyEvent
(
keyEvent
,
complexCharacter
)
);
}
/**
* Applies the given Unicode character in {@code newCharacterCodePoint} to a previously
* entered Unicode combining character and returns the combination of these characters
* if a combination exists.
* <p>
* This method mutates {@link #combiningCharacter} over time to combine characters.
* <p>
* One of the following things happens in this method:
* <ul>
* <li>If no previous {@link #combiningCharacter} exists and the {@code newCharacterCodePoint}
* is not a combining character, then {@code newCharacterCodePoint} is returned.</li>
* <li>If no previous {@link #combiningCharacter} exists and the {@code newCharacterCodePoint}
* is a combining character, then {@code newCharacterCodePoint} is saved as the
* {@link #combiningCharacter} and null is returned.</li>
* <li>If a previous {@link #combiningCharacter} exists and the {@code newCharacterCodePoint}
* is also a combining character, then the {@code newCharacterCodePoint} is combined with
* the existing {@link #combiningCharacter} and null is returned.</li>
* <li>If a previous {@link #combiningCharacter} exists and the {@code newCharacterCodePoint}
* is not a combining character, then the {@link #combiningCharacter} is applied to the
* regular {@code newCharacterCodePoint} and the resulting complex character is returned. The
* {@link #combiningCharacter} is cleared.</li>
* </ul>
* <p>
* The following reference explains the concept of a "combining character":
* https://en.wikipedia.org/wiki/Combining_character
*/
@Nullable
private
Character
applyCombiningCharacterToBaseCharacter
(
int
newCharacterCodePoint
)
{
if
(
newCharacterCodePoint
==
0
)
{
return
null
;
}
Character
complexCharacter
=
(
char
)
newCharacterCodePoint
;
boolean
isNewCodePointACombiningCharacter
=
(
newCharacterCodePoint
&
KeyCharacterMap
.
COMBINING_ACCENT
)
!=
0
;
if
(
isNewCodePointACombiningCharacter
)
{
// If a combining character was entered before, combine this one with that one.
int
plainCodePoint
=
newCharacterCodePoint
&
KeyCharacterMap
.
COMBINING_ACCENT_MASK
;
if
(
combiningCharacter
!=
0
)
{
combiningCharacter
=
KeyCharacterMap
.
getDeadChar
(
combiningCharacter
,
plainCodePoint
);
}
else
{
combiningCharacter
=
plainCodePoint
;
}
}
else
{
// The new character is a regular character. Apply combiningCharacter to it, if it exists.
if
(
combiningCharacter
!=
0
)
{
int
combinedChar
=
KeyCharacterMap
.
getDeadChar
(
combiningCharacter
,
newCharacterCodePoint
);
if
(
combinedChar
>
0
)
{
complexCharacter
=
(
char
)
combinedChar
;
}
combiningCharacter
=
0
;
}
}
return
complexCharacter
;
}
}
\ No newline at end of file
android/src/main/java/com/idlefish/flutterboost/XFlutterView.java
View file @
1d3ace17
...
...
@@ -59,9 +59,9 @@ public class XFlutterView extends FrameLayout {
// These components essentially add some additional behavioral logic on top of
// existing, stateless system channels, e.g., KeyEventChannel, TextInputChannel, etc.
@Nullable
private
TextInputPlugin
textInputPlugin
;
private
X
TextInputPlugin
textInputPlugin
;
@Nullable
private
AndroidKeyProcessor
androidKeyProcessor
;
private
X
AndroidKeyProcessor
androidKeyProcessor
;
@Nullable
private
AndroidTouchProcessor
androidTouchProcessor
;
@Nullable
...
...
@@ -168,8 +168,14 @@ public class XFlutterView extends FrameLayout {
@Override
protected
void
onConfigurationChanged
(
Configuration
newConfig
)
{
super
.
onConfigurationChanged
(
newConfig
);
sendLocalesToFlutter
(
newConfig
);
sendUserSettingsToFlutter
();
try
{
sendLocalesToFlutter
(
newConfig
);
sendUserSettingsToFlutter
();
}
catch
(
Throwable
e
){
Log
.
e
(
TAG
,
"onConfigurationChanged error "
);
}
}
/**
...
...
@@ -398,16 +404,7 @@ public class XFlutterView extends FrameLayout {
}
}
public
AccessibilityBridge
getAccessibilityBridge
()
{
if
(
accessibilityBridge
!=
null
)
{
return
accessibilityBridge
;
}
else
{
// TODO(goderbauer): when a11y is off this should return a one-off snapshot of
// the a11y
// tree.
return
null
;
}
}
// TODO(mattcarroll): Confer with Ian as to why we need this method. Delete if possible, otherwise add comments.
private
void
resetWillNotDraw
(
boolean
isAccessibilityEnabled
,
boolean
isTouchExplorationEnabled
)
{
if
(
flutterEngine
==
null
)
return
;
...
...
@@ -453,34 +450,45 @@ public class XFlutterView extends FrameLayout {
// Initialize various components that know how to process Android View I/O
// in a way that Flutter understands.
textInputPlugin
=
new
TextInputPlugin
(
this
,
this
.
flutterEngine
.
getDartExecutor
()
);
androidKeyProcessor
=
new
AndroidKeyProcessor
(
this
.
flutterEngine
.
getKeyEventChannel
(),
textInputPlugin
);
if
(
textInputPlugin
==
null
){
textInputPlugin
=
new
XTextInputPlugin
(
this
,
this
.
flutterEngine
.
getDartExecutor
()
);
androidKeyProcessor
=
new
XAndroidKeyProcessor
(
this
.
flutterEngine
.
getKeyEventChannel
(),
textInputPlugin
);
}
androidTouchProcessor
=
new
AndroidTouchProcessor
(
this
.
flutterEngine
.
getRenderer
());
accessibilityBridge
=
new
AccessibilityBridge
(
this
,
flutterEngine
.
getAccessibilityChannel
(),
(
AccessibilityManager
)
getContext
().
getSystemService
(
Context
.
ACCESSIBILITY_SERVICE
),
getContext
().
getContentResolver
(),
// TODO(mattcaroll): plumb the platform views controller to the accessibility bridge.
// https://github.com/flutter/flutter/issues/29618
null
);
accessibilityBridge
.
setOnAccessibilityChangeListener
(
onAccessibilityChangeListener
);
resetWillNotDraw
(
accessibilityBridge
.
isAccessibilityEnabled
(),
accessibilityBridge
.
isTouchExplorationEnabled
()
);
if
(
accessibilityBridge
==
null
){
accessibilityBridge
=
new
AccessibilityBridge
(
this
,
flutterEngine
.
getAccessibilityChannel
(),
(
AccessibilityManager
)
getContext
().
getSystemService
(
Context
.
ACCESSIBILITY_SERVICE
),
getContext
().
getContentResolver
(),
// TODO(mattcaroll): plumb the platform views controller to the accessibility bridge.
// https://github.com/flutter/flutter/issues/29618
null
);
accessibilityBridge
.
setOnAccessibilityChangeListener
(
onAccessibilityChangeListener
);
resetWillNotDraw
(
accessibilityBridge
.
isAccessibilityEnabled
(),
accessibilityBridge
.
isTouchExplorationEnabled
()
);
textInputPlugin
.
getInputMethodManager
().
restartInput
(
this
);
}
// Inform the Android framework that it should retrieve a new InputConnection
// now that an engine is attached.
// TODO(mattcarroll): once this is proven to work, move this line ot TextInputPlugin
textInputPlugin
.
getInputMethodManager
().
restartInput
(
this
);
// Push View and Context related information from Android to Flutter.
sendUserSettingsToFlutter
();
...
...
@@ -488,6 +496,16 @@ public class XFlutterView extends FrameLayout {
sendViewportMetricsToFlutter
();
}
public
void
release
(){
if
(
accessibilityBridge
!=
null
){
accessibilityBridge
.
release
();
}
textInputPlugin
.
release
();
}
/**
* Disconnects this {@code FlutterView} from a previously attached {@link FlutterEngine}.
*
...
...
@@ -511,7 +529,6 @@ public class XFlutterView extends FrameLayout {
// signifies that this View does not process input (until a new engine is attached).
// TODO(mattcarroll): once this is proven to work, move this line ot TextInputPlugin
textInputPlugin
.
getInputMethodManager
().
restartInput
(
this
);
// Instruct our FlutterRenderer that we are no longer interested in being its RenderSurface.
flutterEngine
.
getRenderer
().
detachFromRenderSurface
();
flutterEngine
=
null
;
...
...
@@ -560,10 +577,13 @@ public class XFlutterView extends FrameLayout {
* FlutterEngine must be non-null when this method is invoked.
*/
private
void
sendUserSettingsToFlutter
()
{
flutterEngine
.
getSettingsChannel
().
startMessage
()
.
setTextScaleFactor
(
getResources
().
getConfiguration
().
fontScale
)
.
setUse24HourFormat
(
DateFormat
.
is24HourFormat
(
getContext
()))
.
send
();
if
(
flutterEngine
!=
null
&&
flutterEngine
.
getSettingsChannel
()!=
null
){
flutterEngine
.
getSettingsChannel
().
startMessage
()
.
setTextScaleFactor
(
getResources
().
getConfiguration
().
fontScale
)
.
setUse24HourFormat
(
DateFormat
.
is24HourFormat
(
getContext
()))
.
send
();
}
}
// TODO(mattcarroll): consider introducing a system channel for this communication instead of JNI
...
...
android/src/main/java/com/idlefish/flutterboost/XInputConnectionAdaptor.java
0 → 100644
View file @
1d3ace17
package
com.idlefish.flutterboost
;
import
android.content.Context
;
import
android.text.Editable
;
import
android.text.Selection
;
import
android.view.KeyEvent
;
import
android.view.View
;
import
android.view.inputmethod.BaseInputConnection
;
import
android.view.inputmethod.EditorInfo
;
import
android.view.inputmethod.InputMethodManager
;
import
io.flutter.embedding.engine.systemchannels.TextInputChannel
;
import
io.flutter.plugin.common.ErrorLogResult
;
import
io.flutter.plugin.common.MethodChannel
;
class
XInputConnectionAdaptor
extends
BaseInputConnection
{
private
final
View
mFlutterView
;
private
final
int
mClient
;
private
final
TextInputChannel
textInputChannel
;
private
final
Editable
mEditable
;
private
int
mBatchCount
;
private
InputMethodManager
mImm
;
private
static
final
MethodChannel
.
Result
logger
=
new
ErrorLogResult
(
"FlutterTextInput"
);
public
XInputConnectionAdaptor
(
View
view
,
int
client
,
TextInputChannel
textInputChannel
,
Editable
editable
)
{
super
(
view
,
true
);
mFlutterView
=
view
;
mClient
=
client
;
this
.
textInputChannel
=
textInputChannel
;
mEditable
=
editable
;
mBatchCount
=
0
;
mImm
=
(
InputMethodManager
)
view
.
getContext
().
getSystemService
(
Context
.
INPUT_METHOD_SERVICE
);
}
// Send the current state of the editable to Flutter.
private
void
updateEditingState
()
{
// If the IME is in the middle of a batch edit, then wait until it completes.
if
(
mBatchCount
>
0
)
return
;
int
selectionStart
=
Selection
.
getSelectionStart
(
mEditable
);
int
selectionEnd
=
Selection
.
getSelectionEnd
(
mEditable
);
int
composingStart
=
BaseInputConnection
.
getComposingSpanStart
(
mEditable
);
int
composingEnd
=
BaseInputConnection
.
getComposingSpanEnd
(
mEditable
);
mImm
.
updateSelection
(
mFlutterView
,
selectionStart
,
selectionEnd
,
composingStart
,
composingEnd
);
textInputChannel
.
updateEditingState
(
mClient
,
mEditable
.
toString
(),
selectionStart
,
selectionEnd
,
composingStart
,
composingEnd
);
}
@Override
public
Editable
getEditable
()
{
return
mEditable
;
}
@Override
public
boolean
beginBatchEdit
()
{
mBatchCount
++;
return
super
.
beginBatchEdit
();
}
@Override
public
boolean
endBatchEdit
()
{
boolean
result
=
super
.
endBatchEdit
();
mBatchCount
--;
updateEditingState
();
return
result
;
}
@Override
public
boolean
commitText
(
CharSequence
text
,
int
newCursorPosition
)
{
boolean
result
=
super
.
commitText
(
text
,
newCursorPosition
);
updateEditingState
();
return
result
;
}
@Override
public
boolean
deleteSurroundingText
(
int
beforeLength
,
int
afterLength
)
{
if
(
Selection
.
getSelectionStart
(
mEditable
)
==
-
1
)
return
true
;
boolean
result
=
super
.
deleteSurroundingText
(
beforeLength
,
afterLength
);
updateEditingState
();
return
result
;
}
@Override
public
boolean
setComposingRegion
(
int
start
,
int
end
)
{
boolean
result
=
super
.
setComposingRegion
(
start
,
end
);
updateEditingState
();
return
result
;
}
@Override
public
boolean
setComposingText
(
CharSequence
text
,
int
newCursorPosition
)
{
boolean
result
;
if
(
text
.
length
()
==
0
)
{
result
=
super
.
commitText
(
text
,
newCursorPosition
);
}
else
{
result
=
super
.
setComposingText
(
text
,
newCursorPosition
);
}
updateEditingState
();
return
result
;
}
@Override
public
boolean
setSelection
(
int
start
,
int
end
)
{
boolean
result
=
super
.
setSelection
(
start
,
end
);
updateEditingState
();
return
result
;
}
@Override
public
boolean
sendKeyEvent
(
KeyEvent
event
)
{
if
(
event
.
getAction
()
==
KeyEvent
.
ACTION_DOWN
)
{
if
(
event
.
getKeyCode
()
==
KeyEvent
.
KEYCODE_DEL
)
{
int
selStart
=
Selection
.
getSelectionStart
(
mEditable
);
int
selEnd
=
Selection
.
getSelectionEnd
(
mEditable
);
if
(
selEnd
>
selStart
)
{
// Delete the selection.
Selection
.
setSelection
(
mEditable
,
selStart
);
mEditable
.
delete
(
selStart
,
selEnd
);
updateEditingState
();
return
true
;
}
else
if
(
selStart
>
0
)
{
// Delete to the left of the cursor.
int
newSel
=
Math
.
max
(
selStart
-
1
,
0
);
Selection
.
setSelection
(
mEditable
,
newSel
);
mEditable
.
delete
(
newSel
,
selStart
);
updateEditingState
();
return
true
;
}
}
else
if
(
event
.
getKeyCode
()
==
KeyEvent
.
KEYCODE_DPAD_LEFT
)
{
int
selStart
=
Selection
.
getSelectionStart
(
mEditable
);
int
newSel
=
Math
.
max
(
selStart
-
1
,
0
);
setSelection
(
newSel
,
newSel
);
return
true
;
}
else
if
(
event
.
getKeyCode
()
==
KeyEvent
.
KEYCODE_DPAD_RIGHT
)
{
int
selStart
=
Selection
.
getSelectionStart
(
mEditable
);
int
newSel
=
Math
.
min
(
selStart
+
1
,
mEditable
.
length
());
setSelection
(
newSel
,
newSel
);
return
true
;
}
else
{
// Enter a character.
int
character
=
event
.
getUnicodeChar
();
if
(
character
!=
0
)
{
int
selStart
=
Math
.
max
(
0
,
Selection
.
getSelectionStart
(
mEditable
));
int
selEnd
=
Math
.
max
(
0
,
Selection
.
getSelectionEnd
(
mEditable
));
if
(
selEnd
!=
selStart
)
mEditable
.
delete
(
selStart
,
selEnd
);
mEditable
.
insert
(
selStart
,
String
.
valueOf
((
char
)
character
));
setSelection
(
selStart
+
1
,
selStart
+
1
);
updateEditingState
();
}
return
true
;
}
}
return
false
;
}
@Override
public
boolean
performEditorAction
(
int
actionCode
)
{
switch
(
actionCode
)
{
case
EditorInfo
.
IME_ACTION_NONE
:
textInputChannel
.
newline
(
mClient
);
break
;
case
EditorInfo
.
IME_ACTION_UNSPECIFIED
:
textInputChannel
.
unspecifiedAction
(
mClient
);
break
;
case
EditorInfo
.
IME_ACTION_GO
:
textInputChannel
.
go
(
mClient
);
break
;
case
EditorInfo
.
IME_ACTION_SEARCH
:
textInputChannel
.
search
(
mClient
);
break
;
case
EditorInfo
.
IME_ACTION_SEND
:
textInputChannel
.
send
(
mClient
);
break
;
case
EditorInfo
.
IME_ACTION_NEXT
:
textInputChannel
.
next
(
mClient
);
break
;
case
EditorInfo
.
IME_ACTION_PREVIOUS
:
textInputChannel
.
previous
(
mClient
);
break
;
default
:
case
EditorInfo
.
IME_ACTION_DONE
:
textInputChannel
.
done
(
mClient
);
break
;
}
return
true
;
}
}
\ No newline at end of file
android/src/main/java/com/idlefish/flutterboost/XTextInputPlugin.java
0 → 100644
View file @
1d3ace17
package
com.idlefish.flutterboost
;
import
android.content.Context
;
import
android.support.annotation.NonNull
;
import
android.support.annotation.Nullable
;
import
android.text.Editable
;
import
android.text.InputType
;
import
android.text.Selection
;
import
android.view.View
;
import
android.view.inputmethod.BaseInputConnection
;
import
android.view.inputmethod.EditorInfo
;
import
android.view.inputmethod.InputConnection
;
import
android.view.inputmethod.InputMethodManager
;
import
io.flutter.embedding.engine.dart.DartExecutor
;
import
io.flutter.embedding.engine.systemchannels.TextInputChannel
;
import
io.flutter.view.FlutterView
;
/**
* Android implementation of the text input plugin.
*/
public
class
XTextInputPlugin
{
@NonNull
private
View
mView
;
@NonNull
private
final
InputMethodManager
mImm
;
@NonNull
private
final
TextInputChannel
textInputChannel
;
private
int
mClient
=
0
;
@Nullable
private
TextInputChannel
.
Configuration
configuration
;
@Nullable
private
Editable
mEditable
;
private
boolean
mRestartInputPending
;
@Nullable
private
InputConnection
lastInputConnection
;
public
XTextInputPlugin
(
View
view
,
@NonNull
DartExecutor
dartExecutor
)
{
mView
=
view
;
mImm
=
(
InputMethodManager
)
view
.
getContext
().
getSystemService
(
Context
.
INPUT_METHOD_SERVICE
);
textInputChannel
=
new
TextInputChannel
(
dartExecutor
);
textInputChannel
.
setTextInputMethodHandler
(
new
TextInputChannel
.
TextInputMethodHandler
()
{
@Override
public
void
show
()
{
showTextInput
(
mView
);
}
@Override
public
void
hide
()
{
hideTextInput
(
mView
);
}
@Override
public
void
setClient
(
int
textInputClientId
,
TextInputChannel
.
Configuration
configuration
)
{
setTextInputClient
(
textInputClientId
,
configuration
);
}
@Override
public
void
setEditingState
(
TextInputChannel
.
TextEditState
editingState
)
{
setTextInputEditingState
(
mView
,
editingState
);
}
@Override
public
void
clearClient
()
{
clearTextInputClient
();
}
});
}
public
void
release
(){
mView
=
null
;
}
@NonNull
public
InputMethodManager
getInputMethodManager
()
{
return
mImm
;
}
private
static
int
inputTypeFromTextInputType
(
TextInputChannel
.
InputType
type
,
boolean
obscureText
,
boolean
autocorrect
,
TextInputChannel
.
TextCapitalization
textCapitalization
)
{
if
(
type
.
type
==
TextInputChannel
.
TextInputType
.
DATETIME
)
{
return
InputType
.
TYPE_CLASS_DATETIME
;
}
else
if
(
type
.
type
==
TextInputChannel
.
TextInputType
.
NUMBER
)
{
int
textType
=
InputType
.
TYPE_CLASS_NUMBER
;
if
(
type
.
isSigned
)
{
textType
|=
InputType
.
TYPE_NUMBER_FLAG_SIGNED
;
}
if
(
type
.
isDecimal
)
{
textType
|=
InputType
.
TYPE_NUMBER_FLAG_DECIMAL
;
}
return
textType
;
}
else
if
(
type
.
type
==
TextInputChannel
.
TextInputType
.
PHONE
)
{
return
InputType
.
TYPE_CLASS_PHONE
;
}
int
textType
=
InputType
.
TYPE_CLASS_TEXT
;
if
(
type
.
type
==
TextInputChannel
.
TextInputType
.
MULTILINE
)
{
textType
|=
InputType
.
TYPE_TEXT_FLAG_MULTI_LINE
;
}
else
if
(
type
.
type
==
TextInputChannel
.
TextInputType
.
EMAIL_ADDRESS
)
{
textType
|=
InputType
.
TYPE_TEXT_VARIATION_EMAIL_ADDRESS
;
}
else
if
(
type
.
type
==
TextInputChannel
.
TextInputType
.
URL
)
{
textType
|=
InputType
.
TYPE_TEXT_VARIATION_URI
;
}
if
(
obscureText
)
{
// Note: both required. Some devices ignore TYPE_TEXT_FLAG_NO_SUGGESTIONS.
textType
|=
InputType
.
TYPE_TEXT_FLAG_NO_SUGGESTIONS
;
textType
|=
InputType
.
TYPE_TEXT_VARIATION_PASSWORD
;
}
else
{
if
(
autocorrect
)
textType
|=
InputType
.
TYPE_TEXT_FLAG_AUTO_CORRECT
;
}
if
(
textCapitalization
==
TextInputChannel
.
TextCapitalization
.
CHARACTERS
)
{
textType
|=
InputType
.
TYPE_TEXT_FLAG_CAP_CHARACTERS
;
}
else
if
(
textCapitalization
==
TextInputChannel
.
TextCapitalization
.
WORDS
)
{
textType
|=
InputType
.
TYPE_TEXT_FLAG_CAP_WORDS
;
}
else
if
(
textCapitalization
==
TextInputChannel
.
TextCapitalization
.
SENTENCES
)
{
textType
|=
InputType
.
TYPE_TEXT_FLAG_CAP_SENTENCES
;
}
return
textType
;
}
public
InputConnection
createInputConnection
(
View
view
,
EditorInfo
outAttrs
)
{
if
(
mClient
==
0
)
{
lastInputConnection
=
null
;
return
lastInputConnection
;
}
outAttrs
.
inputType
=
inputTypeFromTextInputType
(
configuration
.
inputType
,
configuration
.
obscureText
,
configuration
.
autocorrect
,
configuration
.
textCapitalization
);
outAttrs
.
imeOptions
=
EditorInfo
.
IME_FLAG_NO_FULLSCREEN
;
int
enterAction
;
if
(
configuration
.
inputAction
==
null
)
{
// If an explicit input action isn't set, then default to none for multi-line fields
// and done for single line fields.
enterAction
=
(
InputType
.
TYPE_TEXT_FLAG_MULTI_LINE
&
outAttrs
.
inputType
)
!=
0
?
EditorInfo
.
IME_ACTION_NONE
:
EditorInfo
.
IME_ACTION_DONE
;
}
else
{
enterAction
=
configuration
.
inputAction
;
}
if
(
configuration
.
actionLabel
!=
null
)
{
outAttrs
.
actionLabel
=
configuration
.
actionLabel
;
outAttrs
.
actionId
=
enterAction
;
}
outAttrs
.
imeOptions
|=
enterAction
;
XInputConnectionAdaptor
connection
=
new
XInputConnectionAdaptor
(
view
,
mClient
,
textInputChannel
,
mEditable
);
outAttrs
.
initialSelStart
=
Selection
.
getSelectionStart
(
mEditable
);
outAttrs
.
initialSelEnd
=
Selection
.
getSelectionEnd
(
mEditable
);
lastInputConnection
=
connection
;
return
lastInputConnection
;
}
@Nullable
public
InputConnection
getLastInputConnection
()
{
return
lastInputConnection
;
}
private
void
showTextInput
(
View
view
)
{
view
.
requestFocus
();
mImm
.
showSoftInput
(
view
,
0
);
}
private
void
hideTextInput
(
View
view
)
{
mImm
.
hideSoftInputFromWindow
(
view
.
getApplicationWindowToken
(),
0
);
}
private
void
setTextInputClient
(
int
client
,
TextInputChannel
.
Configuration
configuration
)
{
mClient
=
client
;
this
.
configuration
=
configuration
;
mEditable
=
Editable
.
Factory
.
getInstance
().
newEditable
(
""
);
// setTextInputClient will be followed by a call to setTextInputEditingState.
// Do a restartInput at that time.
mRestartInputPending
=
true
;
}
private
void
applyStateToSelection
(
TextInputChannel
.
TextEditState
state
)
{
int
selStart
=
state
.
selectionStart
;
int
selEnd
=
state
.
selectionEnd
;
if
(
selStart
>=
0
&&
selStart
<=
mEditable
.
length
()
&&
selEnd
>=
0
&&
selEnd
<=
mEditable
.
length
())
{
Selection
.
setSelection
(
mEditable
,
selStart
,
selEnd
);
}
else
{
Selection
.
removeSelection
(
mEditable
);
}
}
private
void
setTextInputEditingState
(
View
view
,
TextInputChannel
.
TextEditState
state
)
{
if
(!
mRestartInputPending
&&
state
.
text
.
equals
(
mEditable
.
toString
()))
{
applyStateToSelection
(
state
);
mImm
.
updateSelection
(
mView
,
Math
.
max
(
Selection
.
getSelectionStart
(
mEditable
),
0
),
Math
.
max
(
Selection
.
getSelectionEnd
(
mEditable
),
0
),
BaseInputConnection
.
getComposingSpanStart
(
mEditable
),
BaseInputConnection
.
getComposingSpanEnd
(
mEditable
));
}
else
{
mEditable
.
replace
(
0
,
mEditable
.
length
(),
state
.
text
);
applyStateToSelection
(
state
);
mImm
.
restartInput
(
view
);
mRestartInputPending
=
false
;
}
}
private
void
clearTextInputClient
()
{
mClient
=
0
;
}
}
\ No newline at end of file
android/src/main/java/com/idlefish/flutterboost/containers/BoostFlutterActivity.java
View file @
1d3ace17
...
...
@@ -185,8 +185,10 @@ public abstract class BoostFlutterActivity extends Activity implements IFlutterV
@Override
protected
void
onDestroy
()
{
Utils
.
fixInputMethodManagerLeak
(
this
);
mSyncer
.
onDestroy
();
super
.
onDestroy
();
}
@Override
...
...
ios/Classes/Engine/FLBFlutterEngine.m
View file @
1d3ace17
...
...
@@ -52,6 +52,8 @@
_dummy
=
[[
FLBFlutterViewContainer
alloc
]
initWithEngine
:
_engine
nibName:
nil
bundle:
nil
];
_dummy
.
name
=
kIgnoreMessageWithName
;
Class
clazz
=
NSClassFromString
(
@"GeneratedPluginRegistrant"
);
if
(
clazz
)
{
if
([
clazz
respondsToSelector
:
NSSelectorFromString
(
@"registerWithRegistry:"
)])
{
...
...
@@ -121,6 +123,9 @@
-
(
void
)
prepareEngineIfNeeded
{
// if ([_dummy respondsToSelector:@selector(setEnableForRunnersBatch:)]) {
// [_dummy setEnableForRunnersBatch:YES];
// }
[
self
detach
];
[
_dummy
surfaceUpdated
:
YES
];
}
...
...
ios/Classes/Messaging/BoostMessageChannel.h
View file @
1d3ace17
...
...
@@ -26,6 +26,8 @@
#import <Flutter/Flutter.h>
#import "FLBTypes.h"
#define kIgnoreMessageWithName @"__flutterboost_dummy__"
@interface
BoostMessageChannel
:
NSObject
+
(
void
)
onNativePageResult
:(
void
(
^
)(
NSNumber
*
))
result
uniqueId
:(
NSString
*
)
uniqueId
key
:(
NSString
*
)
key
resultData
:(
NSDictionary
*
)
resultData
params
:(
NSDictionary
*
)
params
;
...
...
ios/Classes/Messaging/BoostMessageChannel.mm
View file @
1d3ace17
...
...
@@ -100,6 +100,10 @@
+
(
void
)
didShowPageContainer
:(
void
(
^
)(
NSNumber
*
))
result
pageName
:(
NSString
*
)
pageName
params
:(
NSDictionary
*
)
params
uniqueId
:(
NSString
*
)
uniqueId
{
if
([
pageName
isEqualToString
:
kIgnoreMessageWithName
])
{
return
;
}
NSMutableDictionary
*
tmp
=
[
NSMutableDictionary
dictionary
];
if
(
pageName
)
tmp
[
@"pageName"
]
=
pageName
;
if
(
params
)
tmp
[
@"params"
]
=
params
;
...
...
@@ -113,6 +117,10 @@
+
(
void
)
willShowPageContainer
:(
void
(
^
)(
NSNumber
*
))
result
pageName
:(
NSString
*
)
pageName
params
:(
NSDictionary
*
)
params
uniqueId
:(
NSString
*
)
uniqueId
{
if
([
pageName
isEqualToString
:
kIgnoreMessageWithName
])
{
return
;
}
NSMutableDictionary
*
tmp
=
[
NSMutableDictionary
dictionary
];
if
(
pageName
)
tmp
[
@"pageName"
]
=
pageName
;
if
(
params
)
tmp
[
@"params"
]
=
params
;
...
...
@@ -126,6 +134,10 @@
+
(
void
)
willDisappearPageContainer
:(
void
(
^
)(
NSNumber
*
))
result
pageName
:(
NSString
*
)
pageName
params
:(
NSDictionary
*
)
params
uniqueId
:(
NSString
*
)
uniqueId
{
if
([
pageName
isEqualToString
:
kIgnoreMessageWithName
])
{
return
;
}
NSMutableDictionary
*
tmp
=
[
NSMutableDictionary
dictionary
];
if
(
pageName
)
tmp
[
@"pageName"
]
=
pageName
;
if
(
params
)
tmp
[
@"params"
]
=
params
;
...
...
@@ -139,6 +151,10 @@
+
(
void
)
didDisappearPageContainer
:(
void
(
^
)(
NSNumber
*
))
result
pageName
:(
NSString
*
)
pageName
params
:(
NSDictionary
*
)
params
uniqueId
:(
NSString
*
)
uniqueId
{
if
([
pageName
isEqualToString
:
kIgnoreMessageWithName
])
{
return
;
}
NSMutableDictionary
*
tmp
=
[
NSMutableDictionary
dictionary
];
if
(
pageName
)
tmp
[
@"pageName"
]
=
pageName
;
if
(
params
)
tmp
[
@"params"
]
=
params
;
...
...
@@ -152,6 +168,10 @@
+
(
void
)
didInitPageContainer
:(
void
(
^
)(
NSNumber
*
))
result
pageName
:(
NSString
*
)
pageName
params
:(
NSDictionary
*
)
params
uniqueId
:(
NSString
*
)
uniqueId
{
if
([
pageName
isEqualToString
:
kIgnoreMessageWithName
])
{
return
;
}
NSMutableDictionary
*
tmp
=
[
NSMutableDictionary
dictionary
];
if
(
pageName
)
tmp
[
@"pageName"
]
=
pageName
;
if
(
params
)
tmp
[
@"params"
]
=
params
;
...
...
@@ -169,6 +189,10 @@
+
(
void
)
willDeallocPageContainer
:(
void
(
^
)(
NSNumber
*
))
result
pageName
:(
NSString
*
)
pageName
params
:(
NSDictionary
*
)
params
uniqueId
:(
NSString
*
)
uniqueId
{
if
([
pageName
isEqualToString
:
kIgnoreMessageWithName
])
{
return
;
}
NSMutableDictionary
*
tmp
=
[
NSMutableDictionary
dictionary
];
if
(
pageName
)
tmp
[
@"pageName"
]
=
pageName
;
if
(
params
)
tmp
[
@"params"
]
=
params
;
...
...
ios/Classes/container/FLBFlutterViewContainer.h
View file @
1d3ace17
...
...
@@ -27,7 +27,9 @@
#import "FLBFlutterContainer.h"
NS_ASSUME_NONNULL_BEGIN
@interface
FLBFlutterViewContainer
:
FlutterViewController
<
FLBFlutterContainer
>
@interface
FLB2FlutterViewContainer
:
FlutterViewController
<
FLBFlutterContainer
>
@property
(
nonatomic
,
copy
,
readwrite
)
NSString
*
name
;
-
(
void
)
surfaceUpdated
:(
BOOL
)
appeared
;
-
(
void
)
setEnableForRunnersBatch
:(
BOOL
)
enable
;
@end
NS_ASSUME_NONNULL_END
ios/Classes/container/FLBFlutterViewContainer.m
View file @
1d3ace17
...
...
@@ -32,8 +32,7 @@
#define FLUTTER_VIEW FLUTTER_APP.flutterViewController.view
#define FLUTTER_VC FLUTTER_APP.flutterViewController
@interface
FLBFlutterViewContainer
()
@property
(
nonatomic
,
copy
,
readwrite
)
NSString
*
name
;
@interface
FLB2FlutterViewContainer
()
@property
(
nonatomic
,
strong
,
readwrite
)
NSDictionary
*
params
;
@property
(
nonatomic
,
assign
)
long
long
identifier
;
@end
...
...
@@ -145,6 +144,10 @@ static NSUInteger kInstanceCounter = 0;
[
FLUTTER_APP
.
flutterProvider
detach
];
}
-
(
void
)
setEnableForRunnersBatch
:(
BOOL
)
enable
{
//dummy function
NSLog
(
@"[DEBUG]- I did nothing, I am innocent"
);
}
#pragma mark - Life circle methods
...
...
@@ -157,9 +160,11 @@ static NSUInteger kInstanceCounter = 0;
-
(
void
)
viewWillAppear
:(
BOOL
)
animated
{
if
([
FLUTTER_APP
contains
:
self
]){
[
self
surfaceUpdated
:
NO
];
[
self
detatchFlutterEngine
];
}
else
{
[
self
attatchFlutterEngine
];
[
self
surfaceUpdated
:
YES
];
}
[
FLUTTER_APP
resume
];
...
...
@@ -210,14 +215,14 @@ static NSUInteger kInstanceCounter = 0;
-
(
void
)
viewDidDisappear
:(
BOOL
)
animated
{
[
super
viewDidDisappear
:
animated
];
[
FLUTTER_APP
resume
];
[
BoostMessageChannel
didDisappearPageContainer
:
^
(
NSNumber
*
result
)
{}
pageName:
_name
params:
_params
uniqueId:
self
.
uniqueIDString
];
[
super
viewDidDisappear
:
animated
];
[
FLUTTER_APP
resume
];
}
-
(
void
)
installSplashScreenViewIfNecessary
{
...
...
lib/container/boost_container.dart
View file @
1d3ace17
...
...
@@ -30,6 +30,7 @@ import '../support/logger.dart';
enum
ContainerLifeCycle
{
Init
,
Appear
,
WillDisappear
,
Disappear
,
Destroy
,
Background
,
...
...
lib/container/container_coordinator.dart
View file @
1d3ace17
...
...
@@ -236,6 +236,8 @@ class ContainerCoordinator {
}
bool
_nativeContainerWillDisappear
(
String
name
,
Map
params
,
String
pageId
)
{
performContainerLifeCycle
(
_createContainerSettings
(
name
,
params
,
pageId
),
ContainerLifeCycle
.
WillDisappear
);
return
true
;
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment