mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
#9203 broke the keyboard_resize integration test(see more details in flutter/flutter#34085 (comment)). This re-lands @9203 and fixes the issue the integration test uncovered by always allowing to hide the keyboard. The difference from the original change is 07d2598
This commit is contained in:
parent
36b7123bfc
commit
259d334e05
@ -477,7 +477,8 @@ public class FlutterView extends FrameLayout {
|
||||
// in a way that Flutter understands.
|
||||
textInputPlugin = new TextInputPlugin(
|
||||
this,
|
||||
this.flutterEngine.getDartExecutor()
|
||||
this.flutterEngine.getDartExecutor(),
|
||||
null
|
||||
);
|
||||
androidKeyProcessor = new AndroidKeyProcessor(
|
||||
this.flutterEngine.getKeyEventChannel(),
|
||||
|
||||
@ -26,6 +26,13 @@ public class PlatformViewsChannel {
|
||||
private final MethodChannel channel;
|
||||
private PlatformViewsHandler handler;
|
||||
|
||||
public void invokeViewFocused(int viewId) {
|
||||
if (channel == null) {
|
||||
return;
|
||||
}
|
||||
channel.invokeMethod("viewFocused", viewId);
|
||||
}
|
||||
|
||||
private final MethodChannel.MethodCallHandler parsingHandler = new MethodChannel.MethodCallHandler() {
|
||||
@Override
|
||||
public void onMethodCall(MethodCall call, MethodChannel.Result result) {
|
||||
@ -51,6 +58,9 @@ public class PlatformViewsChannel {
|
||||
case "setDirection":
|
||||
setDirection(call, result);
|
||||
break;
|
||||
case "clearFocus":
|
||||
clearFocus(call, result);
|
||||
break;
|
||||
default:
|
||||
result.notImplemented();
|
||||
}
|
||||
@ -172,6 +182,20 @@ public class PlatformViewsChannel {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private void clearFocus(MethodCall call, MethodChannel.Result result) {
|
||||
int viewId = call.arguments();
|
||||
try {
|
||||
handler.clearFocus(viewId);
|
||||
result.success(null);
|
||||
} catch (IllegalStateException exception) {
|
||||
result.error(
|
||||
"error",
|
||||
exception.getMessage(),
|
||||
null
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@ -241,6 +265,11 @@ public class PlatformViewsChannel {
|
||||
*/
|
||||
// TODO(mattcarroll): Introduce an annotation for @TextureId
|
||||
void setDirection(int viewId, int direction);
|
||||
|
||||
/**
|
||||
* Clears the focus from the platform view with a give id if it is currently focused.
|
||||
*/
|
||||
void clearFocus(int viewId);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -70,6 +70,10 @@ public class TextInputChannel {
|
||||
result.error("error", exception.getMessage(), null);
|
||||
}
|
||||
break;
|
||||
case "TextInput.setPlatformViewClient":
|
||||
final int id = (int) args;
|
||||
textInputMethodHandler.setPlatformViewClient(id);
|
||||
break;
|
||||
case "TextInput.setEditingState":
|
||||
try {
|
||||
final JSONObject editingState = (JSONObject) args;
|
||||
@ -218,6 +222,16 @@ public class TextInputChannel {
|
||||
// TODO(mattcarroll): javadoc
|
||||
void setClient(int textInputClientId, @NonNull Configuration configuration);
|
||||
|
||||
/**
|
||||
* Sets a platform view as the text input client.
|
||||
*
|
||||
* Subsequent calls to createInputConnection will be delegated to the platform view until a
|
||||
* different client is set.
|
||||
*
|
||||
* @param id the ID of the platform view to be set as a text input client.
|
||||
*/
|
||||
void setPlatformViewClient(int id);
|
||||
|
||||
// TODO(mattcarroll): javadoc
|
||||
void setEditingState(@NonNull TextEditState editingState);
|
||||
|
||||
|
||||
@ -18,7 +18,7 @@ import android.view.inputmethod.InputMethodManager;
|
||||
|
||||
import io.flutter.embedding.engine.dart.DartExecutor;
|
||||
import io.flutter.embedding.engine.systemchannels.TextInputChannel;
|
||||
import io.flutter.view.FlutterView;
|
||||
import io.flutter.plugin.platform.PlatformViewsController;
|
||||
|
||||
/**
|
||||
* Android implementation of the text input plugin.
|
||||
@ -30,7 +30,8 @@ public class TextInputPlugin {
|
||||
private final InputMethodManager mImm;
|
||||
@NonNull
|
||||
private final TextInputChannel textInputChannel;
|
||||
private int mClient = 0;
|
||||
@NonNull
|
||||
private InputTarget inputTarget = new InputTarget(InputTarget.Type.NO_TARGET, 0);
|
||||
@Nullable
|
||||
private TextInputChannel.Configuration configuration;
|
||||
@Nullable
|
||||
@ -39,7 +40,13 @@ public class TextInputPlugin {
|
||||
@Nullable
|
||||
private InputConnection lastInputConnection;
|
||||
|
||||
public TextInputPlugin(View view, @NonNull DartExecutor dartExecutor) {
|
||||
private PlatformViewsController platformViewsController;
|
||||
|
||||
// When true following calls to createInputConnection will return the cached lastInputConnection if the input
|
||||
// target is a platform view. See the comments on lockPlatformViewInputConnection for more details.
|
||||
private boolean isInputConnectionLocked;
|
||||
|
||||
public TextInputPlugin(View view, @NonNull DartExecutor dartExecutor, PlatformViewsController platformViewsController) {
|
||||
mView = view;
|
||||
mImm = (InputMethodManager) view.getContext().getSystemService(
|
||||
Context.INPUT_METHOD_SERVICE);
|
||||
@ -61,6 +68,11 @@ public class TextInputPlugin {
|
||||
setTextInputClient(textInputClientId, configuration);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPlatformViewClient(int platformViewId) {
|
||||
setPlatformViewTextInputClient(platformViewId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEditingState(TextInputChannel.TextEditState editingState) {
|
||||
setTextInputEditingState(mView, editingState);
|
||||
@ -71,6 +83,8 @@ public class TextInputPlugin {
|
||||
clearTextInputClient();
|
||||
}
|
||||
});
|
||||
this.platformViewsController = platformViewsController;
|
||||
platformViewsController.attachTextInputPlugin(this);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@ -78,6 +92,40 @@ public class TextInputPlugin {
|
||||
return mImm;
|
||||
}
|
||||
|
||||
/***
|
||||
* Use the current platform view input connection until unlockPlatformViewInputConnection is called.
|
||||
*
|
||||
* The current input connection instance is cached and any following call to @{link createInputConnection} returns
|
||||
* the cached connection until unlockPlatformViewInputConnection is called.
|
||||
*
|
||||
* This is a no-op if the current input target isn't a platform view.
|
||||
*
|
||||
* This is used to preserve an input connection when moving a platform view from one virtual display to another.
|
||||
*/
|
||||
public void lockPlatformViewInputConnection() {
|
||||
if (inputTarget.type == InputTarget.Type.PLATFORM_VIEW) {
|
||||
isInputConnectionLocked = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlocks the input connection.
|
||||
*
|
||||
* See also: @{link lockPlatformViewInputConnection}.
|
||||
*/
|
||||
public void unlockPlatformViewInputConnection() {
|
||||
isInputConnectionLocked = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detaches the text input plugin from the platform views controller.
|
||||
*
|
||||
* The TextInputPlugin instance should not be used after calling this.
|
||||
*/
|
||||
public void destroy() {
|
||||
platformViewsController.detachTextInputPlugin();
|
||||
}
|
||||
|
||||
private static int inputTypeFromTextInputType(
|
||||
TextInputChannel.InputType type,
|
||||
boolean obscureText,
|
||||
@ -128,8 +176,16 @@ public class TextInputPlugin {
|
||||
}
|
||||
|
||||
public InputConnection createInputConnection(View view, EditorInfo outAttrs) {
|
||||
if (mClient == 0) {
|
||||
if (inputTarget.type == InputTarget.Type.NO_TARGET) {
|
||||
lastInputConnection = null;
|
||||
return null;
|
||||
}
|
||||
|
||||
if (inputTarget.type == InputTarget.Type.PLATFORM_VIEW) {
|
||||
if (isInputConnectionLocked) {
|
||||
return lastInputConnection;
|
||||
}
|
||||
lastInputConnection = platformViewsController.getPlatformViewById(inputTarget.id).onCreateInputConnection(outAttrs);
|
||||
return lastInputConnection;
|
||||
}
|
||||
|
||||
@ -158,7 +214,7 @@ public class TextInputPlugin {
|
||||
|
||||
InputConnectionAdaptor connection = new InputConnectionAdaptor(
|
||||
view,
|
||||
mClient,
|
||||
inputTarget.id,
|
||||
textInputChannel,
|
||||
mEditable
|
||||
);
|
||||
@ -180,17 +236,28 @@ public class TextInputPlugin {
|
||||
}
|
||||
|
||||
private void hideTextInput(View view) {
|
||||
// Note: a race condition may lead to us hiding the keyboard here just after a platform view has shown it.
|
||||
// This can only potentially happen when switching focus from a Flutter text field to a platform view's text
|
||||
// field(by text field here I mean anything that keeps the keyboard open).
|
||||
// See: https://github.com/flutter/flutter/issues/34169
|
||||
mImm.hideSoftInputFromWindow(view.getApplicationWindowToken(), 0);
|
||||
}
|
||||
|
||||
private void setTextInputClient(int client, TextInputChannel.Configuration configuration) {
|
||||
mClient = client;
|
||||
inputTarget = new InputTarget(InputTarget.Type.FRAMEWORK_CLIENT, 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;
|
||||
unlockPlatformViewInputConnection();
|
||||
}
|
||||
|
||||
private void setPlatformViewTextInputClient(int platformViewId) {
|
||||
inputTarget = new InputTarget(InputTarget.Type.PLATFORM_VIEW, platformViewId);
|
||||
mImm.restartInput(mView);
|
||||
mRestartInputPending = false;
|
||||
}
|
||||
|
||||
private void applyStateToSelection(TextInputChannel.TextEditState state) {
|
||||
@ -220,6 +287,45 @@ public class TextInputPlugin {
|
||||
}
|
||||
|
||||
private void clearTextInputClient() {
|
||||
mClient = 0;
|
||||
if (inputTarget.type == InputTarget.Type.PLATFORM_VIEW) {
|
||||
// Focus changes in the framework tree have no guarantees on the order focus nodes are notified. A node
|
||||
// that lost focus may be notified before or after a node that gained focus.
|
||||
// When moving the focus from a Flutter text field to an AndroidView, it is possible that the Flutter text
|
||||
// field's focus node will be notified that it lost focus after the AndroidView was notified that it gained
|
||||
// focus. When this happens the text field will send a clearTextInput command which we ignore.
|
||||
// By doing this we prevent the framework from clearing a platform view input client(the only way to do so
|
||||
// is to set a new framework text client). I don't see an obvious use case for "clearing" a platform views
|
||||
// text input client, and it may be error prone as we don't know how the platform view manages the input
|
||||
// connection and we probably shouldn't interfere.
|
||||
// If we ever want to allow the framework to clear a platform view text client we should probably consider
|
||||
// changing the focus manager such that focus nodes that lost focus are notified before focus nodes that
|
||||
// gained focus as part of the same focus event.
|
||||
return;
|
||||
}
|
||||
inputTarget = new InputTarget(InputTarget.Type.NO_TARGET, 0);
|
||||
unlockPlatformViewInputConnection();
|
||||
}
|
||||
|
||||
static private class InputTarget {
|
||||
enum Type {
|
||||
NO_TARGET,
|
||||
// InputConnection is managed by the TextInputPlugin, and events are forwarded to the Flutter framework.
|
||||
FRAMEWORK_CLIENT,
|
||||
// InputConnection is managed by an embedded platform view.
|
||||
PLATFORM_VIEW
|
||||
}
|
||||
|
||||
public InputTarget(@NonNull Type type, int id) {
|
||||
this.type = type;
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
Type type;
|
||||
// The ID of the input target.
|
||||
//
|
||||
// For framework clients this is the framework input connection client ID.
|
||||
// For platform views this is the platform view's ID.
|
||||
int id;
|
||||
}
|
||||
}
|
||||
|
||||
@ -11,7 +11,6 @@ import io.flutter.view.AccessibilityBridge;
|
||||
* Facilitates interaction between the accessibility bridge and embedded platform views.
|
||||
*/
|
||||
public interface PlatformViewsAccessibilityDelegate {
|
||||
|
||||
/**
|
||||
* Returns the root of the view hierarchy for the platform view with the requested id, or null if there is no
|
||||
* corresponding view.
|
||||
|
||||
@ -23,12 +23,15 @@ import io.flutter.plugin.common.BinaryMessenger;
|
||||
import io.flutter.plugin.common.MethodCall;
|
||||
import io.flutter.plugin.common.MethodChannel;
|
||||
import io.flutter.plugin.common.StandardMethodCodec;
|
||||
import io.flutter.plugin.editing.TextInputPlugin;
|
||||
import io.flutter.view.AccessibilityBridge;
|
||||
import io.flutter.view.TextureRegistry;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@ -51,6 +54,8 @@ public class PlatformViewsController implements PlatformViewsAccessibilityDelega
|
||||
// The texture registry maintaining the textures into which the embedded views will be rendered.
|
||||
private TextureRegistry textureRegistry;
|
||||
|
||||
private TextInputPlugin textInputPlugin;
|
||||
|
||||
// The system channel used to communicate with the framework about platform views.
|
||||
private PlatformViewsChannel platformViewsChannel;
|
||||
|
||||
@ -59,6 +64,11 @@ public class PlatformViewsController implements PlatformViewsAccessibilityDelega
|
||||
|
||||
private final HashMap<Integer, VirtualDisplayController> vdControllers;
|
||||
|
||||
// The set of root views for all active virtual displays managed by this controller.
|
||||
// This allows an O(1) check whether a view is managed by this controller(by checking if it's root view is in this
|
||||
// set). This is used by isPlatformView.
|
||||
private final HashSet<View> vdRootViews;
|
||||
|
||||
private final PlatformViewsChannel.PlatformViewsHandler channelHandler = new PlatformViewsChannel.PlatformViewsHandler() {
|
||||
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
|
||||
@Override
|
||||
@ -92,14 +102,19 @@ public class PlatformViewsController implements PlatformViewsAccessibilityDelega
|
||||
|
||||
TextureRegistry.SurfaceTextureEntry textureEntry = textureRegistry.createSurfaceTexture();
|
||||
VirtualDisplayController vdController = VirtualDisplayController.create(
|
||||
context,
|
||||
accessibilityEventsDelegate,
|
||||
viewFactory,
|
||||
textureEntry,
|
||||
toPhysicalPixels(request.logicalWidth),
|
||||
toPhysicalPixels(request.logicalHeight),
|
||||
request.viewId,
|
||||
createParams
|
||||
context,
|
||||
accessibilityEventsDelegate,
|
||||
viewFactory,
|
||||
textureEntry,
|
||||
physicalWidth,
|
||||
physicalHeight,
|
||||
request.viewId,
|
||||
createParams,
|
||||
(view, hasFocus) -> {
|
||||
if (hasFocus) {
|
||||
platformViewsChannel.invokeViewFocused(request.viewId);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
if (vdController == null) {
|
||||
@ -108,7 +123,9 @@ public class PlatformViewsController implements PlatformViewsAccessibilityDelega
|
||||
}
|
||||
|
||||
vdControllers.put(request.viewId, vdController);
|
||||
vdController.getView().setLayoutDirection(request.direction);
|
||||
View platformView = vdController.getView();
|
||||
platformView.setLayoutDirection(request.direction);
|
||||
vdRootViews.add(platformView.getRootView());
|
||||
|
||||
// TODO(amirh): copy accessibility nodes to the FlutterView's accessibility tree.
|
||||
|
||||
@ -125,6 +142,9 @@ public class PlatformViewsController implements PlatformViewsAccessibilityDelega
|
||||
+ viewId);
|
||||
}
|
||||
|
||||
View rootView = vdController.getView().getRootView();
|
||||
vdRootViews.remove(rootView);
|
||||
|
||||
vdController.dispose();
|
||||
vdControllers.remove(viewId);
|
||||
}
|
||||
@ -143,11 +163,28 @@ public class PlatformViewsController implements PlatformViewsAccessibilityDelega
|
||||
int physicalHeight = toPhysicalPixels(request.newLogicalHeight);
|
||||
validateVirtualDisplayDimensions(physicalWidth, physicalHeight);
|
||||
|
||||
if (textInputPlugin != null) {
|
||||
// Resizing involved moving the platform view to a new virtual display.
|
||||
// Doing so potentially results in losing an active input connection.
|
||||
// To make sure we preserve the input connection when resizing we lock it here
|
||||
// and unlock after the resize is complete.
|
||||
textInputPlugin.lockPlatformViewInputConnection();
|
||||
}
|
||||
vdRootViews.remove(vdController.getView().getRootView());
|
||||
vdController.resize(
|
||||
physicalWidth,
|
||||
physicalHeight,
|
||||
onComplete
|
||||
physicalWidth,
|
||||
physicalHeight,
|
||||
new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (textInputPlugin != null) {
|
||||
textInputPlugin.unlockPlatformViewInputConnection();
|
||||
}
|
||||
onComplete.run();
|
||||
}
|
||||
}
|
||||
);
|
||||
vdRootViews.add(vdController.getView().getRootView());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -207,6 +244,12 @@ public class PlatformViewsController implements PlatformViewsAccessibilityDelega
|
||||
view.setLayoutDirection(direction);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearFocus(int viewId) {
|
||||
View view = vdControllers.get(viewId).getView();
|
||||
view.clearFocus();
|
||||
}
|
||||
|
||||
private void ensureValidAndroidVersion() {
|
||||
if (Build.VERSION.SDK_INT < MINIMAL_SDK) {
|
||||
Log.e(TAG, "Trying to use platform views with API " + Build.VERSION.SDK_INT
|
||||
@ -221,6 +264,7 @@ public class PlatformViewsController implements PlatformViewsAccessibilityDelega
|
||||
registry = new PlatformViewRegistryImpl();
|
||||
vdControllers = new HashMap<>();
|
||||
accessibilityEventsDelegate = new AccessibilityEventsDelegate();
|
||||
vdRootViews = new HashSet<>();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -270,6 +314,33 @@ public class PlatformViewsController implements PlatformViewsAccessibilityDelega
|
||||
accessibilityEventsDelegate.setAccessibilityBridge(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attaches this controller to a text input plugin.
|
||||
*
|
||||
* While a text input plugin is available, the platform views controller interacts with it to facilitate
|
||||
* delegation of text input connections to platform views.
|
||||
*
|
||||
* A platform views controller should be attached to a text input plugin whenever it is possible for the Flutter
|
||||
* framework to receive text input.
|
||||
*/
|
||||
public void attachTextInputPlugin(TextInputPlugin textInputPlugin) {
|
||||
this.textInputPlugin = textInputPlugin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detaches this controller from the currently attached text input plugin.
|
||||
*/
|
||||
public void detachTextInputPlugin() {
|
||||
textInputPlugin = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the view is a platform view managed by this controller.
|
||||
*/
|
||||
public boolean isPlatformView(View view) {
|
||||
return vdRootViews.contains(view.getRootView());
|
||||
}
|
||||
|
||||
public PlatformViewRegistry getRegistry() {
|
||||
return registry;
|
||||
}
|
||||
|
||||
@ -19,6 +19,7 @@ import android.widget.FrameLayout;
|
||||
import java.lang.reflect.*;
|
||||
|
||||
import static android.content.Context.WINDOW_SERVICE;
|
||||
import static android.view.View.OnFocusChangeListener;
|
||||
|
||||
/*
|
||||
* A presentation used for hosting a single Android view in a virtual display.
|
||||
@ -61,6 +62,8 @@ class SingleViewPresentation extends Presentation {
|
||||
// A reference to the current accessibility bridge to which accessibility events will be delegated.
|
||||
private final AccessibilityEventsDelegate accessibilityEventsDelegate;
|
||||
|
||||
private final OnFocusChangeListener focusChangeListener;
|
||||
|
||||
// This is the view id assigned by the Flutter framework to the embedded view, we keep it here
|
||||
// so when we create the platform view we can tell it its view id.
|
||||
private int viewId;
|
||||
@ -78,6 +81,8 @@ class SingleViewPresentation extends Presentation {
|
||||
|
||||
private PresentationState state;
|
||||
|
||||
private boolean startFocused = false;
|
||||
|
||||
/**
|
||||
* Creates a presentation that will use the view factory to create a new
|
||||
* platform view in the presentation's onCreate, and attach it.
|
||||
@ -88,13 +93,15 @@ class SingleViewPresentation extends Presentation {
|
||||
PlatformViewFactory viewFactory,
|
||||
AccessibilityEventsDelegate accessibilityEventsDelegate,
|
||||
int viewId,
|
||||
Object createParams
|
||||
Object createParams,
|
||||
OnFocusChangeListener focusChangeListener
|
||||
) {
|
||||
super(outerContext, display);
|
||||
this.viewFactory = viewFactory;
|
||||
this.accessibilityEventsDelegate = accessibilityEventsDelegate;
|
||||
this.viewId = viewId;
|
||||
this.createParams = createParams;
|
||||
this.focusChangeListener = focusChangeListener;
|
||||
state = new PresentationState();
|
||||
getWindow().setFlags(
|
||||
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
|
||||
@ -113,16 +120,20 @@ class SingleViewPresentation extends Presentation {
|
||||
Context outerContext,
|
||||
Display display,
|
||||
AccessibilityEventsDelegate accessibilityEventsDelegate,
|
||||
PresentationState state
|
||||
PresentationState state,
|
||||
OnFocusChangeListener focusChangeListener,
|
||||
boolean startFocused
|
||||
) {
|
||||
super(outerContext, display);
|
||||
this.accessibilityEventsDelegate = accessibilityEventsDelegate;
|
||||
viewFactory = null;
|
||||
this.state = state;
|
||||
this.focusChangeListener = focusChangeListener;
|
||||
getWindow().setFlags(
|
||||
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
|
||||
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
|
||||
);
|
||||
this.startFocused = startFocused;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -148,6 +159,14 @@ class SingleViewPresentation extends Presentation {
|
||||
rootView = new AccessibilityDelegatingFrameLayout(getContext(), accessibilityEventsDelegate, embeddedView);
|
||||
rootView.addView(container);
|
||||
rootView.addView(state.fakeWindowViewGroup);
|
||||
|
||||
embeddedView.setOnFocusChangeListener(focusChangeListener);
|
||||
rootView.setFocusableInTouchMode(true);
|
||||
if (startFocused) {
|
||||
embeddedView.requestFocus();
|
||||
} else {
|
||||
rootView.requestFocus();
|
||||
}
|
||||
setContentView(rootView);
|
||||
}
|
||||
|
||||
|
||||
@ -9,11 +9,14 @@ import android.content.Context;
|
||||
import android.hardware.display.DisplayManager;
|
||||
import android.hardware.display.VirtualDisplay;
|
||||
import android.os.Build;
|
||||
import android.util.Log;
|
||||
import android.view.Surface;
|
||||
import android.view.View;
|
||||
import android.view.ViewTreeObserver;
|
||||
import io.flutter.view.TextureRegistry;
|
||||
|
||||
import static android.view.View.OnFocusChangeListener;
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.KITKAT_WATCH)
|
||||
class VirtualDisplayController {
|
||||
|
||||
@ -25,7 +28,8 @@ class VirtualDisplayController {
|
||||
int width,
|
||||
int height,
|
||||
int viewId,
|
||||
Object createParams
|
||||
Object createParams,
|
||||
OnFocusChangeListener focusChangeListener
|
||||
) {
|
||||
textureEntry.surfaceTexture().setDefaultBufferSize(width, height);
|
||||
Surface surface = new Surface(textureEntry.surfaceTexture());
|
||||
@ -46,13 +50,14 @@ class VirtualDisplayController {
|
||||
}
|
||||
|
||||
return new VirtualDisplayController(
|
||||
context, accessibilityEventsDelegate, virtualDisplay, viewFactory, surface, textureEntry, viewId, createParams);
|
||||
context, accessibilityEventsDelegate, virtualDisplay, viewFactory, surface, textureEntry, focusChangeListener, viewId, createParams);
|
||||
}
|
||||
|
||||
private final Context context;
|
||||
private final AccessibilityEventsDelegate accessibilityEventsDelegate;
|
||||
private final int densityDpi;
|
||||
private final TextureRegistry.SurfaceTextureEntry textureEntry;
|
||||
private final OnFocusChangeListener focusChangeListener;
|
||||
private VirtualDisplay virtualDisplay;
|
||||
private SingleViewPresentation presentation;
|
||||
private Surface surface;
|
||||
@ -65,21 +70,30 @@ class VirtualDisplayController {
|
||||
PlatformViewFactory viewFactory,
|
||||
Surface surface,
|
||||
TextureRegistry.SurfaceTextureEntry textureEntry,
|
||||
OnFocusChangeListener focusChangeListener,
|
||||
int viewId,
|
||||
Object createParams
|
||||
) {
|
||||
this.context = context;
|
||||
this.accessibilityEventsDelegate = accessibilityEventsDelegate;
|
||||
this.textureEntry = textureEntry;
|
||||
this.focusChangeListener = focusChangeListener;
|
||||
this.surface = surface;
|
||||
this.virtualDisplay = virtualDisplay;
|
||||
densityDpi = context.getResources().getDisplayMetrics().densityDpi;
|
||||
presentation = new SingleViewPresentation(
|
||||
context, this.virtualDisplay.getDisplay(), viewFactory, accessibilityEventsDelegate, viewId, createParams);
|
||||
context,
|
||||
this.virtualDisplay.getDisplay(),
|
||||
viewFactory,
|
||||
accessibilityEventsDelegate,
|
||||
viewId,
|
||||
createParams,
|
||||
focusChangeListener);
|
||||
presentation.show();
|
||||
}
|
||||
|
||||
public void resize(final int width, final int height, final Runnable onNewSizeFrameAvailable) {
|
||||
boolean isFocused = getView().isFocused();
|
||||
final SingleViewPresentation.PresentationState presentationState = presentation.detachState();
|
||||
// We detach the surface to prevent it being destroyed when releasing the vd.
|
||||
//
|
||||
@ -125,7 +139,13 @@ class VirtualDisplayController {
|
||||
public void onViewDetachedFromWindow(View v) {}
|
||||
});
|
||||
|
||||
presentation = new SingleViewPresentation(context, virtualDisplay.getDisplay(), accessibilityEventsDelegate, presentationState);
|
||||
presentation = new SingleViewPresentation(
|
||||
context,
|
||||
virtualDisplay.getDisplay(),
|
||||
accessibilityEventsDelegate,
|
||||
presentationState,
|
||||
focusChangeListener,
|
||||
isFocused);
|
||||
presentation.show();
|
||||
}
|
||||
|
||||
|
||||
@ -191,9 +191,11 @@ public class FlutterView extends SurfaceView implements BinaryMessenger, Texture
|
||||
PlatformPlugin platformPlugin = new PlatformPlugin(activity, platformChannel);
|
||||
addActivityLifecycleListener(platformPlugin);
|
||||
mImm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
mTextInputPlugin = new TextInputPlugin(this, dartExecutor);
|
||||
PlatformViewsController platformViewsController = mNativeView.getPluginRegistry().getPlatformViewsController();
|
||||
mTextInputPlugin = new TextInputPlugin(this, dartExecutor, platformViewsController);
|
||||
androidKeyProcessor = new AndroidKeyProcessor(keyEventChannel, mTextInputPlugin);
|
||||
androidTouchProcessor = new AndroidTouchProcessor(flutterRenderer);
|
||||
mNativeView.getPluginRegistry().getPlatformViewsController().attachTextInputPlugin(mTextInputPlugin);
|
||||
|
||||
// Send initial platform information to Dart
|
||||
sendLocalesToDart(getResources().getConfiguration());
|
||||
@ -395,6 +397,12 @@ public class FlutterView extends SurfaceView implements BinaryMessenger, Texture
|
||||
return mTextInputPlugin.createInputConnection(this, outAttrs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkInputConnectionProxy(View view) {
|
||||
PlatformViewsController platformViewsController = mNativeView.getPluginRegistry().getPlatformViewsController();
|
||||
return platformViewsController.isPlatformView(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
if (!isAttached()) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user